private void ProcessInputQueue() { var inputs = _commandQueue.Dequeue(); if (inputs.Any()) { //Store new input foreach (var input in inputs) { GameLog.Add(_world.Tick, input); foreach (var command in input.Commands) { Log.Trace(this, input.ActorId + " >> " + input.Tick + ": " + input.Commands.Count()); var inputEntity = Contexts.input.CreateEntity(); command.Execute(inputEntity); inputEntity.AddTick(input.Tick); inputEntity.AddActorId(input.ActorId); //TODO: after adding input, order the commands by timestamp => if commands intersect, the first one should win, timestamp should be added by server, RTT has to be considered //ordering by timestamp requires loopback functionality because we have to wait for server-response; at the moment commands get distributed to all clients except oneself //if a command comes back from server and it was our own command, the local command has to be overwritten instead of just adding it (like it is at the moment) } } var otherActorsInput = inputs.Where(input => input.ActorId != LocalActorId).ToList(); if (otherActorsInput.Any()) { var firstRemoteInputTick = otherActorsInput.Min(input => input.Tick); var lastRemoteInputTick = otherActorsInput.Max(input => input.Tick); Log.Trace(this, ">>>Input from " + firstRemoteInputTick + " to " + lastRemoteInputTick); //Only rollback if the mispredicted frame was in the past (the frame can be in the future e.g. due to high lag compensation) if (firstRemoteInputTick < _world.Tick) { var targetTick = _world.Tick; _world.RevertToTick(firstRemoteInputTick); //Restore last local state while (_world.Tick <= lastRemoteInputTick && _world.Tick < targetTick) { _world.Simulate(); } while (_world.Tick < targetTick) { _world.Predict(); } } } } }
private void Simulate(ServerFrame frame, bool isNeedGenSnap = true) { ProcessInputQueue(frame); _world.Simulate(isNeedGenSnap); var tick = _world.Tick; cmdBuffer.SetClientTick(tick); SetHashCode(); if (isNeedGenSnap && tick % FrameBuffer.SnapshotFrameInterval == 0) { _world.CleanUselessSnapshot(System.Math.Min(cmdBuffer.nextTickToCheck - 1, _world.Tick)); } }