diff --git a/api/lib/src/event/process/server.dart b/api/lib/src/event/process/server.dart index 79fe52e..99e7016 100644 --- a/api/lib/src/event/process/server.dart +++ b/api/lib/src/event/process/server.dart @@ -30,21 +30,23 @@ final class InvalidPacksError extends FatalServerEventError { @override String toString() => - 'Server requested packs, that are not available on the client: $signature'; + 'Server requested packs, that are not available on the client (or is empty): $signature'; } -WorldState? processServerEvent( +Future processServerEvent( ServerWorldEvent event, WorldState state, { required AssetManager assetManager, -}) { +}) async { if (!isValidServerEvent(event, state)) return null; switch (event) { case WorldInitialized event: - final supported = assetManager.isServerSupported(event.packsSignature); + final supported = + await assetManager.isServerSupported(event.packsSignature); if (!supported) { throw InvalidPacksError(signature: event.packsSignature); } + assetManager.setAllowedPacks(event.packsSignature.keys.toSet()); return state.copyWith( table: event.table, id: event.id, diff --git a/api/lib/src/services/asset.dart b/api/lib/src/services/asset.dart index 7324927..a550ad3 100644 --- a/api/lib/src/services/asset.dart +++ b/api/lib/src/services/asset.dart @@ -2,15 +2,28 @@ import 'package:quokka_api/quokka_api.dart'; abstract class AssetManager { QuokkaData? getPack(String key); + Future loadPack(String key) => Future.value(getPack(key)); - bool isServerSupported(Map signature) { + Iterable> get packs; + + Future isServerSupported(Map signature) async { if (signature.isEmpty) return false; for (final entry in signature.entries) { - final pack = getPack(entry.key); + final pack = await loadPack(entry.key); if (pack == null || pack.getChecksum().toString() != entry.value) { return false; } } return true; } + + Map createSignature() { + final signature = {}; + for (final entry in packs) { + signature[entry.key] = entry.value.getChecksum().toString(); + } + return signature; + } + + void setAllowedPacks(Set packs) {} } diff --git a/app/lib/bloc/multiplayer.dart b/app/lib/bloc/multiplayer.dart index 835f820..ccfb9d0 100644 --- a/app/lib/bloc/multiplayer.dart +++ b/app/lib/bloc/multiplayer.dart @@ -76,6 +76,8 @@ class MultiplayerCubit extends Cubit { Stream<(Channel, ConnectionInfo)> get inits => _initController.stream; + FatalServerEventError? _fatalError; + MultiplayerCubit() : super(MultiplayerDisabledState()); bool get isConnected => state.isConnected; @@ -132,12 +134,8 @@ class MultiplayerCubit extends Cubit { final state = this.state; if (state is! MultiplayerConnectedState) return; state.networker.close(); - if (emit) { - if (state.isClient) { - this.emit(MultiplayerDisconnectedState()); - } else { - this.emit(MultiplayerDisabledState()); - } + if (emit && state.isServer) { + this.emit(MultiplayerDisabledState()); } } @@ -152,7 +150,9 @@ class MultiplayerCubit extends Cubit { )); final state = await _addNetworker(client); client.onClosed.listen((_) { - if (!isClosed) emit(MultiplayerDisconnectedState(oldState: state)); + if (isClosed) return; + emit(MultiplayerDisconnectedState(oldState: state, error: _fatalError)); + _fatalError = null; }, onError: (e) => emit(MultiplayerDisconnectedState(error: e))); await client.init(); emit(state); @@ -202,9 +202,7 @@ class MultiplayerCubit extends Cubit { } Future raiseError(FatalServerEventError e) async { - final state = this.state; - if (state is! MultiplayerConnectedState) return; - await state.networker.close(); - emit(MultiplayerDisconnectedState(error: e, oldState: state)); + _fatalError = e; + disconnect(); } } diff --git a/app/lib/bloc/world/bloc.dart b/app/lib/bloc/world/bloc.dart index e8542e1..2b61102 100644 --- a/app/lib/bloc/world/bloc.dart +++ b/app/lib/bloc/world/bloc.dart @@ -44,16 +44,17 @@ class WorldBloc extends Bloc { table: state.table, teamMembers: state.teamMembers, id: user, + packsSignature: assetManager.createSignature(), ), user); }) ..serverEvents.listen(_processEvent); - on((event, emit) { + on((event, emit) async { try { final newState = - processServerEvent(event, state, assetManager: assetManager); - if (newState is! ClientWorldState) return null; + await processServerEvent(event, state, assetManager: assetManager); + if (newState is! ClientWorldState) return; emit(newState); return save(); } on FatalServerEventError catch (e) { diff --git a/app/lib/helpers/asset.dart b/app/lib/helpers/asset.dart index 44dd7b1..f8ed65d 100644 --- a/app/lib/helpers/asset.dart +++ b/app/lib/helpers/asset.dart @@ -24,6 +24,7 @@ class GameAssetManager extends AssetManager { this.currentLocale = 'en', }); + @override Iterable> get packs => _loadedPacks.entries .where((e) => _allowedPacks.isEmpty || _allowedPacks.contains(e.key)); @@ -85,6 +86,7 @@ class GameAssetManager extends AssetManager { @override QuokkaData? getPack(String key) => _loadedPacks[key]; + @override Future loadPack(String key, {QuokkaData? pack, bool force = false}) async { final oldPack = _loadedPacks[key]; @@ -120,6 +122,7 @@ class GameAssetManager extends AssetManager { ..forEach((_, v) => v.then((e) => e.dispose())) ..clear(); + @override void setAllowedPacks(Iterable packs) { _allowedPacks.clear(); _allowedPacks.addAll(packs); diff --git a/server/lib/asset.dart b/server/lib/asset.dart index 573c174..7106488 100644 --- a/server/lib/asset.dart +++ b/server/lib/asset.dart @@ -7,6 +7,7 @@ import 'package:quokka_api/quokka_api.dart'; class ServerAssetManager extends AssetManager { final Map _packs = {}; static const _qkaExtension = 'qka'; + @override Iterable> get packs => _packs.entries; Future init({required Consoler console, bool verbose = false}) async { diff --git a/server/lib/main.dart b/server/lib/main.dart index 8da5738..d88b5dd 100644 --- a/server/lib/main.dart +++ b/server/lib/main.dart @@ -32,10 +32,10 @@ final class QuokkaServer extends Bloc { table: data.getTableOrDefault(), metadata: data.getMetadataOrDefault(), )) { - on((event, emit) { + on((event, emit) async { final newState = - processServerEvent(event, state, assetManager: assetManager); - if (newState == null) return null; + await processServerEvent(event, state, assetManager: assetManager); + if (newState == null) return; emit(newState); return save(); }); @@ -129,6 +129,7 @@ final class QuokkaServer extends Bloc { table: state.table, id: state.id, teamMembers: state.teamMembers, + packsSignature: assetManager.createSignature(), ), user); } diff --git a/server/lib/programs/packs.dart b/server/lib/programs/packs.dart index 33bc124..4510830 100644 --- a/server/lib/programs/packs.dart +++ b/server/lib/programs/packs.dart @@ -10,7 +10,7 @@ class PacksProgram extends ConsoleProgram { String getDescription() => "Show all loaded packs"; @override - void run(List args) { + void run(String label, List args) { print("-----"); final packs = server.assetManager.packs.toList(); print("Loaded ${packs.length} pack(s)."); diff --git a/server/lib/programs/save.dart b/server/lib/programs/save.dart index 5028394..0dbf05d 100644 --- a/server/lib/programs/save.dart +++ b/server/lib/programs/save.dart @@ -9,9 +9,9 @@ class SaveProgram extends ConsoleProgram { String getDescription() => "Saves the world manually"; @override - Future run(List args) async { - print('Saving...'); + Future run(String label, List args) async { + server.consoler.print('Saving...', level: LogLevel.info); await server.save(force: true); - print('Saved.'); + server.consoler.print('Saved.', level: LogLevel.info); } } diff --git a/server/lib/programs/stop.dart b/server/lib/programs/stop.dart index 0568bcd..878cef5 100644 --- a/server/lib/programs/stop.dart +++ b/server/lib/programs/stop.dart @@ -9,7 +9,7 @@ class StopProgram extends ConsoleProgram { String getDescription() => "Stops the server"; @override - void run(List args) { + void run(String label, List args) { server.close(); } } diff --git a/server/pubspec.lock b/server/pubspec.lock index 5db8640..aea1cc7 100644 --- a/server/pubspec.lock +++ b/server/pubspec.lock @@ -74,8 +74,8 @@ packages: dependency: "direct main" description: path: "packages/consoler" - ref: "2433c04c7526744a1aad757b744ec2b68225a35c" - resolved-ref: "2433c04c7526744a1aad757b744ec2b68225a35c" + ref: "68d1e59fa9f611ad496b7f341f0b1741f662469e" + resolved-ref: "68d1e59fa9f611ad496b7f341f0b1741f662469e" url: "https://github.com/LinwoodDev/dart_pkgs" source: git version: "1.0.0" diff --git a/server/pubspec.yaml b/server/pubspec.yaml index a398b8f..7d22e0b 100644 --- a/server/pubspec.yaml +++ b/server/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: consoler: git: url: https://github.com/LinwoodDev/dart_pkgs - ref: 2433c04c7526744a1aad757b744ec2b68225a35c + ref: 68d1e59fa9f611ad496b7f341f0b1741f662469e path: packages/consoler path: ^1.9.0 quokka_api: