private void GetGameUpdates(UdpClient client) { Log("Receiving GameSteps"); try { while (!_shutdown) { IPEndPoint endPoint = null; var msg = client.Receive(ref endPoint); using (var br = new BinaryReader(new MemoryStream(msg))) { if ((SC_Message)msg[0] == SC_Message.GameStepCollection) { GameStepCollection gsc = new GameStepCollection(br); foreach (var gs in gsc.GameSteps) { if (gs.StepNumber > _highestGameStepNum + 8) { Log("Disconnected!"); throw new Exception("Disconnected!"); } _highestGameStepNum = Math.Max(gs.StepNumber, _highestGameStepNum); lock (_gameHistory) { _gameHistory.Add(gs); } if (gs.PlayerInputs.Any()) { var msgs = gs.PlayerInputs .Select(pi => pi.Key + ":" + String.Join("|", pi.Value.Inputs.Select(k => k.Key + ":" + k.Value).ToArray())) .Aggregate((a, e) => a + "," + e); //Log("[" + gs.StepNumber + "] " + msgs); } } } else { Log("Invalid Message!"); } } } } catch (Exception e) { Log(e.ToString()); } Log("GetGameSteps Exit"); }
private void BroadcastGameStepCollection(GameStepCollection gsc) { bw.Seek(0, SeekOrigin.Begin); gsc.SerializeToBuff(bw); bw.Flush(); var tasks = _playersById.Select(async player => { try { //if (new Random().Next(0, 100) <= 6) return; // 7% packet loss await player.UdpClient.SendAsync(tempBuff, (int)ms.Position, player.RemoteEndPoint); } catch (Exception e) { Console.WriteLine(e); } }) .AsParallel() .ToArray(); Task.WaitAll(tasks); }
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); } }