private void ProcessPlayerMovement(NetPlayer p) { //TODO: if the player is too far behind, we insert fake movement while (p.MoveQueueUnverified.Count > 0) { var move = p.MoveQueueUnverified[0]; p.MoveQueueUnverified.RemoveAt(0); //TODO: check for speed hacks etc Shared.ProcessMovementAndCollisions(move, p.ClientSimPlayer, shots, p.PreviousHits); var attackState = Shared.ProcessPlayerAttackCharge(move, p.ClientSimPlayer); if (attackState != null) { PlayerAttack(p.ClientSimPlayer, attackState.Radius); } p.MoveQueueVerified.Add(move); } //Copy health and charge from client version to shared version of player //TODO: think through whether doing this immediately is bad (it won't be in sync with movement) p.Player.Health = p.ClientSimPlayer.Health; p.Player.Charge = p.ClientSimPlayer.Charge; //Publish any movement that is sufficiently old while (p.MoveQueueVerified.Count > 0) { int count = 0; var first = p.MoveQueueVerified[0]; if (first.Tick < lastStep - playerReplayLag) { p.Player.X += first.X; p.Player.Y += first.Y; p.MoveQueueVerified.RemoveAt(0); count++; } else { break; } } }
private void Start() { Console.WriteLine("Starting game server…"); creatureTypes = new CreatureType[1]; creatureTypes[0] = new CreatureType(); stopwatch.Start(); netPlayers = new List <NetPlayer>(); players = new List <Player>(); creatures = new List <Creature>(); shots = new List <Shot>(); EventBasedNetListener listener = new EventBasedNetListener(); NetManager server = new NetManager(listener, MaxClients, connectionKey); if (Packets.SimulateLatency) { server.SimulateLatency = true; server.SimulationMinLatency = Packets.SimulationMinLatency; server.SimulationMaxLatency = Packets.SimulationMaxLatency; server.SimulatePacketLoss = Packets.SimulatePacketLoss; server.SimulationPacketLossChance = Packets.SimulationPacketLossChance; } server.Start(Port); listener.PeerConnectedEvent += peer => { Console.WriteLine("We got connection: {0}", peer.EndPoint); var netPlayer = new NetPlayer(peer.ConnectId, peer); netPlayer.Player = new Player(NewPlayerId()); netPlayer.ClientSimPlayer = new Player(NewPlayerId()); netPlayers.Add(netPlayer); players.Add(netPlayer.Player); Console.WriteLine("{0} clients", server.GetPeers().Count()); NetDataWriter writer = new NetDataWriter(); writer.Put(Packets.WelcomeClient); writer.Put(netPlayer.Player.Id); writer.Put(lastStep); writer.Put(netPlayer.Player.X); writer.Put(netPlayer.Player.Y); peer.Send(writer, SendOptions.ReliableOrdered); }; listener.NetworkReceiveEvent += (peer, reader) => { byte packetType = reader.GetByte(); if (packetType == Packets.Pong) { var pingStart = reader.GetLong(); var lag = stopwatch.ElapsedMilliseconds - pingStart; Console.WriteLine("Ping: " + lag); } if (packetType == Packets.ClientMovement) { var player = netPlayers.Find(p => p.PeerId == peer.ConnectId); if (player == null) { Console.WriteLine("Peer tried to move but has no associated NetPlayer"); } else { //Console.Write("Getting moveticks "); var count = reader.GetInt(); long tick = reader.GetLong(); for (var i = 0; i < count; i++) { tick += reader.GetInt(); //delta sbyte x = reader.GetSByte(); sbyte y = reader.GetSByte(); bool charging = reader.GetBool(); if (tick > player.LastAckedMove && !player.MoveQueueUnverified.Any(qm => qm.Tick == tick) && !player.MoveQueueVerified.Any(qm => qm.Tick == tick)) { player.MoveQueueUnverified.Add(new QueuedMove(tick, x, y, charging)); //Console.WriteLine("Client Move: " + tick + " vs real time " + lastStep + " with " + count + " move snapshots"); //Console.WriteLine("Move lag: " + (lastStep - tick)); } // else dropping duplicate or out-of-order movement if (i == count - 1 && player.LastAckedMove < tick) { player.LastAckedMove = tick; player.RecordLatency((int)(lastStep - tick)); } } //Console.WriteLine(); } } }; while (!Console.KeyAvailable) { long elapsed = stopwatch.ElapsedMilliseconds; while (elapsed > lastStep + simulationTickRate) { Update(server); lastStep = lastStep + simulationTickRate; } long postUpdateElapsed = stopwatch.ElapsedMilliseconds; int earlyAmount = (int)(lastStep + simulationTickRate - postUpdateElapsed); if (earlyAmount > 2) { Thread.Sleep(earlyAmount - 2); } } server.Stop(); }