diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 7288978..93c651f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -9,4 +9,8 @@ - Fixed release build checks - Code restructured 1.1.1 - - Adjusted the Reliable Latency variable to 0.02f (was unsaved uploaded) \ No newline at end of file + - Adjusted the Reliable Latency variable to 0.02f (was unsaved uploaded) +1.2.0 + - Simulation code was restructured (Thanks to Punfish) + - Unreliable packets can be out of order no + - Fixed Latency is now stable \ No newline at end of file diff --git a/FishyLatency.cs b/FishyLatency.cs index 8c01052..e57e7ab 100644 --- a/FishyLatency.cs +++ b/FishyLatency.cs @@ -21,18 +21,31 @@ public class FishyLatency : Transport [Range(0, 1)] [SerializeField] float m_latency = 0f; + [Tooltip("How many % should be a packet loss")] + [Range(0, 1)] + [SerializeField] double m_packetloss = 0; + + [Header("Reliable")] [Tooltip("Additional amount of latency for reliable packets only when a packet get's lossed!")] [Range(0, 1)] - [SerializeField] float m_reliableLatency = 0.02f; + [SerializeField] float m_additionalLatency = 0.02f; - [Tooltip("How many % should be a packet loss")] + [Header("Unreliable")] + [Tooltip("How often in % should be a packet out of order")] [Range(0, 1)] - [SerializeField] double m_packetloss = 0; + [SerializeField] double m_outOfOrder = 0; #endregion #region Private - private List m_clientToServerMessages; - private List m_serverToClientMessages; + private Message? m_nextToServerReliable = null; + private Message? m_nextToServerUnreliable = null; + private List m_toServerReliablePackets; + private List m_toServerUnreliablePackets; + + private Message? m_nextToClientReliable = null; + private Message? m_nextToClientUnreliable = null; + private List m_toClientReliablePackets; + private List m_toClientUnreliablePackets; private struct Message { @@ -46,7 +59,7 @@ public Message(byte channelId, int connectionId, ArraySegment segment, flo { this.channelId = channelId; this.connectionId = connectionId; - this.time = Time.time + latency; + this.time = Time.unscaledTime + latency; this.length = segment.Count; this.message = ByteArrayPool.Retrieve(this.length); Buffer.BlockCopy(segment.Array, segment.Offset, this.message, 0, this.length); @@ -56,11 +69,6 @@ public ArraySegment GetSegment() { return new ArraySegment(message, 0, length); } - - public void AddLatency(float latency) - { - this.time += latency; - } } private readonly System.Random m_random = new System.Random(); @@ -70,9 +78,13 @@ public void AddLatency(float latency) public override void Initialize(NetworkManager networkManager) { m_transport.Initialize(networkManager); - m_clientToServerMessages = new List(); - m_serverToClientMessages = new List(); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + m_toServerReliablePackets = new List(); + m_toServerUnreliablePackets = new List(); + m_toClientReliablePackets = new List(); + m_toClientUnreliablePackets = new List(); +#endif m_transport.OnClientConnectionState += OnClientConnectionState; m_transport.OnServerConnectionState += OnServerConnectionState; m_transport.OnRemoteConnectionState += OnRemoteConnectionState; @@ -346,8 +358,10 @@ public override void Shutdown() m_transport.OnServerReceivedData -= OnServerReceivedData; #if UNITY_EDITOR || DEVELOPMENT_BUILD - m_clientToServerMessages.Clear(); - m_serverToClientMessages.Clear(); + m_toServerReliablePackets.Clear(); + m_toServerUnreliablePackets.Clear(); + m_toClientReliablePackets.Clear(); + m_toClientUnreliablePackets.Clear(); #endif //Stops client then server connections. @@ -387,66 +401,78 @@ public override int GetMTU(byte channel) private void Add(byte channelId, ArraySegment segment, bool server = false, int connectionId = 0) { + Channel c = (Channel)channelId; + List collection; + if (server) - m_serverToClientMessages.Add(new Message(channelId, connectionId, segment, m_latency)); + collection = (c == Channel.Reliable) ? m_toServerReliablePackets : m_toServerUnreliablePackets; else - m_clientToServerMessages.Add(new Message(channelId, connectionId, segment, m_latency)); - } - - private void Simulation(bool server) - { - if(server) + collection = (c == Channel.Reliable) ? m_toClientReliablePackets : m_toClientUnreliablePackets; + + float latency = m_latency; + //If dropping check to add extra latency if reliable, or discard if not. + if (CheckPacketLoss()) { - for (int i = 0; i < m_serverToClientMessages.Count; i++) + if (c == Channel.Reliable) { - if (CheckReliablePacketLoss(m_serverToClientMessages[i])) - break; - - if (m_serverToClientMessages[i].time <= Time.time) - { - m_transport.SendToClient(m_serverToClientMessages[i].channelId, m_serverToClientMessages[i].GetSegment(), m_serverToClientMessages[i].connectionId); - m_serverToClientMessages.RemoveAt(i); - } - } - } - else - { - for (int i = 0; i < m_clientToServerMessages.Count; i++) + latency += m_additionalLatency; //add extra for resend. + } + //If not reliable then return the segment array to pool. + else { - if (CheckReliablePacketLoss(m_clientToServerMessages[i])) - break; - - if (m_clientToServerMessages[i].time <= Time.time) - { - m_transport.SendToServer(m_clientToServerMessages[i].channelId, m_clientToServerMessages[i].GetSegment()); - m_clientToServerMessages.RemoveAt(i); - } + //ByteArrayPool.Store(segment.Array); + return; } } - m_transport.IterateOutgoing(server); + + Message msg = new Message(channelId, connectionId, segment, latency); + int cCount = collection.Count; + if (c == Channel.Unreliable && cCount > 0 && CheckOutOfOrder()) + collection.Insert(cCount - 1, msg); + else + collection.Add(msg); } - private bool CheckReliablePacketLoss(Message msg) + private void Simulation(bool server) { - if (CheckPacketLoss()) - { - if (msg.channelId == GetDefaultReliableChannel()) - { - msg.AddLatency(m_reliableLatency); - return false; - } - return true; - } - else + List collection; + + collection = (server) ? m_toServerReliablePackets : m_toClientReliablePackets; + IterateCollection(collection, server); + collection = (server) ? m_toServerUnreliablePackets : m_toClientUnreliablePackets; + IterateCollection(collection, server); + + m_transport.IterateOutgoing(server); + } + + private void IterateCollection(List c, bool server) + { + while (c.Count > 0) { - return false; + Message msg = c[0]; + //Not enough time has passed. + if (Time.unscaledTime < msg.time) + break; + + //Enough time has passed. + if(server) + m_transport.SendToClient(msg.channelId, msg.GetSegment(), msg.connectionId); + else + m_transport.SendToServer(msg.channelId, msg.GetSegment()); + + c.RemoveAt(0); } } private bool CheckPacketLoss() { return m_packetloss > 0 && m_random.NextDouble() < m_packetloss; - } + } + + private bool CheckOutOfOrder() + { + return m_outOfOrder > 0 && m_random.NextDouble() < m_outOfOrder; + } #endregion } } \ No newline at end of file diff --git a/VERSION.txt b/VERSION.txt index 8cfbc90..867e524 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -1.1.1 \ No newline at end of file +1.2.0 \ No newline at end of file