feat: Implement packaged games loading and update engine initialization to support seeded games

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-25 11:38:01 +01:00
parent d393ca98ec
commit d63d742695
9 changed files with 345 additions and 14 deletions
@@ -53,6 +53,7 @@ class _RecordingEngine extends Wolf3dFlutterEngine {
Future<Wolf3dFlutterEngine> init({
String? directory,
Iterable<String>? additionalDirectories,
Iterable<WolfensteinData>? seededGames,
}) async {
initCallCount++;
lastDirectory = directory;
@@ -0,0 +1,91 @@
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
import 'package:wolf_3d_gui/packaged_games_loader.dart';
void main() {
group('loadPackagedGames', () {
test('loads known packaged directories in order', () async {
final requested = <(GameVersion, String)>[];
final games = await loadPackagedGames(
loader: ({required version, required assetDirectory}) async {
requested.add((version, assetDirectory));
return _buildTestData(version);
},
);
expect(requested, <(GameVersion, String)>[
(GameVersion.retail, 'assets/retail'),
(GameVersion.shareware, 'assets/shareware'),
(GameVersion.spearOfDestinyDemo, 'assets/sod/shareware'),
]);
expect(games.map((g) => g.version), <GameVersion>[
GameVersion.retail,
GameVersion.shareware,
GameVersion.spearOfDestinyDemo,
]);
});
test('skips failing packaged loads and keeps successful ones', () async {
final games = await loadPackagedGames(
loader: ({required version, required assetDirectory}) async {
if (version == GameVersion.shareware) {
throw Exception('shareware unavailable');
}
return _buildTestData(version);
},
);
expect(games.map((g) => g.version), <GameVersion>[
GameVersion.retail,
GameVersion.spearOfDestinyDemo,
]);
});
});
}
WolfensteinData _buildTestData(GameVersion version) {
final wallGrid = List.generate(64, (_) => List.filled(64, 0));
final objectGrid = List.generate(64, (_) => List.filled(64, 0));
for (int i = 0; i < 64; i++) {
wallGrid[0][i] = 2;
wallGrid[63][i] = 2;
wallGrid[i][0] = 2;
wallGrid[i][63] = 2;
}
objectGrid[2][2] = MapObject.playerEast;
return WolfensteinData(
version: version,
dataVersion: DataVersion.unknown,
registry: version == GameVersion.shareware
? SharewareAssetRegistry()
: RetailAssetRegistry(),
walls: <Sprite>[_sprite(1), _sprite(1), _sprite(2), _sprite(2)],
sprites: List<Sprite>.generate(436, (_) => _sprite(255)),
sounds: List<PcmSound>.generate(200, (_) => PcmSound(Uint8List(1))),
adLibSounds: const <PcmSound>[],
music: const <ImfMusic>[],
vgaImages: const <VgaImage>[],
episodes: <Episode>[
Episode(
name: 'Test Episode',
levels: <WolfLevel>[
WolfLevel(
name: 'Test Level',
wallGrid: wallGrid,
areaGrid: List.generate(64, (_) => List.filled(64, -1)),
objectGrid: objectGrid,
music: Music.level01,
),
],
),
],
);
}
Sprite _sprite(int color) =>
Sprite(Uint8List.fromList(List<int>.filled(64 * 64, color)));
@@ -88,6 +88,7 @@ class _RecordingEngine extends Wolf3dFlutterEngine {
Future<Wolf3dFlutterEngine> init({
String? directory,
Iterable<String>? additionalDirectories,
Iterable<WolfensteinData>? seededGames,
}) async {
initCallCount++;
availableGames