public override void ServerLateUpdate() { // flush reliable messages after latency while (reliableServerToClient.Count > 0) { // check the first message time QueuedMessage message = reliableServerToClient[0]; if (message.time + reliableLatency <= Time.time) { // send and eat wrap.ServerSend(message.connectionId, Channels.Reliable, new ArraySegment <byte>(message.bytes)); reliableServerToClient.RemoveAt(0); } // not enough time elapsed yet break; } // flush unreliable messages after latency while (unreliableServerToClient.Count > 0) { // check the first message time QueuedMessage message = unreliableServerToClient[0]; if (message.time + unreliableLatency <= Time.time) { // send and eat wrap.ServerSend(message.connectionId, Channels.Unreliable, new ArraySegment <byte>(message.bytes)); unreliableServerToClient.RemoveAt(0); } // not enough time elapsed yet break; } // update wrapped transport too wrap.ServerLateUpdate(); }
public override void ServerLateUpdate() { // flush reliable messages that are ready to be sent // => list isn't ordered (due to scramble). need to iterate all. for (int i = 0; i < reliableServerToClient.Count; ++i) { QueuedMessage message = reliableServerToClient[i]; if (Time.time >= message.timeToSend) { // send and remove wrap.ServerSend(message.connectionId, Channels.DefaultReliable, new ArraySegment <byte>(message.bytes)); reliableServerToClient.RemoveAt(i); --i; } } // flush unrelabe messages that are ready to be sent // => list isn't ordered (due to scramble). need to iterate all. for (int i = 0; i < unreliableServerToClient.Count; ++i) { QueuedMessage message = unreliableServerToClient[i]; if (Time.time >= message.timeToSend) { // send and remove wrap.ServerSend(message.connectionId, Channels.DefaultUnreliable, new ArraySegment <byte>(message.bytes)); unreliableServerToClient.RemoveAt(i); --i; } } // update wrapped transport too wrap.ServerLateUpdate(); }
public override void ClientLateUpdate() { // flush reliable messages after latency while (reliableClientToServer.Count > 0) { // check the first message time QueuedMessage message = reliableClientToServer[0]; if (message.time <= Time.time) { // send and eat wrap.ClientSend(new ArraySegment <byte>(message.bytes), Channels.Reliable); reliableClientToServer.RemoveAt(0); } // not enough time elapsed yet break; } // flush unreliable messages after latency while (unreliableClientToServer.Count > 0) { // check the first message time QueuedMessage message = unreliableClientToServer[0]; if (message.time <= Time.time) { // send and eat wrap.ClientSend(new ArraySegment <byte>(message.bytes), Channels.Unreliable); unreliableClientToServer.RemoveAt(0); } // not enough time elapsed yet break; } // update wrapped transport too wrap.ClientLateUpdate(); }
// helper function to simulate a send with latency/loss/scramble void SimulateSend(int connectionId, int channelId, ArraySegment <byte> segment, List <QueuedMessage> reliableQueue, List <QueuedMessage> unreliableQueue) { // segment is only valid after returning. copy it. // (allocates for now. it's only for testing anyway.) byte[] bytes = new byte[segment.Count]; Buffer.BlockCopy(segment.Array, segment.Offset, bytes, 0, segment.Count); // enqueue message. send after latency interval. QueuedMessage message = new QueuedMessage { connectionId = connectionId, bytes = bytes }; switch (channelId) { case Channels.DefaultReliable: // simulate latency & spikes message.timeToSend = Time.time + SimulateLatency(reliableLatency, reliableLatencySpikes); reliableQueue.Add(message); break; case Channels.DefaultUnreliable: // simulate packet loss bool drop = random.NextDouble() < unreliableLoss; if (!drop) { // simulate scramble (Random.Next is < max, so +1) // note that list entries are NOT ordered by time anymore // after inserting randomly. int last = unreliableQueue.Count; int index = unreliableScramble ? random.Next(0, last + 1) : last; // simulate latency & spikes message.timeToSend = Time.time + SimulateLatency(unreliableLatency, unreliableLatencySpikes); unreliableQueue.Insert(index, message); } break; default: Debug.LogError($"{nameof(LatencySimulation)} unexpected channelId: {channelId}"); break; } }
// helper function to simulate a send with latency/loss/scramble void SimulateSend(int connectionId, int channelId, ArraySegment <byte> segment, float latency, List <QueuedMessage> reliableQueue, List <QueuedMessage> unreliableQueue) { // segment is only valid after returning. copy it. // (allocates for now. it's only for testing anyway.) byte[] bytes = new byte[segment.Count]; Buffer.BlockCopy(segment.Array, segment.Offset, bytes, 0, segment.Count); // enqueue message. send after latency interval. QueuedMessage message = new QueuedMessage { connectionId = connectionId, bytes = bytes, time = Time.time + latency }; switch (channelId) { case Channels.Reliable: // simulate latency reliableQueue.Add(message); break; case Channels.Unreliable: // simulate packet loss bool drop = random.NextDouble() < unreliableLoss; if (!drop) { // simulate scramble (Random.Next is < max, so +1) bool scramble = random.NextDouble() < unreliableScramble; int last = unreliableQueue.Count; int index = scramble ? random.Next(0, last + 1) : last; // simulate latency unreliableQueue.Insert(index, message); } break; default: Debug.LogError($"{nameof(LatencySimulation)} unexpected channelId: {channelId}"); break; } }