onClientEvent method

Future<void> onClientEvent(
  1. NetworkerPacket<WorldEvent> packet, {
  2. bool force = false,
})

Implementation

Future<void> onClientEvent(
  NetworkerPacket<WorldEvent> packet, {
  bool force = false,
}) async {
  final data = packet.data;
  if (!packet.isServer &&
      data is ClientWorldEvent &&
      data is! AuthenticateRequest) {
    final user = server.userManager.getUser(packet.channel);
    if (user == null ||
        !canProcessClientEvent(
          user.roles,
          data,
          server.configManager.serverRoles,
        )) {
      server.log(
        'Rejected ${data.runtimeType} from channel ${packet.channel}: '
        '${user == null ? 'unauthenticated' : 'roles ${user.roles.join(', ')}'}',
        level: LogLevel.warning,
      );
      return;
    }
    if (!isValidClientEvent(
      data,
      packet.channel,
      state,
      assetManager: assetManager,
      allowManagementRequests: true,
    )) {
      server.log(
        'Rejected invalid ${data.runtimeType} payload from channel '
        '${packet.channel}.',
        level: LogLevel.warning,
      );
      return;
    }
    if (await _handleManagementEvent(data, packet.channel)) return;
  }
  ServerResponse? process;
  try {
    process = await processClientEvent(
      data is UserJoined ? null : data,
      packet.channel,
      state,
      assetManager: assetManager,
      allowServerEvents: packet.isServer,
      // The dedicated server has already applied role authorization above.
      // Peer-hosted games retain the shared API's authority-only default.
      allowManagementRequests: true,
      challengeManager: server.challengeManager,
      userManager: server.userManager,
    );
  } catch (e) {
    server.log('Error processing event: $e', level: LogLevel.error);
  }
  if (process == null) return;
  switch (process) {
    case UpdateServerResponse():
      final event = Event(
        serverEvent: process.main?.data,
        target: process.main?.channel ?? kAnyChannel,
        clientEvent: data,
        source: packet.channel,
        needsUpdate: process.needsUpdate,
        worldName: worldName,
      );
      if (!force) {
        await server.defaultWorld.pluginSystem.fire(event);
        if (event.cancelled) return;
        server.log(
          'Processing event by ${event.source}: ${limitOutput(event.clientEvent)}, answered with ${limitOutput(event.serverEvent)}',
          level: LogLevel.verbose,
        );
      }
      switch (packet.data) {
        case MessageRequest data:
          server.log(
            "Message by ${packet.channel}: ${data.message}",
            level: LogLevel.info,
          );
        default:
      }
      _scheduledUpdates.add((event.serverEvent, process, event.needsUpdate));
      final serverEvent = event.serverEvent;
      if (serverEvent != null) {
        await sendEvent(serverEvent, target: event.target);
      }
      for (final scheduled in event.scheduledEvents) {
        await onClientEvent(scheduled, force: true);
      }
    case KickServerResponse():
      server.kick(packet.channel, process.message);
  }
  if (data is AuthenticateRequest) {
    final user = server.userManager.getUser(packet.channel);
    if (user != null) {
      final validRoles = {
        kDefaultServerRole,
        ...user.roles.where(server.configManager.serverRoles.containsKey),
      };
      if (validRoles.length != user.roles.length ||
          !validRoles.containsAll(user.roles)) {
        await server.userManager.changeRoles(
          '#${packet.channel}',
          validRoles,
        );
      }
    }
  }
  if (data is UserJoined || data is AuthenticateRequest) {
    await server.broadcastServerState(this);
  }
}