diff --git a/apps/wolf_3d_gui/lib/main.dart b/apps/wolf_3d_gui/lib/main.dart index 2cc7c50..a0f1d98 100644 --- a/apps/wolf_3d_gui/lib/main.dart +++ b/apps/wolf_3d_gui/lib/main.dart @@ -1,6 +1,7 @@ /// Flutter entry point for the GUI host application. /// -/// The GUI bootstraps bundled and discoverable game data through [Wolf3d] +/// The GUI bootstraps bundled and discoverable game data through +/// [Wolf3dFlutterEngine] /// before presenting the game-selection flow. library; @@ -17,7 +18,9 @@ void main() async { await windowManager.ensureInitialized(); } - final Wolf3d wolf3d = await Wolf3d().init(debug: kDebugMode); + final Wolf3dFlutterEngine wolf3d = await Wolf3dFlutterEngine().init( + debug: kDebugMode, + ); runApp( MaterialApp( diff --git a/packages/wolf_3d_dart/lib/src/engine/wolf_3d_engine.dart b/packages/wolf_3d_dart/lib/src/engine/wolf_3d_engine.dart new file mode 100644 index 0000000..4d77533 --- /dev/null +++ b/packages/wolf_3d_dart/lib/src/engine/wolf_3d_engine.dart @@ -0,0 +1,219 @@ +import 'package:wolf_3d_dart/wolf_3d_data_types.dart'; +import 'package:wolf_3d_dart/wolf_3d_engine.dart'; +import 'package:wolf_3d_dart/wolf_3d_input.dart'; + +/// Platform-agnostic gameplay session facade for Wolf3D hosts. +/// +/// This class owns shared engine state and host-facing session configuration +/// while remaining independent of Flutter and other UI frameworks. +class Wolf3dEngine { + /// Creates a session facade backed by [audio] and [input]. + Wolf3dEngine({required this.audio, required this.input}); + + /// All successfully discovered or supplied game data sets. + final List availableGames = []; + + WolfensteinData? _activeGame; + + /// Shared engine audio backend used by menus and gameplay sessions. + final EngineAudio audio; + + /// Shared input adapter reused by hosts and gameplay screens. + final Wolf3dInput input; + + Future? _audioShutdownFuture; + + /// Engine menu background color as 24-bit RGB. + int menuBackgroundRgb = 0x890000; + + /// Engine menu panel color as 24-bit RGB. + int menuPanelRgb = 0x590002; + + bool _debugEnabled = false; + + /// Whether host-level debug affordances should be visible. + bool get isDebugEnabled => _debugEnabled; + + /// Enables host-level debug affordances such as debug navigation UI. + Wolf3dEngine enableDebug() { + _debugEnabled = true; + return this; + } + + /// The currently selected game data set. + /// + /// Throws a [StateError] until [setActiveGame] has been called. + WolfensteinData get activeGame { + if (_activeGame == null) { + throw StateError('No active game selected. Call setActiveGame() first.'); + } + return _activeGame!; + } + + /// Nullable access to the selected game, useful during menu bootstrap. + WolfensteinData? get maybeActiveGame => _activeGame; + + // Episode selection lives on the facade so menus can configure gameplay + // before constructing a new engine instance. + int? _activeEpisode; + + /// Index of the episode currently selected in the UI flow. + int? get activeEpisode => _activeEpisode; + + Difficulty? _activeDifficulty; + + /// The difficulty applied when [launchEngine] creates a new session. + Difficulty? get activeDifficulty => _activeDifficulty; + + /// Stores [difficulty] so the next [launchEngine] call uses it. + void setActiveDifficulty(Difficulty difficulty) { + _activeDifficulty = difficulty; + } + + /// Clears any previously selected difficulty so the engine can prompt for one. + void clearActiveDifficulty() { + _activeDifficulty = null; + } + + WolfEngine? _engine; + + /// The most recently launched engine. + /// + /// Throws a [StateError] until [launchEngine] has been called. + WolfEngine get engine { + if (_engine == null) { + throw StateError('No engine launched. Call launchEngine() first.'); + } + return _engine!; + } + + /// Creates and initializes a [WolfEngine] for the current session config. + /// + /// Uses [activeGame], [activeEpisode], and [activeDifficulty]. Stores the + /// engine so it can be retrieved via [engine]. [onGameWon] is invoked when + /// the player completes the final level of the episode. + WolfEngine launchEngine({ + required void Function() onGameWon, + void Function()? onQuit, + SaveGamePersistence? saveGamePersistence, + WolfRendererCapabilities? rendererCapabilities, + WolfRendererSettings? rendererSettings, + void Function(WolfRendererSettings settings)? onRendererSettingsChanged, + }) { + if (availableGames.isEmpty) { + throw StateError( + 'No game data was discovered. Add game files before launching the engine.', + ); + } + + _engine = WolfEngine( + availableGames: availableGames, + difficulty: _activeDifficulty, + startingEpisode: _activeEpisode, + frameBuffer: FrameBuffer(320, 200), + menuBackgroundRgb: menuBackgroundRgb, + menuPanelRgb: menuPanelRgb, + engineAudio: audio, + input: input, + onGameWon: onGameWon, + // In Flutter we keep the renderer screen active while browsing menus, + // so backing out of the top-level menu should not pop the route. + onMenuExit: () {}, + onQuit: onQuit, + saveGamePersistence: saveGamePersistence, + rendererCapabilities: rendererCapabilities, + rendererSettings: rendererSettings, + onRendererSettingsChanged: onRendererSettingsChanged, + onGameSelected: (game) { + _activeGame = game; + audio.activeGame = game; + }, + onEpisodeSelected: (episodeIndex) { + _activeEpisode = episodeIndex; + }, + ); + _engine!.init(); + return _engine!; + } + + /// Sets the active episode for the current [activeGame]. + void setActiveEpisode(int episodeIndex) { + if (_activeGame == null) { + throw StateError('No active game selected. Call setActiveGame() first.'); + } + if (episodeIndex < 0 || episodeIndex >= _activeGame!.episodes.length) { + throw RangeError('Episode index out of range for the active game.'); + } + + _activeEpisode = episodeIndex; + } + + /// Clears any selected episode so menu flow starts fresh. + void clearActiveEpisode() { + _activeEpisode = null; + } + + /// Convenience access to the active episode's level list. + List get levels { + if (_activeEpisode == null) { + throw StateError('No active episode selected.'); + } + return activeGame.episodes[_activeEpisode!].levels; + } + + /// Convenience access to the active game's wall textures. + List get walls => activeGame.walls; + + /// Convenience access to the active game's sprite set. + List get sprites => activeGame.sprites; + + /// Convenience access to digitized PCM effects. + List get sounds => activeGame.sounds; + + /// Convenience access to AdLib/OPL effect assets. + List get adLibSounds => activeGame.adLibSounds; + + /// Convenience access to level music tracks. + List get music => activeGame.music; + + /// Convenience access to VGA UI and splash images. + List get vgaImages => activeGame.vgaImages; + + /// Makes [game] the active data set and points shared services at it. + void setActiveGame(WolfensteinData game) { + if (!availableGames.contains(game)) { + throw ArgumentError( + 'The provided game data is not in the list of available games.', + ); + } + + if (_activeGame == game) { + return; + } + + _activeGame = game; + _activeEpisode = null; + audio.activeGame = game; + } + + /// Stops and disposes shared audio exactly once for app shutdown. + /// + /// Repeated calls return the same in-flight/completed future so hosts can + /// safely invoke shutdown from multiple lifecycle paths. + Future shutdownAudio() { + final existing = _audioShutdownFuture; + if (existing != null) { + return existing; + } + + final shutdown = () async { + await audio.stopAllAudio(); + audio.dispose(); + }(); + _audioShutdownFuture = shutdown; + return shutdown; + } +} + +/// Backward-compatible alias for the previous class name. +typedef Wolf3dSession = Wolf3dEngine; diff --git a/packages/wolf_3d_dart/lib/wolf_3d_engine.dart b/packages/wolf_3d_dart/lib/wolf_3d_engine.dart index 95392c8..0e5b143 100644 --- a/packages/wolf_3d_dart/lib/wolf_3d_engine.dart +++ b/packages/wolf_3d_dart/lib/wolf_3d_engine.dart @@ -19,4 +19,5 @@ export 'src/engine/save/default_save_game_persistence.dart'; export 'src/engine/save/game_session_snapshot.dart'; export 'src/engine/save/save_game_codec.dart'; export 'src/engine/save/save_game_persistence.dart'; +export 'src/engine/wolf_3d_engine.dart'; export 'src/engine/wolf_3d_engine_base.dart'; diff --git a/packages/wolf_3d_flutter/lib/screens/audio_gallery.dart b/packages/wolf_3d_flutter/lib/screens/audio_gallery.dart index eb83425..940675a 100644 --- a/packages/wolf_3d_flutter/lib/screens/audio_gallery.dart +++ b/packages/wolf_3d_flutter/lib/screens/audio_gallery.dart @@ -24,7 +24,7 @@ class _AudioRow { /// Displays all decoded SFX and music tracks for the selected game data. class AudioGallery extends StatefulWidget { /// Shared app facade used to access game assets and the audio backend. - final Wolf3d wolf3d; + final Wolf3dFlutterEngine wolf3d; const AudioGallery({super.key, required this.wolf3d}); diff --git a/packages/wolf_3d_flutter/lib/screens/debug_tools_screen.dart b/packages/wolf_3d_flutter/lib/screens/debug_tools_screen.dart index 63e1efd..a178cb3 100644 --- a/packages/wolf_3d_flutter/lib/screens/debug_tools_screen.dart +++ b/packages/wolf_3d_flutter/lib/screens/debug_tools_screen.dart @@ -7,7 +7,7 @@ import 'package:wolf_3d_flutter/wolf_3d_flutter.dart'; /// Presents debug-only navigation shortcuts for asset galleries. class DebugToolsScreen extends StatelessWidget { /// Shared app facade used to access active game assets. - final Wolf3d wolf3d; + final Wolf3dFlutterEngine wolf3d; /// Creates the debug tools screen for [wolf3d]. const DebugToolsScreen({super.key, required this.wolf3d}); diff --git a/packages/wolf_3d_flutter/lib/screens/game_screen.dart b/packages/wolf_3d_flutter/lib/screens/game_screen.dart index 99c5802..f57687f 100644 --- a/packages/wolf_3d_flutter/lib/screens/game_screen.dart +++ b/packages/wolf_3d_flutter/lib/screens/game_screen.dart @@ -11,10 +11,11 @@ import 'package:wolf_3d_flutter/renderer/wolf_3d_flutter_renderer.dart'; import 'package:wolf_3d_flutter/renderer/wolf_3d_glsl_renderer.dart'; import 'package:wolf_3d_flutter/wolf_3d_flutter.dart'; -/// Launches a [WolfEngine] via [Wolf3d] and exposes renderer/input integrations. +/// Launches a [WolfEngine] via [Wolf3dFlutterEngine] and exposes +/// renderer/input integrations. class GameScreen extends StatefulWidget { /// Shared application facade owning the engine, audio, and input. - final Wolf3d wolf3d; + final Wolf3dFlutterEngine wolf3d; /// Optional host-level shortcut override. /// diff --git a/packages/wolf_3d_flutter/lib/screens/sprite_gallery.dart b/packages/wolf_3d_flutter/lib/screens/sprite_gallery.dart index 3f9b1dc..e12c053 100644 --- a/packages/wolf_3d_flutter/lib/screens/sprite_gallery.dart +++ b/packages/wolf_3d_flutter/lib/screens/sprite_gallery.dart @@ -10,7 +10,7 @@ import 'package:wolf_3d_flutter/wolf_3d_flutter.dart'; /// Displays every sprite frame in the active game along with enemy metadata. class SpriteGallery extends StatefulWidget { /// Shared application facade used to access the active game's sprite set. - final Wolf3d wolf3d; + final Wolf3dFlutterEngine wolf3d; /// Creates the sprite gallery for [wolf3d]. const SpriteGallery({super.key, required this.wolf3d}); diff --git a/packages/wolf_3d_flutter/lib/screens/vga_gallery.dart b/packages/wolf_3d_flutter/lib/screens/vga_gallery.dart index d4019e4..12ff190 100644 --- a/packages/wolf_3d_flutter/lib/screens/vga_gallery.dart +++ b/packages/wolf_3d_flutter/lib/screens/vga_gallery.dart @@ -9,7 +9,7 @@ import 'package:wolf_3d_flutter/wolf_3d_flutter.dart'; /// Shows each VGA image extracted from the currently selected game data set. class VgaGallery extends StatefulWidget { /// Shared app facade used to access available game data sets. - final Wolf3d wolf3d; + final Wolf3dFlutterEngine wolf3d; /// Creates the gallery for the currently selected or browsed game. const VgaGallery({super.key, required this.wolf3d}); diff --git a/packages/wolf_3d_flutter/lib/widgets/gallery_game_selector.dart b/packages/wolf_3d_flutter/lib/widgets/gallery_game_selector.dart index dd79e85..e40b2be 100644 --- a/packages/wolf_3d_flutter/lib/widgets/gallery_game_selector.dart +++ b/packages/wolf_3d_flutter/lib/widgets/gallery_game_selector.dart @@ -20,7 +20,7 @@ String formatGalleryGameTitle(GameVersion version) { /// Selects which discovered game data set gallery screens should display. class GalleryGameSelector extends StatelessWidget { - final Wolf3d wolf3d; + final Wolf3dFlutterEngine wolf3d; final WolfensteinData selectedGame; final ValueChanged onSelected; diff --git a/packages/wolf_3d_flutter/lib/widgets/wolf3d_app.dart b/packages/wolf_3d_flutter/lib/widgets/wolf3d_app.dart index 746f198..5b4a559 100644 --- a/packages/wolf_3d_flutter/lib/widgets/wolf3d_app.dart +++ b/packages/wolf_3d_flutter/lib/widgets/wolf3d_app.dart @@ -3,10 +3,11 @@ library; import 'package:flutter/material.dart'; import 'package:wolf_3d_flutter/wolf_3d_flutter.dart'; -/// Minimal app shell that binds a prepared [Wolf3d] instance to host screens. +/// Minimal app shell that binds a prepared [Wolf3dFlutterEngine] instance to +/// host screens. class Wolf3dApp extends StatelessWidget { /// Shared initialized facade that owns game data, input, and audio services. - final Wolf3d wolf3d; + final Wolf3dFlutterEngine wolf3d; const Wolf3dApp({ super.key, diff --git a/packages/wolf_3d_flutter/lib/wolf_3d_flutter.dart b/packages/wolf_3d_flutter/lib/wolf_3d_flutter.dart index 03087af..bbe74e3 100644 --- a/packages/wolf_3d_flutter/lib/wolf_3d_flutter.dart +++ b/packages/wolf_3d_flutter/lib/wolf_3d_flutter.dart @@ -37,203 +37,40 @@ export 'widgets/gallery_game_selector.dart' export 'widgets/wolf3d_app.dart' show Wolf3dApp; export 'widgets/wolf_menu_shell.dart' show WolfMenuShell; -/// Coordinates asset discovery, audio initialization, and input reuse for apps. -class Wolf3d { +/// Flutter-specific host facade built on top of [Wolf3dEngine]. +/// +/// This type keeps platform-neutral session/engine state in the Dart package +/// while owning Flutter-only concerns such as bundle loading and discovery. +class Wolf3dFlutterEngine extends Wolf3dEngine { /// Creates an empty facade that must be initialized with [init]. - Wolf3d({EngineAudio? audioBackend}) - : audio = audioBackend ?? Wolf3dPlatformAudio(); - - /// All successfully discovered or bundled game data sets. - final List availableGames = []; - WolfensteinData? _activeGame; - - /// Shared engine audio backend used by menus and gameplay sessions. - final EngineAudio audio; - - Future? _audioShutdownFuture; - - /// Engine menu background color as 24-bit RGB. - int menuBackgroundRgb = 0x890000; - - /// Engine menu panel color as 24-bit RGB. - int menuPanelRgb = 0x590002; + Wolf3dFlutterEngine({ + EngineAudio? audioBackend, + Wolf3dFlutterInput? inputBackend, + }) : super( + audio: audioBackend ?? Wolf3dPlatformAudio(), + input: inputBackend ?? Wolf3dFlutterInput(), + ); /// Shared Flutter input adapter reused by gameplay screens. - final Wolf3dFlutterInput input = Wolf3dFlutterInput(); - - bool _debugEnabled = false; - - /// Whether host-level debug affordances should be visible. - bool get isDebugEnabled => _debugEnabled; + @override + Wolf3dFlutterInput get input => super.input as Wolf3dFlutterInput; /// Enables host-level debug affordances such as debug navigation UI. - Wolf3d enableDebug() { - _debugEnabled = true; + @override + Wolf3dFlutterEngine enableDebug() { + super.enableDebug(); return this; } - /// The currently selected game data set. - /// - /// Throws a [StateError] until [setActiveGame] has been called. - WolfensteinData get activeGame { - if (_activeGame == null) { - throw StateError("No active game selected. Call setActiveGame() first."); - } - return _activeGame!; - } - - /// Nullable access to the selected game, useful during menu bootstrap. - WolfensteinData? get maybeActiveGame => _activeGame; - - // Episode selection lives on the facade so menus can configure gameplay - // before constructing a new engine instance. - int? _activeEpisode; - - /// Index of the episode currently selected in the UI flow. - int? get activeEpisode => _activeEpisode; - - Difficulty? _activeDifficulty; - - /// The difficulty applied when [launchEngine] creates a new session. - Difficulty? get activeDifficulty => _activeDifficulty; - - /// Stores [difficulty] so the next [launchEngine] call uses it. - void setActiveDifficulty(Difficulty difficulty) { - _activeDifficulty = difficulty; - } - - /// Clears any previously selected difficulty so the engine can prompt for one. - void clearActiveDifficulty() { - _activeDifficulty = null; - } - - WolfEngine? _engine; - - /// The most recently launched engine. - /// - /// Throws a [StateError] until [launchEngine] has been called. - WolfEngine get engine { - if (_engine == null) { - throw StateError('No engine launched. Call launchEngine() first.'); - } - return _engine!; - } - - /// Creates and initializes a [WolfEngine] for the current session config. - /// - /// Uses [activeGame], [activeEpisode], and [activeDifficulty]. Stores the - /// engine so it can be retrieved via [engine]. [onGameWon] is invoked when - /// the player completes the final level of the episode. - WolfEngine launchEngine({ - required void Function() onGameWon, - void Function()? onQuit, - SaveGamePersistence? saveGamePersistence, - WolfRendererCapabilities? rendererCapabilities, - WolfRendererSettings? rendererSettings, - void Function(WolfRendererSettings settings)? onRendererSettingsChanged, - }) { - if (availableGames.isEmpty) { - throw StateError( - 'No game data was discovered. Add game files before launching the engine.', - ); - } - - _engine = WolfEngine( - availableGames: availableGames, - difficulty: _activeDifficulty, - startingEpisode: _activeEpisode, - frameBuffer: FrameBuffer(320, 200), - menuBackgroundRgb: menuBackgroundRgb, - menuPanelRgb: menuPanelRgb, - engineAudio: audio, - input: input, - onGameWon: onGameWon, - // In Flutter we keep the renderer screen active while browsing menus, - // so backing out of the top-level menu should not pop the route. - onMenuExit: () {}, - onQuit: onQuit, - saveGamePersistence: saveGamePersistence, - rendererCapabilities: rendererCapabilities, - rendererSettings: rendererSettings, - onRendererSettingsChanged: onRendererSettingsChanged, - onGameSelected: (game) { - _activeGame = game; - audio.activeGame = game; - }, - onEpisodeSelected: (episodeIndex) { - _activeEpisode = episodeIndex; - }, - ); - _engine!.init(); - return _engine!; - } - - /// Sets the active episode for the current [activeGame]. - void setActiveEpisode(int episodeIndex) { - if (_activeGame == null) { - throw StateError("No active game selected. Call setActiveGame() first."); - } - if (episodeIndex < 0 || episodeIndex >= _activeGame!.episodes.length) { - throw RangeError("Episode index out of range for the active game."); - } - - _activeEpisode = episodeIndex; - } - - /// Clears any selected episode so menu flow starts fresh. - void clearActiveEpisode() { - _activeEpisode = null; - } - - /// Convenience access to the active episode's level list. - List get levels { - if (_activeEpisode == null) { - throw StateError('No active episode selected.'); - } - return activeGame.episodes[_activeEpisode!].levels; - } - - /// Convenience access to the active game's wall textures. - List get walls => activeGame.walls; - - /// Convenience access to the active game's sprite set. - List get sprites => activeGame.sprites; - - /// Convenience access to digitized PCM effects. - List get sounds => activeGame.sounds; - - /// Convenience access to AdLib/OPL effect assets. - List get adLibSounds => activeGame.adLibSounds; - - /// Convenience access to level music tracks. - List get music => activeGame.music; - - /// Convenience access to VGA UI and splash images. - List get vgaImages => activeGame.vgaImages; - - /// Makes [game] the active data set and points shared services at it. - void setActiveGame(WolfensteinData game) { - if (!availableGames.contains(game)) { - throw ArgumentError( - "The provided game data is not in the list of available games.", - ); - } - - if (_activeGame == game) { - return; // No change needed - } - - _activeGame = game; - _activeEpisode = null; - audio.activeGame = game; - } - /// Initializes the engine by loading available game data. /// /// Set [debug] to `true` to explicitly enable host-level debug affordances. - Future init({String? directory, bool debug = false}) async { + Future init({ + String? directory, + bool debug = false, + }) async { if (debug) { - _debugEnabled = true; + enableDebug(); } await audio.init(); availableGames.clear(); @@ -288,24 +125,6 @@ class Wolf3d { return this; } - /// Stops and disposes shared audio exactly once for app shutdown. - /// - /// Repeated calls return the same in-flight/completed future so hosts can - /// safely invoke shutdown from multiple lifecycle paths. - Future shutdownAudio() { - final existing = _audioShutdownFuture; - if (existing != null) { - return existing; - } - - final shutdown = () async { - await audio.stopAllAudio(); - audio.dispose(); - }(); - _audioShutdownFuture = shutdown; - return shutdown; - } - /// Loads an asset from the Flutter bundle, returning `null` when absent. Future _tryLoad(String path) async { try { @@ -316,3 +135,9 @@ class Wolf3d { } } } + +/// Backward-compatible alias for the previous Flutter host facade name. +typedef Wolf3dFlutter = Wolf3dFlutterEngine; + +/// Backward-compatible alias for the legacy Flutter host facade name. +typedef Wolf3d = Wolf3dFlutterEngine; diff --git a/packages/wolf_3d_flutter/test/game_screen_lifecycle_audio_test.dart b/packages/wolf_3d_flutter/test/game_screen_lifecycle_audio_test.dart index c6c53c5..bcf3461 100644 --- a/packages/wolf_3d_flutter/test/game_screen_lifecycle_audio_test.dart +++ b/packages/wolf_3d_flutter/test/game_screen_lifecycle_audio_test.dart @@ -47,7 +47,7 @@ class _CountingAudio implements EngineAudio { void main() { testWidgets('dispose path shuts down audio', (tester) async { final audio = _CountingAudio(); - final wolf3d = Wolf3d(audioBackend: audio); + final wolf3d = Wolf3dFlutterEngine(audioBackend: audio); await tester.pumpWidget( MaterialApp( diff --git a/packages/wolf_3d_flutter/test/wolf_3d_flutter_debug_mode_test.dart b/packages/wolf_3d_flutter/test/wolf_3d_flutter_debug_mode_test.dart index b64d949..ff9c5a0 100644 --- a/packages/wolf_3d_flutter/test/wolf_3d_flutter_debug_mode_test.dart +++ b/packages/wolf_3d_flutter/test/wolf_3d_flutter_debug_mode_test.dart @@ -39,15 +39,15 @@ class _NoopAudio implements EngineAudio { } void main() { - group('Wolf3d debug mode', () { + group('Wolf3dFlutterEngine debug mode', () { test('is disabled by default', () { - final wolf3d = Wolf3d(audioBackend: _NoopAudio()); + final wolf3d = Wolf3dFlutterEngine(audioBackend: _NoopAudio()); expect(wolf3d.isDebugEnabled, isFalse); }); test('enableDebug toggles debug mode', () { - final wolf3d = Wolf3d(audioBackend: _NoopAudio()); + final wolf3d = Wolf3dFlutterEngine(audioBackend: _NoopAudio()); final returned = wolf3d.enableDebug(); @@ -56,7 +56,7 @@ void main() { }); test('init(debug: true) enables debug mode', () async { - final wolf3d = Wolf3d(audioBackend: _NoopAudio()); + final wolf3d = Wolf3dFlutterEngine(audioBackend: _NoopAudio()); await wolf3d.init(debug: true); @@ -103,7 +103,7 @@ void main() { }); } -class _TestWolf3d extends Wolf3d { +class _TestWolf3d extends Wolf3dFlutterEngine { _TestWolf3d({required super.audioBackend}); @override diff --git a/packages/wolf_3d_flutter/test/wolf_3d_flutter_shutdown_audio_test.dart b/packages/wolf_3d_flutter/test/wolf_3d_flutter_shutdown_audio_test.dart index 42047ba..fb42463 100644 --- a/packages/wolf_3d_flutter/test/wolf_3d_flutter_shutdown_audio_test.dart +++ b/packages/wolf_3d_flutter/test/wolf_3d_flutter_shutdown_audio_test.dart @@ -44,10 +44,10 @@ class _CountingAudio implements EngineAudio { } void main() { - group('Wolf3d.shutdownAudio', () { + group('Wolf3dFlutterEngine.shutdownAudio', () { test('stops and disposes audio once', () async { final audio = _CountingAudio(); - final wolf3d = Wolf3d(audioBackend: audio); + final wolf3d = Wolf3dFlutterEngine(audioBackend: audio); await wolf3d.shutdownAudio(); await wolf3d.shutdownAudio(); @@ -58,7 +58,7 @@ void main() { test('concurrent calls share the same shutdown work', () async { final audio = _CountingAudio(); - final wolf3d = Wolf3d(audioBackend: audio); + final wolf3d = Wolf3dFlutterEngine(audioBackend: audio); await Future.wait([ wolf3d.shutdownAudio(),