public void Handle(ByteArray data, Connection <T> connection) { if (connection.destroyed) { return; } if (data.Length < 12) { return; } int recvSendingID = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 0)); int recvPartID = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 4)); int recvLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 8)); //Always send an ACK back immediately NetworkMessage nm = NetworkMessage.Create(-5, 8, NetworkMessageType.UNORDERED_UNRELIABLE); Array.Copy(data.data, 0, nm.data.data, 0, 8); handler.SendMessageWithHighPriority(nm, connection); ReliableMessageReceiveTracking rmrt = null; if (receivingMessages.ContainsKey(recvSendingID)) { rmrt = receivingMessages[recvSendingID]; } //Received either a new chunk or a duplicate, if the messageID is higher than what we have received, it's new. if (rmrt == null) { if (recvSendingID > 0) { int distance = recvSendingID - unorderedReceiveID; //A message in the past (doesn't detect wrap around) bool fromThePast = distance <= 0; //A future message received before we have wrapped around bool massivelyInPast = -distance > (Int32.MaxValue / 4); //A past message received when we have wrapped around bool massivelyInFuture = distance > (Int32.MaxValue / 4); if (fromThePast && !massivelyInPast || massivelyInFuture) { return; } while (recvSendingID != unorderedReceiveID) { if (unorderedReceiveID == Int32.MaxValue) { unorderedReceiveID = 0; } unorderedReceiveID++; rmrt = ReliableMessageReceiveTracking.Create(); lock (receivingMessages) { receivingMessages.Add(unorderedReceiveID, rmrt); } } } else { int distance = -recvSendingID - orderedReceiveID; //A message in the past (doesn't detect wrap around) bool fromThePast = distance <= 0; //A future message received before we have wrapped around bool massivelyInPast = -distance > (Int32.MaxValue / 4); //A past message received when we have wrapped around bool massivelyInFuture = distance > (Int32.MaxValue / 4); if (fromThePast && !massivelyInPast || massivelyInFuture) { return; } while (-recvSendingID != orderedReceiveID) { if (orderedReceiveID == Int32.MaxValue) { orderedReceiveID = 0; } orderedReceiveID++; rmrt = ReliableMessageReceiveTracking.Create(); lock (receivingMessages) { receivingMessages.Add(-orderedReceiveID, rmrt); } } } rmrt = receivingMessages[recvSendingID]; } //Fist setup if needed if (rmrt.networkMessage == null) { if (recvSendingID > 0) { rmrt.Setup(recvLength, NetworkMessageType.UNORDERED_RELIABLE); } else { rmrt.Setup(recvLength, NetworkMessageType.ORDERED_RELIABLE); } } //Handle incoming data rmrt.Handle(recvPartID, recvLength, data); //We have all the parts if (rmrt.receivePartsLeft == 0) { if (recvSendingID > 0) { handler.Handle(rmrt.networkMessage, connection); } else { //This message is received in order if (-recvSendingID == orderedHandleID) { orderedHandleID++; if (orderedHandleID == Int32.MaxValue) { orderedHandleID = 0; } handler.Handle(rmrt.networkMessage, connection); } else { //This message is received out of order and we need to hold onto it orderedHandleMessages.Add(-recvSendingID, rmrt.networkMessage); } //If a message fills the missing hole this can play out. while (orderedHandleMessages.ContainsKey(orderedHandleID)) { NetworkMessage handleMessage = orderedHandleMessages[orderedHandleID]; orderedHandleMessages.Remove(orderedHandleID); handler.Handle(handleMessage, connection); orderedHandleID++; if (orderedHandleID == Int32.MaxValue) { orderedHandleID = 0; } } } rmrt.Destroy(); lock (receivingMessages) { receivingMessages.Remove(recvSendingID); } } }