public GameStep?GetNextStep() { lock (_gameHistory) { GameStep nextStep = new GameStep(); // If new Game Step is found if (_gameHistory.TryGet(_unityGameStepNum, out nextStep)) { if (_unityGameStepNum != nextStep.StepNumber) { Log("Exception!"); throw new InvalidProgramException("Next step should be last step + 1!"); } _unityGameStepNum++; return(nextStep); } // If no game step is found else { var lag = _highestGameStepNum - _unityGameStepNum; return(null); } } }
private void SendPlayerUpdates() { Console.WriteLine("Starting Broadcasts"); _lastStepBroadcast = DateTime.UtcNow; DateTime start = DateTime.UtcNow; int sleepIntervalMs = GameStepIntervalMs; try { while (true) { if (sleepIntervalMs > 0) { Thread.Sleep(sleepIntervalMs); } start = DateTime.UtcNow; GameStep gameStep; lock (_gameLock) { byte ellapsed = (byte)Math.Min((DateTime.UtcNow - _lastStepBroadcast).TotalMilliseconds, byte.MaxValue); // Create new GameStep to broadcast gameStep = new GameStep(_stepNumber, ellapsed); GameStep lastGameStep; // If previous GameSteps exit if (_gameHistory.Count > 0 && _gameHistory.TryGet((UInt16)(_stepNumber - 1), out lastGameStep)) { foreach (var currentInput in _curPlayerInputs) { // If Player input exists from last game update, take XOR of last player input and current player input PlayerInputs lastInput; if (lastGameStep.PlayerInputs.TryGetValue(currentInput.Key, out lastInput)) { var changed = currentInput.Value.Inputs .Where(i => !lastInput.Inputs.ContainsKey(i.Key) || lastInput.Inputs[i.Key] != i.Value) .ToDictionary(k => k.Key, k => k.Value); PlayerInputs pi = new PlayerInputs() { PlayerId = currentInput.Key, Inputs = changed }; gameStep.PlayerInputs.Add(pi.PlayerId, pi); } // If no last game update for this player, just send current inputs else { gameStep.PlayerInputs.Add(currentInput.Key, currentInput.Value); } } _curPlayerInputs.Clear(); } // If no previous GameSteps exist else { gameStep.PlayerInputs = _curPlayerInputs; } _gameHistory.Add(gameStep); } GameStepCollection gsc = new GameStepCollection(3); gsc.GameSteps.Add(gameStep); // Send Redundant Step #1 if (_stepNumber >= 1) { UInt16 idx = (UInt16)Math.Max(_stepNumber - 2, 0); GameStep redundant; if (_gameHistory.TryGet(idx, out redundant)) { gsc.GameSteps.Add(redundant); } } // Send Redundant Step #2 if (_stepNumber >= 3) { UInt16 idx = (UInt16)Math.Max(_stepNumber - 8, 0); GameStep redundant; if (_gameHistory.TryGet(idx, out redundant)) { gsc.GameSteps.Add(redundant); } } BroadcastGameStepCollection(gsc); // Calculate next Sleep Interval _lastStepBroadcast = DateTime.UtcNow; _stepNumber++; TimeSpan broadcastDuration = (_lastStepBroadcast - start); sleepIntervalMs = Math.Max(GameStepIntervalMs - (int)broadcastDuration.TotalMilliseconds, 0); } } catch (Exception e) { Console.Write(e); } }