Example #1
0
        public void SplitOutRoutedMessages(GameMessage gameMessage)
        {
            var controllerId = gameMessage.Data[0];
            var messageId    = gameMessage.Data[8];
            int offset       = 9;

            if (messageId == 8)   // Routed multiple
            {
                do
                {
                    bool has2ByteLen = (((gameMessage.Data[offset] & 0x80) >> 7) == 1);
                    int  length      = has2ByteLen ? gameMessage.Data[offset + 1] | (gameMessage.Data[offset] ^ 0x80) << 8 : gameMessage.Data[offset];
                    offset += has2ByteLen ? 2 : 1;

                    ushort reffId = BinaryPrimitives.ReadUInt16LittleEndian(gameMessage.Data.Slice(offset, 2));
                    offset += 2;

                    Span <byte> msgData  = null;
                    ulong       entityId = 0;

                    if (reffId == 0xFFFF)
                    {
                        entityId = BinaryPrimitives.ReadUInt64LittleEndian(gameMessage.Data.Slice(offset, 8));
                        offset  += 8;
                        msgData  = gameMessage.Data.Slice(offset, length - 10).ToArray(); // minus 10 for the length of the reff id and the entityId
                        offset  += msgData.Length;

                        // Check if the message is a ref id assign
                        if (msgData[0] == 9)
                        {
                            var reffIdToAssign = BinaryPrimitives.ReadUInt16LittleEndian(msgData.Slice(1, 2));

                            if (ReffIdLookup.ContainsKey(reffIdToAssign))
                            {
                                if (ReffIdLookup[reffIdToAssign] != entityId)
                                {
                                    Console.WriteLine($"ReffId ({reffIdToAssign}) already in look up for EntityId: {ReffIdLookup[reffIdToAssign]}, reassigning to {entityId}");
                                }

                                ReffIdLookup[reffIdToAssign] = entityId;
                            }
                            else
                            {
                                if (ReffIdLookup.TryAdd(reffIdToAssign, entityId))
                                {
                                    Console.WriteLine($"[Error] Couldn't add ReffId {reffIdToAssign} to EntityId {entityId}");
                                }
                            }
                        }
                    }
                    else
                    {
                        msgData = gameMessage.Data.Slice(offset, length - 2).ToArray();  // minus 2 for the reff id
                        offset += msgData.Length;

                        // Try and get the entity id for this from the reff id
                        if (ReffIdLookup.TryGetValue(reffId, out var entId))
                        {
                            entityId = entId;
                        }
                        else
                        {
                            Console.WriteLine($"Couldn't find EntityId in lookup for: {reffId}");
                        }
                    }

                    var subMessage = new SubMessage(Messages.Count, gameMessage, msgData, entityId);
                    Messages.Add(subMessage);
                } while (offset < gameMessage.Data.Length);
            }
        }
Example #2
0
        public void Reassemble(bool verboseLog)
        {
            Packets  = new List <Packet>();
            Messages = new List <Message>();

            foreach (Datagram datagram in Datagrams)
            {
                if (datagram.Server == Server.Matrix)
                {
                    Packets.Add(new MatrixPacket(Packets.Count, datagram));
                }
                else
                {
                    int         consumed = 0;
                    Span <byte> data     = datagram.Data;

                    while (consumed < data.Length)
                    {
                        GamePacket packet = new GamePacket(Packets.Count, datagram, consumed);
                        Packets.Add(packet);
                        consumed += packet.Length;
                    }
                }
            }

            //SequenceStart = SwapBytes(SequenceStart); // was the wrong endianness in the old fileformat, fixed now
            ReliableGamePacketInputQueue    sMatrix  = new ReliableGamePacketInputQueue(SequenceStart);
            ReliableGamePacketInputQueue    sGSS     = new ReliableGamePacketInputQueue(SequenceStart);
            ReliableGamePacketInputQueue    cMatrix  = new ReliableGamePacketInputQueue(SequenceStart);
            ReliableGamePacketInputQueue    cGSS     = new ReliableGamePacketInputQueue(SequenceStart);
            List <GamePacket>               sMBuffer = new List <GamePacket>();
            List <GamePacket>               sGBuffer = new List <GamePacket>();
            List <GamePacket>               cMBuffer = new List <GamePacket>();
            List <GamePacket>               cGBuffer = new List <GamePacket>();
            Dictionary <ushort, GamePacket> sMAck    = new Dictionary <ushort, GamePacket>();
            Dictionary <ushort, GamePacket> cMAck    = new Dictionary <ushort, GamePacket>();
            Dictionary <ushort, GamePacket> sGAck    = new Dictionary <ushort, GamePacket>();
            Dictionary <ushort, GamePacket> cGAck    = new Dictionary <ushort, GamePacket>();

            foreach (Packet packet in Packets)
            {
                if (packet.Server == Server.Matrix)
                {
                    Messages.Add(new MatrixMessage(Messages.Count, packet as MatrixPacket));
                    continue;
                }

                GamePacket gPacket = packet as GamePacket;

                Dictionary <ushort, GamePacket> needsAck = null;
                ReliableGamePacketInputQueue    queue    = null;
                List <GamePacket> buffer = null;

                switch (gPacket.Channel)
                {
                case Channel.Control:
                    ControlMessage.MessageType type = ControlMessage.GetMessageType(packet.Data);
                    if (type == ControlMessage.MessageType.MatrixAck)
                    {
                        needsAck = packet.FromServer ? cMAck : sMAck;
                    }
                    else if (type == ControlMessage.MessageType.GSSAck)
                    {
                        needsAck = packet.FromServer ? cGAck : sGAck;
                    }

                    if (needsAck == null)
                    {
                        Messages.Add(new GameMessage(Messages.Count, gPacket));
                        break;
                    }

                    ushort ackFor = ControlMessage.GetAckFor(gPacket.Data);

                    if (needsAck.ContainsKey(ackFor))
                    {
                        needsAck[ackFor].AckPacket = gPacket;
                        gPacket.AckPacket          = needsAck[ackFor];
                        needsAck.Remove(ackFor);
                        Messages.Add(new GameMessage(Messages.Count, gPacket));
                    }
                    else
                    {
                        if (verboseLog)
                        {
                            Console.WriteLine("Duplicate " + type + ", seq: " + ackFor + " - " + (gPacket.FromServer ? "Server -> Client" : "Client -> Server"));
                        }
                    }

                    break;

                case Channel.UnreliableGss:
                    var message = new GameMessage(Messages.Count, gPacket);
                    Messages.Add(message);
                    SplitOutRoutedMessages(message);
                    break;

                case Channel.Matrix:
                    queue    = (gPacket.FromServer ? sMatrix : cMatrix);
                    buffer   = (gPacket.FromServer ? sMBuffer : cMBuffer);
                    needsAck = packet.FromServer ? sMAck : cMAck;
                    break;

                case Channel.ReliableGss:
                    queue    = (gPacket.FromServer ? sGSS : cGSS);
                    buffer   = (gPacket.FromServer ? sGBuffer : cGBuffer);
                    needsAck = packet.FromServer ? sGAck : cGAck;
                    break;
                }

                if (queue == null)
                {
                    continue;
                }


                ReliableGamePacketInputQueue.EnqueueResult result = queue.Enqueue(gPacket);

                if (result == ReliableGamePacketInputQueue.EnqueueResult.Ok)
                {
                    needsAck.Add(gPacket.SequenceNumber, gPacket);
                }
                else
                {
                    if (verboseLog)
                    {
                        Console.WriteLine(result + " packet, seq: " + gPacket.SequenceNumber + ", channel: " + gPacket.Channel + " - " + (gPacket.FromServer ? "Server -> Client" : "Client -> Server"));
                    }
                }

                GamePacket qPacket;
                while (queue.TryDequeue(out qPacket))
                {
                    buffer.Add(qPacket);

                    if (!qPacket.IsSplit)
                    {
                        if (buffer.Count > 1)
                        {
                            if (verboseLog)
                            {
                                StringBuilder sb = new StringBuilder();
                                sb.Append("Reassembled split packet, seq: ");
                                sb.Append(buffer[0].SequenceNumber);
                                sb.Append("->");
                                sb.Append(buffer[buffer.Count - 1].SequenceNumber);
                                sb.Append(", channel ");
                                sb.Append(qPacket.Channel);
                                sb.Append(" - ");
                                sb.Append((qPacket.FromServer ? "Server -> Client" : "Client -> Server"));

                                Console.WriteLine(sb.ToString());
                            }
                        }

                        Messages.Add(new GameMessage(Messages.Count, buffer.ToArray()));
                        buffer.Clear();
                    }
                }
            }
        }