diff --git a/api/lib/src/event/event.mapper.dart b/api/lib/src/event/event.mapper.dart index 100b22f..b42a9b5 100644 --- a/api/lib/src/event/event.mapper.dart +++ b/api/lib/src/event/event.mapper.dart @@ -1976,7 +1976,7 @@ class ObjectsSpawnedMapper extends SubClassMapperBase { if (_instance == null) { MapperContainer.globals.use(_instance = ObjectsSpawnedMapper._()); HybridWorldEventMapper.ensureInitialized().addSubMapper(_instance!); - GlobalVectorDefinitionMapper.ensureInitialized(); + VectorDefinitionMapper.ensureInitialized(); GameObjectMapper.ensureInitialized(); } return _instance!; @@ -1985,16 +1985,16 @@ class ObjectsSpawnedMapper extends SubClassMapperBase { @override final String id = 'ObjectsSpawned'; - static GlobalVectorDefinition _$cell(ObjectsSpawned v) => v.cell; - static const Field _f$cell = - Field('cell', _$cell); - static List _$objects(ObjectsSpawned v) => v.objects; - static const Field> _f$objects = - Field('objects', _$objects); + static String _$table(ObjectsSpawned v) => v.table; + static const Field _f$table = Field('table', _$table); + static Map> _$objects(ObjectsSpawned v) => + v.objects; + static const Field>> + _f$objects = Field('objects', _$objects); @override final MappableFields fields = const { - #cell: _f$cell, + #table: _f$table, #objects: _f$objects, }; @@ -2007,7 +2007,7 @@ class ObjectsSpawnedMapper extends SubClassMapperBase { HybridWorldEventMapper.ensureInitialized(); static ObjectsSpawned _instantiate(DecodingData data) { - return ObjectsSpawned(data.dec(_f$cell), data.dec(_f$objects)); + return ObjectsSpawned(data.dec(_f$table), data.dec(_f$objects)); } @override @@ -2063,12 +2063,10 @@ extension ObjectsSpawnedValueCopy<$R, $Out> abstract class ObjectsSpawnedCopyWith<$R, $In extends ObjectsSpawned, $Out> implements HybridWorldEventCopyWith<$R, $In, $Out> { - GlobalVectorDefinitionCopyWith<$R, GlobalVectorDefinition, - GlobalVectorDefinition> get cell; - ListCopyWith<$R, GameObject, GameObjectCopyWith<$R, GameObject, GameObject>> - get objects; + MapCopyWith<$R, VectorDefinition, List, + ObjectCopyWith<$R, List, List>> get objects; @override - $R call({GlobalVectorDefinition? cell, List? objects}); + $R call({String? table, Map>? objects}); ObjectsSpawnedCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( Then<$Out2, $R2> t); } @@ -2082,22 +2080,20 @@ class _ObjectsSpawnedCopyWithImpl<$R, $Out> late final ClassMapperBase $mapper = ObjectsSpawnedMapper.ensureInitialized(); @override - GlobalVectorDefinitionCopyWith<$R, GlobalVectorDefinition, - GlobalVectorDefinition> - get cell => $value.cell.copyWith.$chain((v) => call(cell: v)); - @override - ListCopyWith<$R, GameObject, GameObjectCopyWith<$R, GameObject, GameObject>> - get objects => ListCopyWith($value.objects, - (v, t) => v.copyWith.$chain(t), (v) => call(objects: v)); + MapCopyWith<$R, VectorDefinition, List, + ObjectCopyWith<$R, List, List>> + get objects => MapCopyWith($value.objects, + (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(objects: v)); @override - $R call({GlobalVectorDefinition? cell, List? objects}) => + $R call({String? table, Map>? objects}) => $apply(FieldCopyWithData({ - if (cell != null) #cell: cell, + if (table != null) #table: table, if (objects != null) #objects: objects })); @override ObjectsSpawned $make(CopyWithData data) => ObjectsSpawned( - data.get(#cell, or: $value.cell), data.get(#objects, or: $value.objects)); + data.get(#table, or: $value.table), + data.get(#objects, or: $value.objects)); @override ObjectsSpawnedCopyWith<$R2, ObjectsSpawned, $Out2> $chain<$R2, $Out2>( diff --git a/api/lib/src/event/hybrid.dart b/api/lib/src/event/hybrid.dart index 5f1f10a..bc8c738 100644 --- a/api/lib/src/event/hybrid.dart +++ b/api/lib/src/event/hybrid.dart @@ -16,10 +16,13 @@ final class BackgroundChanged extends HybridWorldEvent @MappableClass() final class ObjectsSpawned extends HybridWorldEvent with ObjectsSpawnedMappable { - final GlobalVectorDefinition cell; - final List objects; + final String table; + final Map> objects; - ObjectsSpawned(this.cell, this.objects); + ObjectsSpawned(this.table, this.objects); + ObjectsSpawned.single(GlobalVectorDefinition cell, List objects) + : objects = {cell.position: objects}, + table = cell.table; } @MappableClass() diff --git a/api/lib/src/event/process/client.dart b/api/lib/src/event/process/client.dart index 42dc67e..b358198 100644 --- a/api/lib/src/event/process/client.dart +++ b/api/lib/src/event/process/client.dart @@ -17,7 +17,7 @@ bool isValidClientEvent( 0, state .getTableOrDefault(event.cell.table) - .getCell(event.cell.location) + .getCell(event.cell.position) .objects .length - 1) ?? @@ -25,8 +25,8 @@ bool isValidClientEvent( ShuffleCellRequest() => state .getTableOrDefault(event.cell.table) .cells - .containsKey(event.cell.location), - ObjectsSpawned() => event.objects.every((e) { + .containsKey(event.cell.position), + ObjectsSpawned() => event.objects.values.expand((e) => e).every((e) { final figure = assetManager.getPack(e.asset.namespace)?.getFigure(e.asset.id); return figure != null && @@ -46,7 +46,7 @@ bool isValidClientEvent( 0, state .getTableOrDefault(event.cell.table) - .getCell(event.cell.location) + .getCell(event.cell.position) .objects .length - 1) ?? @@ -55,7 +55,7 @@ bool isValidClientEvent( 0, state .getTableOrDefault(event.cell.table) - .getCell(event.cell.location) + .getCell(event.cell.position) .objects .length - 1), @@ -99,7 +99,7 @@ bool isValidClientEvent( return (TeamLeft(channel, team), kAnyChannel); case CellRollRequest(): final table = state.getTableOrDefault(event.cell.table); - var cell = table.getCell(event.cell.location); + var cell = table.getCell(event.cell.position); final random = Random(); GameObject roll(GameObject object) { final figure = assetManager @@ -123,7 +123,7 @@ bool isValidClientEvent( return (ObjectsChanged(event.cell, objects), kAnyChannel); case ShuffleCellRequest(): final table = state.getTableOrDefault(event.cell.table); - final cell = table.cells[event.cell.location]; + final cell = table.cells[event.cell.position]; if (cell == null) return null; final positions = List.generate(cell.objects.length, (i) => i) ..shuffle(); diff --git a/api/lib/src/event/process/server.dart b/api/lib/src/event/process/server.dart index 0239913..fa22026 100644 --- a/api/lib/src/event/process/server.dart +++ b/api/lib/src/event/process/server.dart @@ -13,7 +13,7 @@ bool isValidServerEvent(ServerWorldEvent event, WorldState state) => 0, state .getTableOrDefault(event.cell.table) - .getCell(event.cell.location) + .getCell(event.cell.position) .objects .length - 1)), @@ -30,7 +30,7 @@ bool isValidServerEvent(ServerWorldEvent event, WorldState state) => 0, state .getTableOrDefault(event.cell.table) - .getCell(event.cell.location) + .getCell(event.cell.position) .objects .length - 1) ?? @@ -39,7 +39,7 @@ bool isValidServerEvent(ServerWorldEvent event, WorldState state) => 0, state .getTableOrDefault(event.cell.table) - .getCell(event.cell.location) + .getCell(event.cell.position) .objects .length - 1), @@ -98,20 +98,20 @@ WorldState? processServerEvent( return state.copyWith(teamMembers: allMembers); case ObjectsChanged(): return state.mapTableOrDefault(event.cell.table, (table) { - final cell = table.cells[event.cell.location] ?? TableCell(); + final cell = table.cells[event.cell.position] ?? TableCell(); return table.copyWith.cells.replace( - event.cell.location, cell.copyWith(objects: event.objects)); + event.cell.position, cell.copyWith(objects: event.objects)); }); case CellShuffled(positions: final positions): return state.mapTableOrDefault(event.cell.table, (table) { - final cell = table.cells[event.cell.location] ?? TableCell(); + final cell = table.cells[event.cell.position] ?? TableCell(); final objects = cell.objects; final newObjects = List.from(objects); for (var i = 0; i < positions.length; i++) { newObjects[positions[i]] = objects[i]; } return table.copyWith.cells.replace( - event.cell.location, + event.cell.position, cell.copyWith( objects: newObjects, )); @@ -119,10 +119,14 @@ WorldState? processServerEvent( case BackgroundChanged(): return state.copyWith.table(background: event.background); case ObjectsSpawned(): - return state.mapTableOrDefault(event.cell.table, (table) { - final cell = table.getCell(event.cell.location); - return table.copyWith.cells.replace(event.cell.location, - cell.copyWith(objects: [...cell.objects, ...event.objects])); + return state.mapTableOrDefault(event.table, (table) { + var newTable = table; + for (final entry in event.objects.entries) { + final cell = newTable.cells[entry.key] ?? TableCell(); + newTable = newTable.copyWith.cells + .replace(entry.key, cell.copyWith(objects: entry.value)); + } + return newTable; }); case ObjectsMoved(): return state.mapTableOrDefault(event.table, (table) { @@ -148,19 +152,19 @@ WorldState? processServerEvent( }); case CellHideChanged(): return state.mapTableOrDefault(event.cell.table, (table) { - final cell = table.cells[event.cell.location] ?? TableCell(); + final cell = table.cells[event.cell.position] ?? TableCell(); final objectIndex = event.object; if (objectIndex != null) { final object = cell.objects[objectIndex]; return table.copyWith.cells.replace( - event.cell.location, + event.cell.position, cell.copyWith.objects.replace(objectIndex, object.copyWith(hidden: event.hide ?? !object.hidden))); } else { final hidden = !(event.hide ?? cell.objects.firstOrNull?.hidden ?? false); return table.copyWith.cells.replace( - event.cell.location, + event.cell.position, cell.copyWith( objects: cell.objects .map((e) => e.copyWith(hidden: hidden)) @@ -170,14 +174,14 @@ WorldState? processServerEvent( }); case CellItemsCleared(): return state.mapTableOrDefault(event.cell.table, (table) { - final cell = table.cells[event.cell.location] ?? TableCell(); + final cell = table.cells[event.cell.position] ?? TableCell(); final objectIndex = event.object; if (objectIndex != null) { return table.copyWith.cells.replace( - event.cell.location, cell.copyWith.objects.removeAt(objectIndex)); + event.cell.position, cell.copyWith.objects.removeAt(objectIndex)); } else { return table.copyWith.cells.replace( - event.cell.location, + event.cell.position, cell.copyWith( objects: [], )); @@ -185,13 +189,13 @@ WorldState? processServerEvent( }); case ObjectIndexChanged(): return state.mapTableOrDefault(event.cell.table, (table) { - final cell = table.cells[event.cell.location] ?? TableCell(); + final cell = table.cells[event.cell.position] ?? TableCell(); final object = cell.objects[event.object]; final newObjects = List.from(cell.objects); newObjects.removeAt(event.object); newObjects.insert(event.index, object); return table.copyWith.cells - .replace(event.cell.location, cell.copyWith(objects: newObjects)); + .replace(event.cell.position, cell.copyWith(objects: newObjects)); }); case TeamChanged(): return state.copyWith.info.teams.put(event.name, event.team); diff --git a/api/lib/src/models/deck.dart b/api/lib/src/models/deck.dart index 8960490..1fcd46c 100644 --- a/api/lib/src/models/deck.dart +++ b/api/lib/src/models/deck.dart @@ -22,22 +22,22 @@ class DeckDefinition with DeckDefinitionMappable { class FigureDeckDefinition with FigureDeckDefinitionMappable { final String name; final String? variation; - final VectorDefinition location; + final VectorDefinition position; FigureDeckDefinition({ required this.name, this.variation, - this.location = VectorDefinition.zero, + this.position = VectorDefinition.zero, }); } @MappableClass() class BoardDeckDefinition with BoardDeckDefinitionMappable { final String name; - final VectorDefinition location; + final VectorDefinition position; BoardDeckDefinition({ required this.name, - this.location = VectorDefinition.zero, + this.position = VectorDefinition.zero, }); } diff --git a/api/lib/src/models/deck.mapper.dart b/api/lib/src/models/deck.mapper.dart index 18cd8cb..1fccf03 100644 --- a/api/lib/src/models/deck.mapper.dart +++ b/api/lib/src/models/deck.mapper.dart @@ -191,22 +191,22 @@ class FigureDeckDefinitionMapper extends ClassMapperBase { static String? _$variation(FigureDeckDefinition v) => v.variation; static const Field _f$variation = Field('variation', _$variation, opt: true); - static VectorDefinition _$location(FigureDeckDefinition v) => v.location; - static const Field _f$location = - Field('location', _$location, opt: true, def: VectorDefinition.zero); + static VectorDefinition _$position(FigureDeckDefinition v) => v.position; + static const Field _f$position = + Field('position', _$position, opt: true, def: VectorDefinition.zero); @override final MappableFields fields = const { #name: _f$name, #variation: _f$variation, - #location: _f$location, + #position: _f$position, }; static FigureDeckDefinition _instantiate(DecodingData data) { return FigureDeckDefinition( name: data.dec(_f$name), variation: data.dec(_f$variation), - location: data.dec(_f$location)); + position: data.dec(_f$position)); } @override @@ -266,8 +266,8 @@ abstract class FigureDeckDefinitionCopyWith< $R, $In extends FigureDeckDefinition, $Out> implements ClassCopyWith<$R, $In, $Out> { - VectorDefinitionCopyWith<$R, VectorDefinition, VectorDefinition> get location; - $R call({String? name, String? variation, VectorDefinition? location}); + VectorDefinitionCopyWith<$R, VectorDefinition, VectorDefinition> get position; + $R call({String? name, String? variation, VectorDefinition? position}); FigureDeckDefinitionCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( Then<$Out2, $R2> t); } @@ -282,22 +282,22 @@ class _FigureDeckDefinitionCopyWithImpl<$R, $Out> FigureDeckDefinitionMapper.ensureInitialized(); @override VectorDefinitionCopyWith<$R, VectorDefinition, VectorDefinition> - get location => $value.location.copyWith.$chain((v) => call(location: v)); + get position => $value.position.copyWith.$chain((v) => call(position: v)); @override $R call( {String? name, Object? variation = $none, - VectorDefinition? location}) => + VectorDefinition? position}) => $apply(FieldCopyWithData({ if (name != null) #name: name, if (variation != $none) #variation: variation, - if (location != null) #location: location + if (position != null) #position: position })); @override FigureDeckDefinition $make(CopyWithData data) => FigureDeckDefinition( name: data.get(#name, or: $value.name), variation: data.get(#variation, or: $value.variation), - location: data.get(#location, or: $value.location)); + position: data.get(#position, or: $value.position)); @override FigureDeckDefinitionCopyWith<$R2, FigureDeckDefinition, $Out2> @@ -323,19 +323,19 @@ class BoardDeckDefinitionMapper extends ClassMapperBase { static String _$name(BoardDeckDefinition v) => v.name; static const Field _f$name = Field('name', _$name); - static VectorDefinition _$location(BoardDeckDefinition v) => v.location; - static const Field _f$location = - Field('location', _$location, opt: true, def: VectorDefinition.zero); + static VectorDefinition _$position(BoardDeckDefinition v) => v.position; + static const Field _f$position = + Field('position', _$position, opt: true, def: VectorDefinition.zero); @override final MappableFields fields = const { #name: _f$name, - #location: _f$location, + #position: _f$position, }; static BoardDeckDefinition _instantiate(DecodingData data) { return BoardDeckDefinition( - name: data.dec(_f$name), location: data.dec(_f$location)); + name: data.dec(_f$name), position: data.dec(_f$position)); } @override @@ -393,8 +393,8 @@ extension BoardDeckDefinitionValueCopy<$R, $Out> abstract class BoardDeckDefinitionCopyWith<$R, $In extends BoardDeckDefinition, $Out> implements ClassCopyWith<$R, $In, $Out> { - VectorDefinitionCopyWith<$R, VectorDefinition, VectorDefinition> get location; - $R call({String? name, VectorDefinition? location}); + VectorDefinitionCopyWith<$R, VectorDefinition, VectorDefinition> get position; + $R call({String? name, VectorDefinition? position}); BoardDeckDefinitionCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( Then<$Out2, $R2> t); } @@ -409,17 +409,17 @@ class _BoardDeckDefinitionCopyWithImpl<$R, $Out> BoardDeckDefinitionMapper.ensureInitialized(); @override VectorDefinitionCopyWith<$R, VectorDefinition, VectorDefinition> - get location => $value.location.copyWith.$chain((v) => call(location: v)); + get position => $value.position.copyWith.$chain((v) => call(position: v)); @override - $R call({String? name, VectorDefinition? location}) => + $R call({String? name, VectorDefinition? position}) => $apply(FieldCopyWithData({ if (name != null) #name: name, - if (location != null) #location: location + if (position != null) #position: position })); @override BoardDeckDefinition $make(CopyWithData data) => BoardDeckDefinition( name: data.get(#name, or: $value.name), - location: data.get(#location, or: $value.location)); + position: data.get(#position, or: $value.position)); @override BoardDeckDefinitionCopyWith<$R2, BoardDeckDefinition, $Out2> diff --git a/api/lib/src/models/table.dart b/api/lib/src/models/table.dart index 2a3036e..f59bd39 100644 --- a/api/lib/src/models/table.dart +++ b/api/lib/src/models/table.dart @@ -48,18 +48,18 @@ class GameTable with GameTableMappable { @MappableClass() class GlobalVectorDefinition with GlobalVectorDefinitionMappable { final String table; - final VectorDefinition location; + final VectorDefinition position; GlobalVectorDefinition( this.table, int x, int y, - ) : location = VectorDefinition(x, y); + ) : position = VectorDefinition(x, y); - GlobalVectorDefinition.fromLocal(this.table, this.location); + GlobalVectorDefinition.fromLocal(this.table, this.position); - int get x => location.x; - int get y => location.y; + int get x => position.x; + int get y => position.y; } @MappableClass() diff --git a/api/lib/src/models/table.mapper.dart b/api/lib/src/models/table.mapper.dart index 24a1ee0..caf8c28 100644 --- a/api/lib/src/models/table.mapper.dart +++ b/api/lib/src/models/table.mapper.dart @@ -664,16 +664,16 @@ class GlobalVectorDefinitionMapper static const Field _f$x = Field('x', _$x); static int _$y(GlobalVectorDefinition v) => v.y; static const Field _f$y = Field('y', _$y); - static VectorDefinition _$location(GlobalVectorDefinition v) => v.location; - static const Field _f$location = - Field('location', _$location, mode: FieldMode.member); + static VectorDefinition _$position(GlobalVectorDefinition v) => v.position; + static const Field _f$position = + Field('position', _$position, mode: FieldMode.member); @override final MappableFields fields = const { #table: _f$table, #x: _f$x, #y: _f$y, - #location: _f$location, + #position: _f$position, }; static GlobalVectorDefinition _instantiate(DecodingData data) { diff --git a/api/lib/src/models/vector.dart b/api/lib/src/models/vector.dart index 5d35997..a4ea989 100644 --- a/api/lib/src/models/vector.dart +++ b/api/lib/src/models/vector.dart @@ -12,6 +12,9 @@ class VectorDefinition with VectorDefinitionMappable { static const one = VectorDefinition(1, 1); String toDisplayString() => '($x, $y)'; + + operator +(VectorDefinition other) => + VectorDefinition(x + other.x, y + other.y); } class VectorDefinitionHook extends MappingHook { diff --git a/app/lib/board/cell.dart b/app/lib/board/cell.dart index 7787243..b7a319a 100644 --- a/app/lib/board/cell.dart +++ b/app/lib/board/cell.dart @@ -243,7 +243,7 @@ class GameCell extends PositionComponent bool anyRollable(ClientWorldState state) { final assetManager = state.assetManager; final global = toGlobalDefinition(state); - final local = global.location; + final local = global.position; final cell = state.table.getCell(local); if (!state.isCellVisible(global)) return false; return cell.objects.any((object) => diff --git a/app/lib/board/hand/deck.dart b/app/lib/board/hand/deck.dart index 1d91d4e..9fdc084 100644 --- a/app/lib/board/hand/deck.dart +++ b/app/lib/board/hand/deck.dart @@ -31,15 +31,17 @@ class DeckDefinitionHandItem extends HandItem> { void moveItem(HandItemDropZone zone) { if (zone is! GameCell) return; final global = zone.toGlobalDefinition(bloc.state); - bloc.process(ObjectsSpawned( - global, - item.item.figures - .map((e) => GameObject( - asset: ItemLocation(item.namespace, e.name), - variation: e.variation)) - .toList())); + final objects = >{}; + for (final e in item.item.figures) { + final location = global.position + e.position; + objects.putIfAbsent(location, () => []).add(GameObject( + asset: ItemLocation(item.namespace, e.name), + variation: e.variation, + )); + } + bloc.process(ObjectsSpawned(bloc.state.tableName, objects)); if (bloc.state.switchCellOnMove) { - bloc.process(CellSwitched(global.location)); + bloc.process(CellSwitched(global.position)); } } } diff --git a/app/lib/board/hand/figure.dart b/app/lib/board/hand/figure.dart index 711a4a2..03b4cc3 100644 --- a/app/lib/board/hand/figure.dart +++ b/app/lib/board/hand/figure.dart @@ -29,13 +29,13 @@ class FigureDefinitionHandItem void moveItem(HandItemDropZone zone) { if (zone is! GameCell) return; final global = zone.toGlobalDefinition(bloc.state); - bloc.process(ObjectsSpawned(global, [ + bloc.process(ObjectsSpawned.single(global, [ GameObject( asset: ItemLocation(item.$1.namespace, item.$1.id), variation: item.$2) ])); if (bloc.state.switchCellOnMove) { - bloc.process(CellSwitched(global.location)); + bloc.process(CellSwitched(global.position)); } } } diff --git a/app/lib/board/hand/object.dart b/app/lib/board/hand/object.dart index ac4c92b..1017dbb 100644 --- a/app/lib/board/hand/object.dart +++ b/app/lib/board/hand/object.dart @@ -42,24 +42,24 @@ class GameObjectHandItem extends HandItem<(VectorDefinition, int, GameObject)> { void moveItem(HandItemDropZone zone) { final current = toGlobalDefinition(bloc.state); switch (zone) { - case GameCell e: - final global = e.toDefinition(); + case GameCell(): + final global = zone.toDefinition(); bloc.process(ObjectsMoved( [item.$2], current.table, - current.location, + current.position, global, )); if (bloc.state.switchCellOnMove) { bloc.process(CellSwitched(global)); } - case GameObjectHandItem e: + case GameObjectHandItem(): bloc.process(ObjectIndexChanged( current, item.$2, - e.item.$2, + zone.item.$2, )); - case GameHand _: + case GameHand(): final cell = bloc.state.table.cells[item.$1]; bloc.process(ObjectIndexChanged( current,