feat: Add original layout envelope save codec with encoding/decoding and tests

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-23 14:57:36 +01:00
parent db06f5f5cb
commit de8bff1964
5 changed files with 244 additions and 17 deletions
@@ -154,7 +154,7 @@ void main() {
engine.menuManager.mainMenuEntries
.map((entry) => entry.isEnabled)
.toList(),
[true, false, false, true, false, true, false, false, true, true],
[true, false, false, false, false, true, false, false, true, true],
);
input.isInteracting = true;
@@ -194,7 +194,7 @@ void main() {
engine.menuManager.mainMenuEntries
.map((entry) => entry.isEnabled)
.toList(),
[true, false, false, true, false, true, false, false, true, true],
[true, false, false, false, false, true, false, false, true, true],
);
input.isInteracting = true;
@@ -242,7 +242,7 @@ void main() {
engine.menuManager.mainMenuEntries
.map((entry) => entry.isEnabled)
.toList(),
[true, false, false, true, true, true, false, true, true, true],
[true, false, false, false, true, true, false, true, true, true],
);
input.isMovingForward = true;
@@ -273,10 +273,6 @@ void main() {
expect(manager.selectedMainIndex, 0);
manager.updateMainMenu(const EngineInput(isMovingBackward: true));
manager.updateMainMenu(const EngineInput());
expect(manager.selectedMainIndex, 3);
manager.updateMainMenu(const EngineInput(isMovingBackward: true));
manager.updateMainMenu(const EngineInput());
expect(manager.selectedMainIndex, 5);
@@ -292,6 +288,10 @@ void main() {
manager.updateMainMenu(const EngineInput(isMovingBackward: true));
manager.updateMainMenu(const EngineInput());
expect(manager.selectedMainIndex, 0);
manager.updateMainMenu(const EngineInput(isMovingBackward: true));
manager.updateMainMenu(const EngineInput());
expect(manager.selectedMainIndex, 5);
});
test('menu transition defaults to normal fade and can opt into fizzle', () {
@@ -367,11 +367,6 @@ void main() {
input.isMovingBackward = false;
engine.tick(const Duration(milliseconds: 16));
input.isMovingBackward = true;
engine.tick(const Duration(milliseconds: 16));
input.isMovingBackward = false;
engine.tick(const Duration(milliseconds: 16));
expect(engine.menuManager.selectedMainIndex, 9);
input.isInteracting = true;
@@ -84,6 +84,62 @@ void main() {
throwsA(isA<FormatException>()),
);
});
test('OriginalLayoutEnvelopeSaveGameCodec round-trips save metadata', () {
final WolfEngine engine = _buildEngine();
engine.init();
final OriginalLayoutEnvelopeSaveGameCodec codec =
OriginalLayoutEnvelopeSaveGameCodec();
final SaveGameFile file = SaveGameFile(
slot: 3,
gameVersion: engine.data.version,
dataVersionName: engine.data.dataVersion.name,
description: 'Classic Envelope',
createdAtMs: 999,
snapshot: engine.captureSaveState(),
checksum: 0,
);
final Uint8List encoded = codec.encode(file);
final SaveGameFile decoded = codec.decode(encoded);
expect(decoded.slot, 3);
expect(decoded.description, 'Classic Envelope');
expect(decoded.createdAtMs, 999);
expect(decoded.gameVersion, engine.data.version);
expect(
decoded.snapshot.activeEpisodeIndex,
file.snapshot.activeEpisodeIndex,
);
expect(decoded.snapshot.activeLevelIndex, file.snapshot.activeLevelIndex);
});
test('OriginalLayoutEnvelopeSaveGameCodec rejects invalid checksum', () {
final WolfEngine engine = _buildEngine();
engine.init();
final OriginalLayoutEnvelopeSaveGameCodec codec =
OriginalLayoutEnvelopeSaveGameCodec();
final Uint8List encoded = codec.encode(
SaveGameFile(
slot: 0,
gameVersion: engine.data.version,
dataVersionName: engine.data.dataVersion.name,
description: 'Classic Checksum',
createdAtMs: 12,
snapshot: engine.captureSaveState(),
checksum: 0,
),
);
encoded[encoded.length - 1] ^= 0xFF;
expect(
() => codec.decode(encoded),
throwsA(isA<FormatException>()),
);
});
}
class _TestInput extends Wolf3dInput {