public void SendGameStateUpdate() { DebugTools.Assert(_networkManager.IsServer); if (!_networkManager.IsConnected) { // Prevent deletions piling up if we have no clients. _entityManager.CullDeletionHistory(uint.MaxValue); _mapManager.CullDeletionHistory(uint.MaxValue); return; } var oldestAck = uint.MaxValue; foreach (var connection in _networkManager.Channels) { if (!ackedStates.TryGetValue(connection.ConnectionId, out var ack)) { ackedStates.Add(connection.ConnectionId, 0); } else if (ack < oldestAck) { oldestAck = ack; } } if (oldestAck > lastOldestAck) { lastOldestAck = oldestAck; _entityManager.CullDeletionHistory(oldestAck); } var entities = _entityManager.GetEntityStates(oldestAck); var players = _playerManager.GetPlayerStates(); var deletions = _entityManager.GetDeletedEntities(oldestAck); var mapData = _mapManager.GetStateData(oldestAck); var state = new GameState(oldestAck, _gameTiming.CurTick, entities, players, deletions, mapData); foreach (var c in _networkManager.Channels) { var session = _playerManager.GetSessionByChannel(c); if (session == null || session.Status != SessionStatus.InGame) { continue; } var stateUpdateMessage = _networkManager.CreateNetMessage <MsgState>(); stateUpdateMessage.State = state; _networkManager.ServerSendMessage(stateUpdateMessage, c); } }
/// <inheritdoc /> public void SendGameStateUpdate() { DebugTools.Assert(_networkManager.IsServer); _entityManager.Update(); if (!_networkManager.IsConnected) { // Prevent deletions piling up if we have no clients. _entityManager.CullDeletionHistory(GameTick.MaxValue); _mapManager.CullDeletionHistory(GameTick.MaxValue); return; } var inputSystem = _systemManager.GetEntitySystem <InputSystem>(); var oldestAck = GameTick.MaxValue; var oldDeps = IoCManager.Resolve <IDependencyCollection>(); var deps = new DependencyCollection(); deps.RegisterInstance <ILogManager>(new ProxyLogManager(IoCManager.Resolve <ILogManager>())); deps.BuildGraph(); (MsgState, INetChannel) GenerateMail(IPlayerSession session) { IoCManager.InitThread(deps, true); if (session.Status != SessionStatus.InGame) { return(default);
/// <inheritdoc /> public void SendGameStateUpdate() { DebugTools.Assert(_networkManager.IsServer); _entityManager.Update(); if (!_networkManager.IsConnected) { // Prevent deletions piling up if we have no clients. _entityManager.CullDeletionHistory(GameTick.MaxValue); _mapManager.CullDeletionHistory(GameTick.MaxValue); return; } var inputSystem = _systemManager.GetEntitySystem <InputSystem>(); var oldestAck = GameTick.MaxValue; foreach (var session in _playerManager.GetAllPlayers()) { if (session.Status != SessionStatus.InGame) { continue; } var channel = session.ConnectedClient; if (!_ackedStates.TryGetValue(channel.ConnectionId, out var lastAck)) { DebugTools.Assert("Why does this channel not have an entry?"); } var entStates = lastAck == GameTick.Zero || !PvsEnabled ? _entityManager.GetEntityStates(lastAck) : _entityManager.UpdatePlayerSeenEntityStates(lastAck, session, _entityManager.MaxUpdateRange); var playerStates = _playerManager.GetPlayerStates(lastAck); var deletions = _entityManager.GetDeletedEntities(lastAck); var mapData = _mapManager.GetStateData(lastAck); // lastAck varies with each client based on lag and such, we can't just make 1 global state and send it to everyone var lastInputCommand = inputSystem.GetLastInputCommand(session); var lastSystemMessage = _entityNetworkManager.GetLastMessageSequence(session); var state = new GameState(lastAck, _gameTiming.CurTick, Math.Max(lastInputCommand, lastSystemMessage), entStates?.ToArray(), playerStates?.ToArray(), deletions?.ToArray(), mapData); if (lastAck < oldestAck) { oldestAck = lastAck; } // actually send the state var stateUpdateMessage = _networkManager.CreateNetMessage <MsgState>(); stateUpdateMessage.State = state; _networkManager.ServerSendMessage(stateUpdateMessage, channel); // If the state is too big we let Lidgren send it reliably. // This is to avoid a situation where a state is so large that it consistently gets dropped // (or, well, part of it). // When we send them reliably, we immediately update the ack so that the next state will not be huge. if (stateUpdateMessage.ShouldSendReliably()) { _ackedStates[channel.ConnectionId] = _gameTiming.CurTick; } } // keep the deletion history buffers clean if (oldestAck > _lastOldestAck) { _lastOldestAck = oldestAck; _entityManager.CullDeletionHistory(oldestAck); _mapManager.CullDeletionHistory(oldestAck); } }
/// <inheritdoc /> public void SendGameStateUpdate() { DebugTools.Assert(_networkManager.IsServer); if (!_networkManager.IsConnected) { // Prevent deletions piling up if we have no clients. _entityManager.CullDeletionHistory(GameTick.MaxValue); _mapManager.CullDeletionHistory(GameTick.MaxValue); return; } var oldestAck = GameTick.MaxValue; foreach (var channel in _networkManager.Channels) { var session = _playerManager.GetSessionByChannel(channel); if (session == null || session.Status != SessionStatus.InGame) // client still joining, maybe iterate over sessions instead? { continue; } if (!_ackedStates.TryGetValue(channel.ConnectionId, out var lastAck)) { DebugTools.Assert("Why does this channel not have an entry?"); } //TODO: Cull these based on client view rectangle, remember the issues with transform parenting var entities = _entityManager.GetEntityStates(lastAck); var players = _playerManager.GetPlayerStates(lastAck); var deletions = _entityManager.GetDeletedEntities(lastAck); var mapData = _mapManager.GetStateData(lastAck); // lastAck varies with each client based on lag and such, we can't just make 1 global state and send it to everyone var state = new GameState(lastAck, _gameTiming.CurTick, entities, players, deletions, mapData); // actually send the state var stateUpdateMessage = _networkManager.CreateNetMessage <MsgState>(); stateUpdateMessage.State = state; _networkManager.ServerSendMessage(stateUpdateMessage, channel); // we are not going to send a full state every tick (rip bandwidth) until they ack, so assume they receive it // and start the deltas from the full state. // the client will signal to us if they need another one. if (lastAck == GameTick.Zero) { _ackedStates[channel.ConnectionId] = _gameTiming.CurTick; } if (lastAck < oldestAck) { oldestAck = lastAck; } } // keep the deletion history buffers clean if (oldestAck > _lastOldestAck) { _lastOldestAck = oldestAck; _entityManager.CullDeletionHistory(oldestAck); _mapManager.CullDeletionHistory(oldestAck); } }
/// <inheritdoc /> public void SendGameStateUpdate() { DebugTools.Assert(_networkManager.IsServer); if (!_networkManager.IsConnected) { // Prevent deletions piling up if we have no clients. _entityManager.CullDeletionHistory(GameTick.MaxValue); _mapManager.CullDeletionHistory(GameTick.MaxValue); return; } var oldestAck = GameTick.MaxValue; var work = new List <(INetChannel channel, GameTick lastAck)>(); foreach (var channel in _networkManager.Channels) { var session = _playerManager.GetSessionByChannel(channel); if (session == null || session.Status != SessionStatus.InGame) { // client still joining, maybe iterate over sessions instead? continue; } if (!_ackedStates.TryGetValue(channel.ConnectionId, out var lastAck)) { DebugTools.Assert("Why does this channel not have an entry?"); } work.Add((channel, lastAck)); if (lastAck < oldestAck) { oldestAck = lastAck; } } var workDone = ParallelStates ? work.AsParallel().Select(GenerateStateFor).ToList() : work.Select(GenerateStateFor).ToList(); foreach (var(channel, state) in workDone) { // actually send the state var stateUpdateMessage = _networkManager.CreateNetMessage <MsgState>(); stateUpdateMessage.State = state; _networkManager.ServerSendMessage(stateUpdateMessage, channel); // If the state is too big we let Lidgren send it reliably. // This is to avoid a situation where a state is so large that it consistently gets dropped // (or, well, part of it). // When we send them reliably, we immediately update the ack so that the next state will not be huge. if (stateUpdateMessage.ShouldSendReliably()) { _ackedStates[channel.ConnectionId] = _gameTiming.CurTick; } } // keep the deletion history buffers clean if (oldestAck > _lastOldestAck) { _lastOldestAck = oldestAck; _entityManager.CullDeletionHistory(oldestAck); _mapManager.CullDeletionHistory(oldestAck); } }