public void GameTests_SpawnAndDespawnDuringConnect() { TestTransport.Reset(); // Once upon a time there was a server... TestGameServer server = new TestGameServer(); server.Update(); // One tick to get away from 0 // And it had a nice, old entity. Born all the way back in tick 1 var oldOne = server.SpawnEntity <MyEntity>(-1); // Then a client joined the server TestGameClient client = new TestGameClient(2); // They did the handshake / map / client ready server.Update(); client.Update(); // And exchanged / client config/info server.Update(); client.Update(); // Meanwhile in another part of the net, a router decides to start dropping // packages like santa himself. Horrors! Our client is now unable to speak // a word. In particualar unable to say ACK NetworkClient.clientBlockOut.Value = "1"; // The server suspects nothing and passes on a snapshot. Of course no // ack will come back from the poor client server.Update(); client.Update(); // And then, in a freak accident, just as we have sent the first snapshot // to the client, the old entity decide to die... server.DespawnEntity(oldOne); // Since we have not heard acks from the client, the server dutifully // keeps sending snapshots with no baseline. It is very tempting // for the server to not send out anything about the oldOne now. // After all it was born eons ago AND now it is gone. // How could an old, dead entity be of interest to a young client? // But what has been spawned must be despawned! // And we already told the client about the oldOne in our first snapshot. server.Update(); client.Update(); // Now the router comes back to life. Server begins to get acks // so snapshots can now be delta compressed. Skies seem to be clearing up. NetworkClient.clientBlockOut.Value = "0"; // Look at them sync again. Perhaps this is the beginning of a beautiful friendship for (int i = 0; i < 10; i++) { server.Update(); client.Update(); server.world.AssertReplicatedToClient(client.world, server.clients[0]); } // THE END }
public void GameTests_SpawnAndUpdate100Entities() { TestTransport.Reset(); TestGameServer server = new TestGameServer(); TestGameClient client = new TestGameClient(2); for (int i = 0; i < 100; ++i) { server.SpawnEntity <MyEntity>(-1); } for (int i = 0; i < 1000; ++i) { server.Update(); client.Update(); if (i > 2) { server.world.AssertReplicatedToClient(client.world, server.clients[0]); } } var c = server.networkServer.GetConnections()[server.clients[0]]; GameDebug.Log("Sent bytes: " + c.counters.bytesOut); GameDebug.Log("Sent packages: " + c.counters.packagesOut); GameDebug.Log("Generated snapshots: " + server.networkServer.statsGeneratedEntitySnapshots); GameDebug.Log("Sent snapshotdata: " + server.networkServer.statsSentOutgoing); }
public void Commands_TickTest() { TestTransport.Reset(); var random = new Random(9904); var serverTransport = new TestTransport("127.0.0.1", 1); var clientTransport = new TestTransport("127.0.0.1", 2); var snapshotConsumer = new NullSnapshotConsumer(); var server = new NetworkServer(serverTransport); var client = new NetworkClient(clientTransport); client.Connect("127.0.0.1:1"); server.InitializeMap((ref NetworkWriter data) => { data.WriteString("name", "TestMap"); }); server.Update(this); var sentCommands = new Dictionary <int, MyCommand>(); m_ReceivedCommands.Clear(); var RUNS = 1000; var serverTick = 0; var clientTick = 10; while (serverTick < RUNS) { server.Update(this); server.HandleClientCommands(serverTick, this); ++serverTick; server.SendData(); client.Update(this, snapshotConsumer); if (clientTick < RUNS) { client.QueueCommand(clientTick, (ref NetworkWriter writer) => { var sent = new MyCommand(); sent.intValue = random.Next(-1000, 1000); sent.boolValue = random.Next(0, 1) == 1; sent.floatValue = (float)random.NextDouble(); sentCommands.Add(clientTick, sent); sent.Serialize(ref writer); }); } ++clientTick; client.SendData(); } foreach (var sent in sentCommands) { sent.Value.AssertReplicatedCorrectly(m_ReceivedCommands[sent.Key], false); } }
public void Events_ServerToClient_SendReliable() { TestTransport.Reset(); var serverTransport = new TestTransport("127.0.0.1", 1); var clientTransport = new TestTransport("127.0.0.1", 2); var snapshotConsumer = new NullSnapshotConsumer(); var serverCallbacks = new ServerCallbacks(this); var clientCallbacks = new ClientCallbacks(this); var server = new NetworkServer(serverTransport); var client = new NetworkClient(clientTransport); server.Update(serverCallbacks); client.Connect("127.0.0.1:1"); server.InitializeMap((ref NetworkWriter data) => { data.WriteString("name", "TestMap"); }); server.Update(serverCallbacks); server.SendData(); client.Update(clientCallbacks, snapshotConsumer); var RUNS = 1000; eventSent = 0; eventReceived = 0; lastEventSent = null; for (int i = 0; i < RUNS; ++i) { server.Update(serverCallbacks); if (eventSent == eventReceived && i < RUNS - 32) { server.QueueEvent(1, (ushort)EventType.MyEvent, true, (ref NetworkWriter writer) => { lastEventSent = new MyEvent(); lastEventSent.Serialize(ref writer); }); ++eventSent; } server.SendData(); if (i % 3 == 0) { clientTransport.DropPackages(); } client.Update(clientCallbacks, snapshotConsumer); Assert.IsTrue(eventReceived <= eventSent); client.SendData(); } Assert.AreEqual(eventSent, eventReceived); }
public void Events_ServerToClient_BroadcastUnreliable() { TestTransport.Reset(); var snapshotConsumer = new NullSnapshotConsumer(); var serverTransport = new TestTransport("127.0.0.1", 1); var server = new NetworkServer(serverTransport); var serverCallbacks = new ServerCallbacks(this); var clientCallbacks = new ClientCallbacks(this); const int NUM_CLIENTS = 3; var clientTransports = new TestTransport[NUM_CLIENTS]; var clients = new NetworkClient[NUM_CLIENTS]; for (int i = 0; i < NUM_CLIENTS; ++i) { clientTransports[i] = new TestTransport("127.0.0.1", i + 2); clients[i] = new NetworkClient(clientTransports[i]); clients[i].Connect("127.0.0.1:1"); } server.InitializeMap((ref NetworkWriter data) => { data.WriteString("name", "TestMap"); }); server.Update(serverCallbacks); var RUNS = 1000; eventSent = 0; eventReceived = 0; lastEventSent = null; for (int i = 0; i < RUNS; ++i) { server.Update(serverCallbacks); if (eventSent == eventReceived * NUM_CLIENTS && i < RUNS - 2) { server.QueueEventBroadcast((ushort)EventType.MyEvent, false, (ref NetworkWriter writer) => { lastEventSent = new MyEvent(); lastEventSent.Serialize(ref writer); }); ++eventSent; } server.SendData(); foreach (var client in clients) { client.Update(clientCallbacks, snapshotConsumer); client.SendData(); } } Assert.AreEqual(eventSent, eventReceived / NUM_CLIENTS); }
public void GameTests_AfterNonBaselineNewEntityTypeInSameSlot() { TestTransport.Reset(); TestGameServer server = new TestGameServer(); server.Update(); TestGameClient client = new TestGameClient(2); NetworkServer.serverDebug.Value = "2"; NetworkClient.clientDebug.Value = "2"; // Handshake server.Update(); client.Update(); // Map server.Update(); client.Update(); // Spawn entity of one type TestEntity entity = server.SpawnEntity <MyEntity>(-1); server.Update(); client.Update(); server.world.AssertReplicatedToClient(client.world, server.clients[0]); // Despawn and respawn with new type server.DespawnEntity(entity); NetworkClient.clientBlockIn.Value = "-1"; NetworkConfig.netChokeSendInterval.Value = "0"; // Run enough updates so that server consider id for despawned entity reusable for (int i = 0; i < NetworkConfig.snapshotDeltaCacheSize; i++) { server.Update(); client.Update(); } // Spawn new entity. Different type but will have same id entity = server.SpawnEntity <TestEntity>(-1); NetworkClient.clientBlockIn.Value = "0"; server.Update(); client.Update(); server.Update(); client.Update(); server.world.AssertReplicatedToClient(client.world, server.clients[0]); }
public void GameTests_AfterNonBaselineStaleEntitiesRemoved() { TestTransport.Reset(); TestGameServer server = new TestGameServer(); server.Update(); TestGameClient client = new TestGameClient(2); NetworkServer.serverDebug.Value = "2"; NetworkClient.clientDebug.Value = "2"; // Handshake server.Update(); client.Update(); // Map server.Update(); client.Update(); // Spawn entity of one type TestEntity entity = server.SpawnEntity <MyEntity>(-1); server.Update(); client.Update(); server.world.AssertReplicatedToClient(client.world, server.clients[0]); NetworkClient.clientBlockIn.Value = "-1"; NetworkConfig.netChokeSendInterval.Value = "0"; // Run enough updates so that server consider id for despawned entity reusable for (int i = 0; i < NetworkConfig.snapshotDeltaCacheSize; i++) { server.Update(); client.Update(); } // Despawn. Since next update going out is without baseline, no explicit despawn will // be sent. We rely on client to prune this entity as a stale entity. server.DespawnEntity(entity); NetworkClient.clientBlockIn.Value = "0"; server.Update(); client.Update(); server.Update(); client.Update(); server.world.AssertReplicatedToClient(client.world, server.clients[0]); }
public void GameTests_StaleBaselineTest() { NetworkConfig.netChokeSendInterval.Value = "0"; TestTransport.Reset(); TestGameServer server = new TestGameServer(); server.Update(); // Server tick away from 0 TestGameClient client = new TestGameClient(2); // Handshakes server.Update(); client.Update(); server.Update(); client.Update(); var e = server.SpawnEntity <MyEntity>(-1); server.DespawnEntity(e); // Server send first snapshot. No BL. Contains SPAWN server.Update(); server.Update(); client.Update(); for (var i = 0; i < 200; i++) { server.Update(); } client.m_Transport.DropPackages(); e = server.SpawnEntity <MyEntity>(-1); server.Update(); client.Update(); server.Update(); client.Update(); server.Update(); client.Update(); NetworkConfig.netChokeSendInterval.Value = "0.3"; }
public void Events_ClientToServer_SendUnreliable() { TestTransport.Reset(); var serverTransport = new TestTransport(0); var clientTransport = new TestTransport(1); var serverCallbacks = new ServerCallbacks(this); var clientCallbacks = new ClientCallbacks(this); var server = new NetworkServer(serverTransport); var client = new NetworkClient(clientTransport); client.Connect("0"); server.InitializeMap((ref NetworkWriter data) => { data.WriteString("name", "TestMap"); }); server.Update(serverCallbacks); var RUNS = 1000; eventSent = 0; eventReceived = 0; lastEventSent = null; for (int i = 0; i < RUNS; ++i) { server.Update(serverCallbacks); server.SendData(); client.Update(clientCallbacks); if (eventSent == eventReceived && i < RUNS - 2) { client.QueueEvent((ushort)EventType.MyEvent, false, (ref NetworkWriter writer) => { lastEventSent = new MyEvent(); lastEventSent.Serialize(ref writer); }); ++eventSent; } client.SendData(); } Assert.AreEqual(eventReceived, eventSent); }
public void GameTests_RandomSpawnAndDespawn() { TestTransport.Reset(); var random = new System.Random(129315); TestGameServer server = new TestGameServer(); TestGameClient client = new TestGameClient(1); for (int i = 0; i < 1000; ++i) { // 20 % of spawning in frames 0-100, 200-300, etc. and 10% otherwise and wise // verse for despawning, so we can oscilating number oFf entities if (random.Next(0, i % 200 < 100 ? 5 : 10) == 0) { server.SpawnEntity <MyEntity>(-1); } if (random.Next(0, i % 200 > 100 ? 5 : 10) == 0 && server.world.entities.Count > 0) { var index = random.Next(0, server.world.entities.Count); var enumerator = server.world.entities.GetEnumerator(); while (index >= 0) { enumerator.MoveNext(); --index; } server.DespawnEntity(enumerator.Current.Value); } server.Update(); client.Update(); if (i > 2) { server.world.AssertReplicatedToClient(client.world, server.clients[0]); } } }
public void GameTests_SpawnAndUpdate100Entities() { TestTransport.Reset(); TestGameServer server = new TestGameServer(); TestGameClient client = new TestGameClient(1); for (int i = 0; i < 100; ++i) { server.SpawnEntity <MyEntity>(-1); } for (int i = 0; i < 1000; ++i) { server.Update(); client.Update(); if (i > 2) { server.world.AssertReplicatedToClient(client.world, server.clients[0]); } } }
public void GameTests_PredictingClientData() { TestTransport.Reset(); TestGameServer server = new TestGameServer(); TestGameClient client1 = new TestGameClient(1); TestGameClient client2 = new TestGameClient(2); // Allow server to get connections server.Update(); server.Update(); // NOTE: this relies on incoming clients getting assigned id's 1, 2, 3 .. Assert.AreEqual(2, server.clients.Count); Assert.AreEqual(1, server.clients[0]); Assert.AreEqual(2, server.clients[1]); for (int i = 0; i < 100; ++i) { // Spawn entities that are non predicted as well as predicted by either client var idx = i % (server.clients.Count + 1); var simulatingClient = idx < server.clients.Count ? server.clients[idx] : -1; server.SpawnEntity <MyEntity>(simulatingClient); server.Update(); client1.Update(); client2.Update(); if (i > 2) { server.world.AssertReplicatedToClient(client1.world, server.clients[0]); server.world.AssertReplicatedToClient(client2.world, server.clients[1]); } } }
public void GameTests_FullSpawnAndDespawn() { TestTransport.Reset(); TestGameServer server = new TestGameServer(); TestGameClient client = new TestGameClient(1); for (int i = 0; i < 100; ++i) { server.SpawnEntity <MyEntity>(-1); server.Update(); client.Update(); if (i > 2) { server.world.AssertReplicatedToClient(client.world, server.clients[0]); } } for (int i = 0; i < 100; ++i) { Assert.AreNotEqual(server.world.entities.Count, 0); var enumerator = server.world.entities.GetEnumerator(); enumerator.MoveNext(); server.DespawnEntity(enumerator.Current.Value); server.Update(); client.Update(); if (i > 2) { server.world.AssertReplicatedToClient(client.world, server.clients[0]); } } // Test spawn and despawn in same frame for (int i = 0; i < 4; ++i) { var entity = server.SpawnEntity <MyEntity>(-1); server.DespawnEntity(entity); server.Update(); client.Update(); if (i > 2) { server.world.AssertReplicatedToClient(client.world, server.clients[0]); } } // Run server for enough ticks so that it can assume all despawned entities are too old to be of interest // to any client. for (int i = 0; i < NetworkConfig.snapshotDeltaCacheSize + 1; i++) { server.Update(); client.Update(); } // Then server should have deleted them all from its internal list Assert.AreEqual(0, server.networkServer.NumEntities); }
public void Commands_TickJumpBack() { TestTransport.Reset(); var random = new Random(9904); var serverTransport = new TestTransport(0); var clientTransport = new TestTransport(1); var server = new NetworkServer(serverTransport); var client = new NetworkClient(clientTransport); client.Connect("0"); server.InitializeMap((ref NetworkWriter data) => { data.WriteString("name", "TestMap"); }); server.Update(this); var sentCommands = new Dictionary <int, MyCommand>(); m_ReceivedCommands.Clear(); var RUNS = 100; var serverTick = 0; var clientTick = 10; bool jumped = false; while (serverTick < RUNS) { server.Update(this); server.HandleClientCommands(serverTick, this); ++serverTick; server.SendData(); client.Update(this); if (clientTick < RUNS) { if (!jumped && clientTick == 50) { jumped = true; clientTick = 45; for (int i = serverTick; i < 50; ++i) { sentCommands.Remove(i); } } client.QueueCommand(clientTick, (ref NetworkWriter writer) => { var sent = new MyCommand(); sent.intValue = random.Next(-1000, 1000); sent.boolValue = random.Next(0, 1) == 1; sent.floatValue = (float)random.NextDouble(); sentCommands.Add(clientTick, sent); sent.Serialize(ref writer); }); } ++clientTick; client.SendData(); } foreach (var sent in sentCommands) { sent.Value.AssertReplicatedCorrectly(m_ReceivedCommands[sent.Key], false); } }