processServerEvent function

ServerProcessed processServerEvent(
  1. ServerWorldEvent event,
  2. WorldState state, {
  3. required List<SignatureMetadata> signature,
})

Implementation

ServerProcessed processServerEvent(
  ServerWorldEvent event,
  WorldState state, {
  required List<SignatureMetadata> signature,
}) {
  if (!isValidServerEvent(event, state)) return ServerProcessed(null);
  switch (event) {
    case WorldInitialized():
      final serverSignature = event.packsSignature;
      final supported = serverSignature == null
          ? true
          : isServerSupported(signature, serverSignature);
      if (!supported) {
        throw InvalidPacksError(
          signature: serverSignature,
          expected: signature,
        );
      }
      return ServerProcessed(
        state.copyWith(
          table: event.table ?? state.table,
          id: event.id ?? state.id,
          teamMembers: event.teamMembers ?? state.teamMembers,
          info: event.info ?? state.info,
          dialogs: event.clearUserInterface ? [] : state.dialogs,
          images: event.clearUserInterface ? {} : state.images,
          gameState: GameState.play,
          authRequest: null,
        ),
      );
    case TeamJoined():
      return ServerProcessed(
        state.copyWith(
          teamMembers: {
            ...state.teamMembers,
            event.team: {...?state.teamMembers[event.team], event.user},
          },
        ),
      );
    case TeamLeft():
      final members = Set<Channel>.from(state.teamMembers[event.team] ?? {});
      members.remove(event.user);
      final allMembers = Map<String, Set<int>>.from(state.teamMembers);
      if (members.isEmpty) {
        allMembers.remove(event.team);
      } else {
        allMembers[event.team] = members;
      }
      return ServerProcessed(state.copyWith(teamMembers: allMembers));
    case ObjectsChanged():
      return ServerProcessed(
        state.mapTableOrDefault(event.cell.table, (table) {
          final cell = table.cells[event.cell.position] ?? TableCell();
          final newCell = cell.copyWith(objects: event.objects);
          if (newCell.isEmpty) {
            return table.copyWith.cellsBox(
              content: Map<VectorDefinition, TableCell>.from(table.cells)
                ..remove(event.cell.position),
            );
          }
          return table.copyWith.cellsBox(
            content: Map<VectorDefinition, TableCell>.from(table.cells)
              ..[event.cell.position] = newCell,
          );
        }),
      );
    case CellShuffled(positions: final positions):
      return ServerProcessed(
        state.mapTableOrDefault(event.cell.table, (table) {
          final cell = table.cells[event.cell.position] ?? TableCell();
          final objects = cell.objects;
          final newObjects = List<GameObject>.from(objects);
          for (var i = 0; i < positions.length; i++) {
            newObjects[positions[i]] = objects[i];
          }
          return table.copyWith.cellsBox(
            content: Map<VectorDefinition, TableCell>.from(table.cells)
              ..[event.cell.position] = cell.copyWith(objects: newObjects),
          );
        }),
      );
    case BackgroundChanged():
      return ServerProcessed(
        state.copyWith.table(background: event.background),
      );
    case ObjectsSpawned():
      return ServerProcessed(
        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.cellsBox(
              content: Map<VectorDefinition, TableCell>.from(newTable.cells)
                ..[entry.key] = cell.copyWith(objects: entry.value),
            );
          }
          return newTable;
        }),
      );
    case ObjectsMoved():
      return ServerProcessed(
        state.mapTableOrDefault(event.table, (table) {
          var from = table.cells[event.from] ?? TableCell();
          var to = table.cells[event.to] ?? TableCell();
          final toRemove = List<int>.from(event.objects)
            ..sort((a, b) => b.compareTo(a));
          final toAdd = toRemove.map((e) => from.objects[e]).toList();
          final newObjects = List<GameObject>.from(from.objects);
          for (final i in toRemove) {
            newObjects.removeAt(i);
          }
          from = from.copyWith(objects: newObjects);
          to = to.copyWith(objects: [...to.objects, ...toAdd]);
          final cells = Map<VectorDefinition, TableCell>.from(table.cells)
            ..[event.to] = to;
          if (from.isEmpty) {
            cells.remove(event.from);
          } else {
            cells[event.from] = from;
          }

          return table.copyWith.cellsBox(content: cells);
        }),
      );
    case CellHideChanged():
      return ServerProcessed(
        state.mapTableOrDefault(event.cell.table, (table) {
          final cell = table.cells[event.cell.position] ?? TableCell();
          final objectIndex = event.object;
          if (objectIndex != null) {
            final object = cell.objects[objectIndex];
            return table.copyWith.cellsBox(
              content: Map<VectorDefinition, TableCell>.from(table.cells)
                ..[event.cell.position] = cell.copyWith.objects.replace(
                  objectIndex,
                  object.copyWith(hidden: event.hide ?? !object.hidden),
                ),
            );
          }
          final hidden =
              !(event.hide ?? cell.objects.firstOrNull?.hidden ?? false);
          return table.copyWith.cellsBox(
            content: Map<VectorDefinition, TableCell>.from(table.cells)
              ..[event.cell.position] = cell.copyWith(
                objects: cell.objects
                    .map((e) => e.copyWith(hidden: hidden))
                    .toList(),
              ),
          );
        }),
      );
    case ObjectsRemoved():
      return ServerProcessed(
        state.mapTableOrDefault(event.cell.table, (table) {
          final cell = table.cells[event.cell.position] ?? TableCell();
          final objectIndex = event.objects;
          var newCell = cell;
          if (objectIndex != null) {
            final objects = List<GameObject>.from(cell.objects);
            final indexes = objectIndex.toList()
              ..sort((a, b) => b.compareTo(a));
            for (final index in indexes) {
              objects.removeAt(index);
            }
            newCell = cell.copyWith();
          } else {
            newCell = cell.copyWith(objects: []);
          }
          if (newCell.isEmpty) {
            return table.copyWith.cellsBox(
              content: Map<VectorDefinition, TableCell>.from(table.cells)
                ..remove(event.cell.position),
            );
          }
          return table.copyWith.cellsBox(
            content: Map<VectorDefinition, TableCell>.from(table.cells)
              ..[event.cell.position] = newCell,
          );
        }),
      );
    case ObjectIndexChanged():
      return ServerProcessed(
        state.mapTableOrDefault(event.cell.table, (table) {
          final cell = table.cells[event.cell.position] ?? TableCell();
          final object = cell.objects[event.object];
          final newObjects = List<GameObject>.from(cell.objects);
          newObjects.removeAt(event.object);
          newObjects.insert(event.index, object);
          return table.copyWith.cellsBox(
            content: Map<VectorDefinition, TableCell>.from(table.cells)
              ..[event.cell.position] = cell.copyWith(objects: newObjects),
          );
        }),
      );
    case TeamChanged():
      var info = state.info;
      var newName = event.newName;
      var teamMembers = Map<String, Set<int>>.from(state.teamMembers);
      if (newName != null) {
        final teams = Map<String, GameTeam>.fromEntries(
          info.teams.entries.map((e) {
            if (e.key == event.name) {
              return MapEntry(newName, event.team);
            }
            return e;
          }),
        );
        info = info.copyWith(teams: teams);
        teamMembers[newName] = teamMembers.remove(event.name) ?? {};
      } else {
        info = info.copyWith.teams.put(event.name, event.team);
      }
      return ServerProcessed(
        state.copyWith(info: info, teamMembers: teamMembers),
      );
    case TeamRemoved():
      return ServerProcessed(
        state.copyWith(
          info: state.info.copyWith.teams.remove(event.team),
          teamMembers: Map.from(state.teamMembers)..remove(event.team),
        ),
      );
    case MetadataChanged():
      return ServerProcessed(state.copyWith(metadata: event.metadata));
    case MessageSent():
      return ServerProcessed(
        state.copyWith.messages.add(
          ChatMessage(
            author: event.user,
            content: event.message,
            timestamp: DateTime.now(),
          ),
        ),
      );
    case TableRenamed():
      final data = state.data.getTable(event.name);
      return ServerProcessed(
        state.copyWith(
          tableName: event.name == state.tableName
              ? event.newName
              : state.tableName,
          data: data == null
              ? state.data
              : state.data
                    .removeTable(event.name)
                    .setTable(data, event.newName),
        ),
      );
    case TableRemoved():
      return ServerProcessed(
        state.copyWith(
          tableName: state.tableName == event.name ? '' : state.tableName,
          data: state.data.removeTable(event.name),
        ),
      );
    case NoteChanged():
      return ServerProcessed(
        state.copyWith(data: state.data.setNote(event.name, event.content)),
      );
    case NoteRemoved():
      return ServerProcessed(
        state.copyWith(data: state.data.removeNote(event.name)),
      );
    case BoardTilesSpawned():
      return ServerProcessed(
        state.mapTableOrDefault(event.table, (table) {
          final cells = Map<VectorDefinition, TableCell>.from(table.cells);
          for (final entry in event.tiles.entries) {
            cells[entry.key] = table
                .getCell(entry.key)
                .copyWith
                .tiles
                .addAll(entry.value);
          }
          return table.copyWith.cellsBox(content: cells);
        }),
      );
    case BoardTilesChanged():
      return ServerProcessed(
        state.mapTableOrDefault(event.table, (table) {
          final cells = Map<VectorDefinition, TableCell>.from(table.cells);
          for (final entry in event.tiles.entries) {
            final newCell = table
                .getCell(entry.key)
                .copyWith(tiles: entry.value);
            if (newCell.isEmpty) {
              cells.remove(entry.key);
            } else {
              cells[entry.key] = newCell;
            }
          }
          return table.copyWith.cellsBox(content: cells);
        }),
      );
    case DialogOpened():
      final index = state.dialogs.indexWhere((e) => e.id == event.dialog.id);
      final image = event.dialog.image;
      final responses = <ClientWorldEvent>[];
      if (image != null && !state.images.containsKey(image)) {
        responses.add(ImagesRequest([image]));
      }
      if (index != -1) {
        return ServerProcessed(
          state.copyWith.dialogs.replace(index, event.dialog),
          responses,
        );
      }
      return ServerProcessed(
        state.copyWith.dialogs.add(event.dialog),
        responses,
      );
    case DialogsClosed():
      return ServerProcessed(
        state.copyWith.dialogs.where(
          (e) => !(event.ids?.contains(e.id) ?? true),
        ),
      );
    case ImagesUpdated():
      return ServerProcessed(
        state.copyWith(images: {...state.images, ...event.images}),
      );
    case ServerStateUpdated():
      return ServerProcessed(state.copyWith(serverState: event.state));
    case AuthenticatedRequested():
      return ServerProcessed(state.copyWith(authRequest: event));
  }
}