LatencySimulation: one Queue for all channels to simplify code and support more channels later

This commit is contained in:
mischa 2024-06-11 16:23:38 +02:00
parent 9d0a72da9c
commit 993983036a

View File

@ -18,12 +18,14 @@ struct QueuedMessage
public int connectionId;
public byte[] bytes;
public double time;
public int channelId;
public QueuedMessage(int connectionId, byte[] bytes, double time)
public QueuedMessage(int connectionId, byte[] bytes, double time, int channelId)
{
this.connectionId = connectionId;
this.bytes = bytes;
this.time = time;
this.channelId = channelId;
}
}
@ -86,10 +88,8 @@ public ushort Port
// message queues
// list so we can insert randomly (scramble)
readonly List<QueuedMessage> reliableClientToServer = new List<QueuedMessage>();
readonly List<QueuedMessage> reliableServerToClient = new List<QueuedMessage>();
readonly List<QueuedMessage> unreliableClientToServer = new List<QueuedMessage>();
readonly List<QueuedMessage> unreliableServerToClient = new List<QueuedMessage>();
readonly List<QueuedMessage> clientToServer = new List<QueuedMessage>();
readonly List<QueuedMessage> serverToClient = new List<QueuedMessage>();
// random
// UnityEngine.Random.value is [0, 1] with both upper and lower bounds inclusive
@ -142,8 +142,7 @@ void SimulateSend(
ArraySegment<byte> segment,
int channelId,
float latency,
List<QueuedMessage> reliableQueue,
List<QueuedMessage> unreliableQueue)
List<QueuedMessage> messageQueue)
{
// segment is only valid after returning. copy it.
// (allocates for now. it's only for testing anyway.)
@ -156,30 +155,31 @@ void SimulateSend(
connectionId,
bytes,
#if !UNITY_2020_3_OR_NEWER
NetworkTime.localTime + latency
NetworkTime.localTime + latency,
#else
Time.unscaledTimeAsDouble + latency
Time.unscaledTimeAsDouble + latency,
#endif
channelId
);
switch (channelId)
{
case Channels.Reliable:
// simulate latency
reliableQueue.Add(message);
messageQueue.Add(message);
break;
case Channels.Unreliable:
// simulate packet loss
// simulate latency, drop, scramble
bool drop = random.NextDouble() < unreliableLoss/100;
if (!drop)
{
// simulate scramble (Random.Next is < max, so +1)
bool scramble = random.NextDouble() < unreliableScramble/100;
int last = unreliableQueue.Count;
int last = messageQueue.Count;
int index = scramble ? random.Next(0, last + 1) : last;
// simulate latency
unreliableQueue.Insert(index, message);
messageQueue.Insert(index, message);
}
break;
default:
@ -215,14 +215,13 @@ public override void ClientConnect(Uri uri)
public override void ClientDisconnect()
{
wrap.ClientDisconnect();
reliableClientToServer.Clear();
unreliableClientToServer.Clear();
clientToServer.Clear();
}
public override void ClientSend(ArraySegment<byte> segment, int channelId)
{
float latency = SimulateLatency(channelId);
SimulateSend(0, segment, channelId, latency, reliableClientToServer, unreliableClientToServer);
SimulateSend(0, segment, channelId, latency, clientToServer);
}
public override Uri ServerUri() => wrap.ServerUri();
@ -236,7 +235,7 @@ public override void ClientSend(ArraySegment<byte> segment, int channelId)
public override void ServerSend(int connectionId, ArraySegment<byte> segment, int channelId)
{
float latency = SimulateLatency(channelId);
SimulateSend(connectionId, segment, channelId, latency, reliableServerToClient, unreliableServerToClient);
SimulateSend(connectionId, segment, channelId, latency, serverToClient);
}
public override void ServerStart()
@ -252,20 +251,19 @@ public override void ServerStart()
public override void ServerStop()
{
wrap.ServerStop();
reliableServerToClient.Clear();
unreliableServerToClient.Clear();
serverToClient.Clear();
}
public override void ClientEarlyUpdate() => wrap.ClientEarlyUpdate();
public override void ServerEarlyUpdate() => wrap.ServerEarlyUpdate();
public override void ClientLateUpdate()
{
// flush reliable messages after latency.
// flush messages after latency.
// need to iterate all, since queue isn't a sortedlist.
for (int i = 0; i < reliableClientToServer.Count; ++i)
for (int i = 0; i < clientToServer.Count; ++i)
{
// message ready to be sent?
QueuedMessage message = reliableClientToServer[i];
QueuedMessage message = clientToServer[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
@ -273,27 +271,8 @@ public override void ClientLateUpdate()
#endif
{
// send and eat
wrap.ClientSend(new ArraySegment<byte>(message.bytes), Channels.Reliable);
reliableClientToServer.RemoveAt(i);
--i;
}
}
// flush unreliable messages after latency.
// need to iterate all, since queue isn't a sortedlist.
for (int i = 0; i < unreliableClientToServer.Count; ++i)
{
// message ready to be sent?
QueuedMessage message = unreliableClientToServer[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
if (message.time <= Time.unscaledTimeAsDouble)
#endif
{
// send and eat
wrap.ClientSend(new ArraySegment<byte>(message.bytes), Channels.Unreliable);
unreliableClientToServer.RemoveAt(i);
wrap.ClientSend(new ArraySegment<byte>(message.bytes), message.channelId);
clientToServer.RemoveAt(i);
--i;
}
}
@ -303,13 +282,12 @@ public override void ClientLateUpdate()
}
public override void ServerLateUpdate()
{
// flush reliable messages after latency.
// flush messages after latency.
// need to iterate all, since queue isn't a sortedlist.
for (int i = 0; i < reliableServerToClient.Count; ++i)
for (int i = 0; i < serverToClient.Count; ++i)
{
// message ready to be sent?
QueuedMessage message = reliableServerToClient[i];
QueuedMessage message = serverToClient[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
@ -317,28 +295,8 @@ public override void ServerLateUpdate()
#endif
{
// send and eat
wrap.ServerSend(message.connectionId, new ArraySegment<byte>(message.bytes), Channels.Reliable);
reliableServerToClient.RemoveAt(i);
--i;
}
}
// flush unreliable messages after latency.
// need to iterate all, since queue isn't a sortedlist.
for (int i = 0; i < unreliableServerToClient.Count; ++i)
{
// message ready to be sent?
QueuedMessage message = unreliableServerToClient[i];
#if !UNITY_2020_3_OR_NEWER
if (message.time <= NetworkTime.localTime)
#else
if (message.time <= Time.unscaledTimeAsDouble)
#endif
{
// send and eat
wrap.ServerSend(message.connectionId, new ArraySegment<byte>(message.bytes), Channels.Unreliable);
unreliableServerToClient.RemoveAt(i);
wrap.ServerSend(message.connectionId, new ArraySegment<byte>(message.bytes), message.channelId);
serverToClient.RemoveAt(i);
--i;
}
}