feat: Implement save game functionality with encoding/decoding
- Added SaveGameCodec for encoding and decoding save game files. - Introduced SaveGamePersistence interface for slot-based save game persistence. - Implemented FlutterSaveGamePersistence for file-based save management on Flutter. - Enhanced WolfEngine to support saving and loading game states. - Updated menu manager to include save/load game options. - Created tests for SaveGameCodec to ensure proper functionality. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
library;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||
|
||||
/// Flutter desktop adapter for slot-based game save persistence.
|
||||
class FlutterSaveGamePersistence implements SaveGamePersistence {
|
||||
FlutterSaveGamePersistence({String? directoryPath})
|
||||
: _directoryPath = directoryPath;
|
||||
|
||||
final String? _directoryPath;
|
||||
String? _resolvedDirectoryPath;
|
||||
|
||||
Future<String> _resolveDirectoryPath() async {
|
||||
if (_resolvedDirectoryPath != null) {
|
||||
return _resolvedDirectoryPath!;
|
||||
}
|
||||
|
||||
if (_directoryPath != null) {
|
||||
_resolvedDirectoryPath = _directoryPath;
|
||||
return _resolvedDirectoryPath!;
|
||||
}
|
||||
|
||||
final String home =
|
||||
Platform.environment['HOME'] ?? Platform.environment['APPDATA'] ?? '.';
|
||||
_resolvedDirectoryPath = '$home/.wolf3d_saves';
|
||||
return _resolvedDirectoryPath!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List?> load({
|
||||
required int slot,
|
||||
required GameVersion version,
|
||||
}) async {
|
||||
if (kIsWeb) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final String dirPath = await _resolveDirectoryPath();
|
||||
final File file = File(_slotPath(dirPath, slot, version));
|
||||
if (!file.existsSync()) {
|
||||
return null;
|
||||
}
|
||||
return await file.readAsBytes();
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> save({
|
||||
required int slot,
|
||||
required GameVersion version,
|
||||
required Uint8List bytes,
|
||||
}) async {
|
||||
if (kIsWeb) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String dirPath = await _resolveDirectoryPath();
|
||||
final Directory dir = Directory(dirPath);
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create(recursive: true);
|
||||
}
|
||||
await File(
|
||||
_slotPath(dirPath, slot, version),
|
||||
).writeAsBytes(bytes, flush: true);
|
||||
}
|
||||
|
||||
String _slotPath(String dirPath, int slot, GameVersion version) {
|
||||
final String normalizedSlot = slot.clamp(0, 9).toString();
|
||||
return '$dirPath/SAVEGAM$normalizedSlot.${version.fileExtension}';
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ class Wolf3d {
|
||||
WolfEngine launchEngine({
|
||||
required void Function() onGameWon,
|
||||
void Function()? onQuit,
|
||||
SaveGamePersistence? saveGamePersistence,
|
||||
WolfRendererCapabilities? rendererCapabilities,
|
||||
WolfRendererSettings? rendererSettings,
|
||||
void Function(WolfRendererSettings settings)? onRendererSettingsChanged,
|
||||
@@ -109,6 +110,7 @@ class Wolf3d {
|
||||
// so backing out of the top-level menu should not pop the route.
|
||||
onMenuExit: () {},
|
||||
onQuit: onQuit,
|
||||
saveGamePersistence: saveGamePersistence,
|
||||
rendererCapabilities: rendererCapabilities,
|
||||
rendererSettings: rendererSettings,
|
||||
onRendererSettingsChanged: onRendererSettingsChanged,
|
||||
|
||||
Reference in New Issue
Block a user