public static void Handle(Packet packet, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfUnion("ADDR", NetworkAddressMember.MEMBER_XBOXCLIENTADDRESS, new List<Tdf>
                {
                    new TdfStruct("VALU", new List<Tdf>
                    {
                        new TdfString("HOST", "373244-gosprapp357.ea.com"),
                        new TdfInteger("IP", 0),
                        new TdfInteger("PORT", 10041)
                    })
                }),
                new TdfInteger("SECU", 1),
                new TdfInteger("XDNS", 0)
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.REDIRECTOR,
                commandId = 0x1,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Notify(ulong clientId, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            var client = ClientManager.GetClient(clientId);
            var game = Database.GetGameByID(client.gameId);

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfInteger("GID", client.gameId),
                new TdfInteger("PID", client.persona.id),
                new TdfInteger("STAT", 4) // GameState.POST_GAME? // TODO: get enum for this, probably GameState or so
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x74,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfUnion addr = (TdfUnion)data["ADDR"];
            TdfStruct valu = (TdfStruct)addr.data.Find(tdf => tdf.label == "VALU");

            TdfStruct inip = (TdfStruct)valu.data.Find(tdf => tdf.label == "INIP");
            TdfInteger ip = (TdfInteger)inip.data.Find(tdf => tdf.label == "IP");
            TdfInteger port = (TdfInteger)inip.data.Find(tdf => tdf.label == "PORT");

            Log.Debug(string.Format("Updating internal network info for client {0}.", clientId));
            ClientManager.UpdateClientInternalNetworkData(clientId, ip.value, (ushort)port.value);

            TdfEncoder encoder = new TdfEncoder();

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.USERSESSIONS,
                commandId = 0x14,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfInteger gid = (TdfInteger)data["GID"];
            TdfList pcap = (TdfList)data["PCAP"];

            Database.UpdateGameCapacity(gid.value, pcap.list);

            TdfEncoder encoder = new TdfEncoder();

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x5,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);

            GameCapacityChangeNotification.Notify(gid.value, pcap.list, stream);
        }
        public static void Notify(ulong gameId, ulong personaId, PlayerRemovedReason reason, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfInteger("CNTX", 0),
                new TdfInteger("GID", gameId),
                new TdfInteger("PID", personaId),
                new TdfInteger("REAS", (ulong)reason)
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x28,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Notify(ulong gameId, ArrayList capacity, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfList("CAP", TdfBaseType.TDF_TYPE_INTEGER, capacity),
                new TdfInteger("GID", gameId),
                new TdfInteger("TCAP", 0)
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x6F,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(Packet packet, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfMap("CONF", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING, new Dictionary<object, object>
                {
                    { "Achievements", "ACH32_00,ACH33_00,ACH34_00,ACH35_00,ACH36_00,ACH37_00,ACH38_00,ACH39_00,ACH40_00,XPACH01_00,XPACH02_00,XPACH03_00,XPACH04_00,XPACH05_00,XP2ACH01_00,XP2ACH04_00,XP2ACH03_00,XP2ACH05_00,XP2ACH02_00,XP3ACH01_00,XP3ACH05_00,XP3ACH03_00,XP3ACH04_00,XP3ACH02_00,XP4ACH01_00,XP4ACH02_00,XP4ACH03_00,XP4ACH04_00,XP4ACH05_00,XP5ACH01_00,XP5ACH02_00,XP5ACH03_00,XP5ach04_00,XP5ach05_00" },
                    { "WinCodes", "r01_00,r05_00,r04_00,r03_00,r02_00,r10_00,r08_00,r07_00,r06_00,r09_00,r11_00,r12_00,r13_00,r14_00,r15_00,r16_00,r17_00,r18_00,r19_00,r20_00,r21_00,r22_00,r23_00,r24_00,r25_00,r26_00,r27_00,r28_00,r29_00,r30_00,r31_00,r32_00,r33_00,r35_00,r36_00,r37_00,r34_00,r38_00,r39_00,r40_00,r41_00,r42_00,r43_00,r44_00,r45_00,xp2rgm_00,xp2rntdmcq_00,xp2rtdmc_00,xp3rts_00,xp3rdom_00,xp3rnts_00,xp3rngm_00,xp4rndom_00,xp4rscav_00,xp4rnscv_00,xp4ramb1_00,xp4ramb2_00,xp5r502_00,xp5r501_00,xp5ras_00,xp5asw_00" }
                })
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.UTIL,
                commandId = 0x1,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            var client = ClientManager.GetClient(clientId);

            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfInteger gameId = (TdfInteger)data["GID"];
            TdfInteger personaId = (TdfInteger)data["PID"];
            TdfInteger reason = (TdfInteger)data["REAS"];

            // TODO: GameManager.RemovePlayer

            TdfEncoder encoder = new TdfEncoder();

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = packet.componentId,
                commandId = 0xB,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);

            // send a notification that a player has been removed
            PlayerRemovedNotification.Notify(gameId.value, personaId.value, (PlayerRemovedReason)reason.value, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            //TdfMap smap = new TdfMap("SMAP", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING);
            //smap.Map("cust", ""); // TODO: fetch from userSettingsSave 0x000B

            encoder.WriteTdf(new List<Tdf>
            {

            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.UTIL,
                commandId = 0xB,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfInteger gid = (TdfInteger)data["GID"];
            TdfInteger gsta = (TdfInteger)data["GSTA"];

            // update game state
            Database.UpdateGameState(gid.value, (GameState)gsta.value);

            Log.Info(string.Format("Advancing game state to {0} for game {1}.", (GameState)gsta.value, gid.value));

            TdfEncoder encoder = new TdfEncoder();

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = packet.componentId,
                commandId = 0x3,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);

            GameStateChangeNotification.Notify(gid.value, (GameState)gsta.value, stream);
        }
        public static void Handle(Packet packet, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.CLUBS,
                commandId = 0xA8C,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Notify(ulong clientId, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            var client = ClientManager.GetClient(clientId);
            var game = Database.GetGameByID(client.gameId);

            ArrayList statValues = new ArrayList();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfString("GRNM", "player_mpdefault2"),
                new TdfString("KEY", "No_Scope_Defined"),
                new TdfInteger("LAST", 1),
                new TdfStruct("STS", new List<Tdf>
                {
                    new TdfList("STAT", TdfBaseType.TDF_TYPE_STRUCT, new ArrayList
                    {
                        new List<Tdf>
                        {
                            new TdfInteger("EID", (ulong)client.entityIds[0]),
                            new TdfVector2("ETYP", 0x7802, 0x1),
                            new TdfInteger("POFF", 0),
                            new TdfList("STAT", TdfBaseType.TDF_TYPE_STRING, statValues)
                        }
                    })
                }),
                new TdfInteger("VID", client.viewId)
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.STATS,
                commandId = 0x32,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfString pnam = (TdfString)data["PNAM"];

            var client = ClientManager.GetClient(clientId);

            Log.Info(string.Format("User {0} logging in to persona {1}.", client.user.id, pnam.value));

            TdfEncoder encoder = new TdfEncoder();
            encoder.WriteTdf(new TdfInteger("BUID", client.persona.id));
            encoder.WriteTdf(new TdfInteger("FRST", 0));
            encoder.WriteTdf(new TdfString("KEY", "10c38a80_a223eb9d6c2c199db1885856a297055d"));
            encoder.WriteTdf(new TdfInteger("LLOG", Utilities.GetUnixTime()));
            encoder.WriteTdf(new TdfString("MAIL", client.user.mail));

            encoder.WriteTdf(new TdfStruct("PDTL", new List<Tdf>
            {
                new TdfString("DSNM", client.persona.name), // persona display name
                new TdfInteger("LAST", Utilities.GetUnixTime()), // time of last persona authentication
                new TdfInteger("PID", 0), // persona ID
                new TdfInteger("STAS", 2), // ACTIVE
                new TdfInteger("XREF", 0),
                new TdfInteger("XTYP", (ulong)ExternalRefType.BLAZE_EXTERNAL_REF_TYPE_UNKNOWN) // this is actually a TdfMin
            }));

            encoder.WriteTdf(new TdfInteger("UID", clientId)); // Blaze user ID

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.AUTHENTICATION,
                commandId = 0x6E,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfList targ = (TdfList)data["TARG"];
            List<Tdf> targData = (List<Tdf>)targ.list[0];
            TdfInteger stat = (TdfInteger)targData[2];

            TdfEncoder encoder = new TdfEncoder();
            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x1D,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);

            var client = ClientManager.GetClient(clientId);

            switch ((PlayerState)stat.value)
            {
                case PlayerState.DISCONNECTED:
                    // TODO: GameManager.RemovePlayer?
                    Log.Warn("*updateMeshConnection -> RemovePlayer*");
                    break;

                case PlayerState.CONNECTED:
                    GamePlayerStateChangeNotification.Notify(clientId, stream);
                    PlayerJoinCompletedNotification.Notify(client.gameId, client.persona.id, stream);
                    break;

                default:
                    Log.Warn("Unknown PlayerState in updateMeshCommand: " + stat.value);
                    break;
            }
        }
        public static void Handle(Packet packet, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            // set gamestate to VIRTUAL?

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0xF,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            var client = ClientManager.GetClient(clientId);

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfString("ADRS", "127.0.0.1"),
                new TdfInteger("ANON", 0),

                // telemetryDisable
                new TdfString("DISA", "AD,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AW,AX,AZ,BA,BB,BD,BF,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CC,CD,CF,CG,CI,CK,CL,CM,CN,CO,CR,CU,CV,CX,DJ,DM,DO,DZ,EC,EG,EH,ER,ET,FJ,FK,FM,FO,GA,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GS,GT,GU,GW,GY,HM,HN,HT,ID,IL,IM,IN,IO,IQ,IR,IS,JE,JM,JO,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LY,MA,MC,MD,ME,MG,MH,ML,MM,MN,MO,MP,MQ,MR,MS,MU,MV,MW,MY,MZ,NA,NC,NE,NF,NG,NI,NP,NR,NU,OM,PA,PE,PF,PG,PH,PK,PM,PN,PS,PW,PY,QA,RE,RS,RW,SA,SB,SC,SD,SG,SH,SJ,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TT,TV,TZ,UA,UG,UM,UY,UZ,VA,VC,VE,VG,VN,VU,WF,WS,YE,YT,ZM,ZW,ZZ"),
                new TdfString("FILT", ""),
                new TdfInteger("LOC", client.localization),

                // telemetryNoToggleOk
                new TdfString("NOOK", "US,CA,MX"),
                new TdfInteger("PORT", 9988),

                new TdfInteger("SDLY", 15000),
                new TdfString("SESS", "telemetry_session"),
                new TdfString("SKEY", "telemetry_key"),
                new TdfInteger("SPCT", 75),
                new TdfString("STIM", "Default")
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.UTIL,
                commandId = 0x5,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfMap attr = (TdfMap)data["ATTR"];
            TdfInteger gid = (TdfInteger)data["GID"];

            Log.Info(string.Format("Setting game attributes for game {0}.", gid.value));

            var game = Database.GetGameByID(gid.value);
            var attributes = game.attributes;

            foreach (var key in attr.map.Keys)
            {
                attributes[key] = attr.map[key];
            }

            Database.UpdateGameAttributes(gid.value, attributes);

            TdfEncoder encoder = new TdfEncoder();

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x7,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);

            GameAttribChangeNotification.Notify(gid.value, attr.map, stream);
        }
        public static void Notify(ulong gameId, Dictionary<object, object> attributes, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfMap("ATTR", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING, attributes),
                new TdfInteger("GID", gameId)
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x50,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Notify(ulong clientId, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            var client = ClientManager.GetClient(clientId);
            var game = Database.GetGameByID(client.gameId);

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfInteger("GID", (ulong)client.gameId),
                new TdfStruct("PDAT", new List<Tdf>
                {
                    new TdfInteger("EXID", 0),
                    new TdfInteger("GID", (ulong)client.gameId),
                    new TdfInteger("LOC", client.localization),
                    new TdfString("NAME", client.persona.name),
                    new TdfMap("PATT", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING, new Dictionary<object, object>
                    {
                        { "Premium", "False" }
                    }),
                    new TdfInteger("PID", client.persona.id),
                    new TdfUnion("PNET", NetworkAddressMember.MEMBER_IPPAIRADDRESS, new List<Tdf>
                    {
                        new TdfStruct("VALU", new List<Tdf>
                        {
                            new TdfStruct("EXIP", new List<Tdf>
                            {
                                new TdfInteger("IP", client.externalNetworkInfo.ip),
                                new TdfInteger("PORT", client.externalNetworkInfo.port)
                            }),
                            new TdfStruct("INIP", new List<Tdf>
                            {
                                new TdfInteger("IP", client.internalNetworkInfo.ip),
                                new TdfInteger("PORT", client.internalNetworkInfo.port)
                            })
                        })
                    }),
                    new TdfInteger("SID", 1), // TODO: check what the f**k is this...
                    new TdfInteger("SLOT", 0),
                    new TdfInteger("STAT", 2), // TODO: get enum for this, it's probably ACTIVE
                    new TdfInteger("TIDX", 65535),
                    new TdfInteger("TIME", 0), // TODO: time goes here?
                    new TdfVector3("UGID", 0, 0, 0),
                    new TdfInteger("UID", client.persona.id)
                })
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x19,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Notify(ulong clientId, SslStream stream)
        {
            TdfEncoder encoder = new TdfEncoder();

            var client = ClientManager.GetClient(clientId);
            var game = Database.GetGameByID(client.gameId);

            encoder.WriteTdf(new List<Tdf>
            {
               new TdfStruct("GAME", new List<Tdf>
                {
                    new TdfList("ADMN", TdfBaseType.TDF_TYPE_INTEGER, new ArrayList { client.persona.id }),
                    new TdfMap("ATTR", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING, game.attributes),
                    new TdfList("CAP", TdfBaseType.TDF_TYPE_INTEGER, game.capacity),
                    new TdfInteger("GID", (ulong)client.gameId),
                    new TdfString("GNAM", game.name),
                    new TdfInteger("GPVH", 666),
                    //new TdfInteger("GSET", game.gset),
                    new TdfInteger("GSID", 1),
                    new TdfInteger("GSTA", (ulong)game.state),
                    new TdfString("GTYP", "frostbite_multiplayer"),
                    new TdfList("HNET", TdfBaseType.TDF_TYPE_STRUCT, new ArrayList
                    {
                        new List<Tdf>
                        {
                            new TdfStruct("EXIP", new List<Tdf>
                            {
                                new TdfInteger("IP", game.externalNetworkInfo.ip),
                                new TdfInteger("PORT", game.externalNetworkInfo.port)
                            }),
                            new TdfStruct("INIP", new List<Tdf>
                            {
                                new TdfInteger("IP", game.internalNetworkInfo.ip),
                                new TdfInteger("PORT", game.internalNetworkInfo.port)
                            })
                        }
                    }, true),
                    new TdfInteger("HSES", 13666),
                    new TdfInteger("IGNO", 0),
                    new TdfInteger("MCAP", game.maxPlayers),
                    new TdfStruct("NQQS", new List<Tdf>
                    {
                        new TdfInteger("DBPS", 0),
                        new TdfInteger("NATT", 0), // TODO: get from DB
                        new TdfInteger("UBPS", 0)
                    }),
                    new TdfInteger("NRES", (ulong)game.notResetable),
                    new TdfInteger("NTOP", (ulong)game.networkTopology),
                    new TdfString("PGID", ""),
                    new TdfBlob("PGSR", new byte[] { }),
                    new TdfStruct("PHST", new List<Tdf>
                    {
                        new TdfInteger("HPID", client.persona.id),
                        new TdfInteger("HSLT", 1)
                    }),
                    new TdfInteger("PRES", (ulong)game.presenceMode),
                    new TdfString("PSAS", "ams"),
                    new TdfInteger("QCAP", (ulong)game.queueCapacity),
                    new TdfInteger("SEED", 2291),
                    new TdfInteger("TCAP", 0),
                    new TdfStruct("THST", new List<Tdf>
                    {
                        new TdfInteger("HPID", (ulong)client.gameId),
                        new TdfInteger("HSLT", 0)
                    }),
                    new TdfString("UUID", ""),
                    new TdfInteger("VOIP", (ulong)game.voipTopology),
                    new TdfString("VSTR", "67")
                }),
                new TdfList("PROS", TdfBaseType.TDF_TYPE_STRUCT, new ArrayList
                {
                    new List<Tdf>
                    {
                        new TdfBlob("BLOB", new byte[] { }),
                        new TdfInteger("EXID", 0),
                        new TdfInteger("GID", client.gameId),
                        new TdfInteger("LOC", client.localization),
                        new TdfString("NAME", client.persona.name),
                        new TdfMap("PATT", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING, new Dictionary<object, object>
                        {
                            { "Premium", "False" }
                        }),
                        new TdfInteger("PID", client.persona.id),
                        new TdfUnion("PNET", NetworkAddressMember.MEMBER_IPPAIRADDRESS, new List<Tdf>
                        {
                            new TdfStruct("VALU", new List<Tdf>
                            {
                                new TdfStruct("EXIP", new List<Tdf>
                                {
                                    new TdfInteger("IP", client.externalNetworkInfo.ip),
                                    new TdfInteger("PORT", client.externalNetworkInfo.port)
                                }),
                                new TdfStruct("INIP", new List<Tdf>
                                {
                                    new TdfInteger("IP", client.internalNetworkInfo.ip),
                                    new TdfInteger("PORT", client.internalNetworkInfo.port)
                                })
                            })
                        }),
                        new TdfInteger("SID", 1), // TODO: check what the f**k is this...
                        new TdfInteger("SLOT", 0),
                        new TdfInteger("STAT", 2), // TODO: get enum for this, it's probably ACTIVE
                        new TdfInteger("TIDX", 65535),
                        new TdfInteger("TIME", 0), // TODO: time goes here?
                        new TdfVector3("UGID", 0, 0, 0),
                        new TdfInteger("UID", client.persona.id)
                    }
                }),
                new TdfInteger("REAS", 0),
                new TdfStruct("VALU", new List<Tdf>
                {
                    new TdfInteger("DCTX", 3)
                })
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x16,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfInteger gid = (TdfInteger)data["GID"];
            TdfUnion pnet = (TdfUnion)data["PNET"];
            TdfStruct valu = (TdfStruct)pnet.data.Find(tdf => tdf.label == "VALU");

            TdfStruct exip = (TdfStruct)valu.data.Find(tdf => tdf.label == "EXIP");
            TdfInteger exipIP = (TdfInteger)exip.data.Find(tdf => tdf.label == "IP");
            TdfInteger exipPort = (TdfInteger)exip.data.Find(tdf => tdf.label == "PORT");

            TdfStruct inip = (TdfStruct)valu.data.Find(tdf => tdf.label == "INIP");
            TdfInteger inipIP = (TdfInteger)inip.data.Find(tdf => tdf.label == "IP");
            TdfInteger inipPort = (TdfInteger)inip.data.Find(tdf => tdf.label == "PORT");

            var client = ClientManager.GetClient(clientId);

            if (Database.GameExists(gid.value))
            {
                // update stuff
                ClientManager.UpdateClientInternalNetworkData(clientId, inipIP.value, (ushort)inipPort.value);
                ClientManager.UpdateClientExternalNetworkData(clientId, exipIP.value, (ushort)inipPort.value);
                ClientManager.UpdateClientGameID(clientId, (ulong)gid.value);

                Log.Info(string.Format("User {0} is joining game {1}.", client.user.id, gid.value));

                TdfEncoder encoder = new TdfEncoder();

                encoder.WriteTdf(new List<Tdf>
                {
                    new TdfInteger("GID", (ulong)gid.value),
                    new TdfInteger("JGS", 0)
                });

                byte[] payload = encoder.Encode();

                Utilities.SendPacket(new Packet
                {
                    componentId = Component.GAMEMANAGER,
                    commandId = 0x9,
                    errorCode = 0,
                    msgType = MessageType.REPLY,
                    msgNum = packet.msgNum,

                    payload = payload,
                    payloadSize = payload.Length
                }, stream);

                var game = Database.GetGameByID(gid.value);
                var gameClient = ClientManager.GetClient(game.clientId);

                // TODO: check if only userupdated needed
                UserAddedNotification.Notify(clientId, stream, true);
                UserUpdatedNotification.Notify(client.persona.id, stream);

                JoiningPlayerInitiateConnectionsNotification.Notify(clientId, stream);
                UserSessionExtendedDataUpdateNotification.Notify(clientId, stream, true);

                PlayerJoiningNotification.Notify(clientId, gameClient.stream);
                PlayerClaimingReservationNotification.Notify(clientId, gameClient.stream);
                UserSessionExtendedDataUpdateNotification.Notify(clientId, gameClient.stream, true);
            }
            else
            {
                Log.Warn(string.Format("User {0} wanted to a game that doesn't exist ({1}).", client.user.id, gid.value));

                /*
                 * not sure if we should set the error code to GAMEMANAGER_ERR_NO_DEDICATED_SERVER_FOUND (0x12D0004)
                 * or GAMEMANAGER_ERR_INVALID_GAME_ID (0x20004)
                 * */

                Utilities.SendPacket(new Packet
                {
                    componentId = Component.GAMEMANAGER,
                    commandId = 0x9,
                    errorCode = 0x20004, // GAMEMANAGER_ERR_INVALID_GAME_ID
                    msgType = MessageType.ERROR_REPLY,
                    msgNum = packet.msgNum,

                    payload = null,
                    payloadSize = 0
                }, stream);
            }
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfString auth = (TdfString)data["AUTH"];
            ClientManager.UpdateClientAuthToken(clientId, auth.value);

            TdfInteger pid = (TdfInteger)data["PID"];

            var user = Database.GetUser(pid.value);

            if (user.mail != null)
            {
                ClientManager.SetClientUser(clientId, user);
            }
            else
            {
                Log.Warn(string.Format("Could not find user by persona ID {0}.", pid.value));
            }

            Log.Info(string.Format("Performing silent login with persona {0} for user {1}.", pid.value, user.id));

            var persona = Database.GetPersona(pid.value);

            if (persona.name != null)
            {
                //Log.Info(string.Format("User {0} logging in to persona {1} with auth token {2}.", user.id, persona.name, auth.value));
                ClientManager.SetClientPersona(clientId, persona);
            }
            else
            {
                Log.Warn(string.Format("Could not find persona {0} for user {1}.", pid.value, user.id));
            }

            // not sure what is this type for
            //TdfInteger type = (TdfInteger)data.Find(tdf => tdf.label == "TYPE");

            var client = ClientManager.GetClient(clientId);

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfInteger("AGUP", 0),
                new TdfString("LDHT", ""),
                new TdfInteger("NTOS", 0),
                new TdfString("PCTK", "fa1a26c1-d934-422a-a6ba-ed92614f7d87"),
                new TdfString("PRIV", ""),
                new TdfStruct("SESS", new List<Tdf>
                {
                    new TdfInteger("BUID", client.persona.id),
                    new TdfInteger("FRST", 0),
                    new TdfString("KEY", "some_key"),
                    new TdfInteger("LLOG", Utilities.GetUnixTime()),
                    new TdfString("MAIL", client.user.mail), // TODO: get mail for client
                    new TdfStruct("PDTL", new List<Tdf>
                    {
                        new TdfString("DSNM", client.persona.name), // persona display name
                        new TdfInteger("LAST", Utilities.GetUnixTime()), // time of last persona authentication
                        new TdfInteger("PID", client.persona.id), // persona ID
                        new TdfInteger("STAS", 0), // should be ACTIVE(2)?
                        new TdfInteger("XREF", 0),
                        new TdfInteger("XTYP", (ulong)ExternalRefType.BLAZE_EXTERNAL_REF_TYPE_UNKNOWN) // this is actually a TdfMin
                    }),
                    new TdfInteger("UID", clientId)
                }),
                new TdfInteger("SPAM", 0),
                new TdfString("THST", ""),
                new TdfString("TSUI", ""),
                new TdfString("TURI", "")
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.AUTHENTICATION,
                commandId = 0x32,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            // decode payload
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            // read client type
            TdfStruct cdat = (TdfStruct)data["CDAT"];
            TdfInteger type = (TdfInteger)cdat.data.Find(tdf => tdf.label == "TYPE");
            TdfString svcn = (TdfString)cdat.data.Find(tdf => tdf.label == "SVCN");

            TdfStruct cinf = (TdfStruct)data["CINF"];
            TdfInteger loc = (TdfInteger)cinf.data.Find(tdf => tdf.label == "LOC");

            // set client type
            ClientManager.UpdateClientType(clientId, (ClientType)type.value);
            ClientManager.UpdateClientLocalization(clientId, loc.value);
            ClientManager.UpdateClientService(clientId, svcn.value);

            var client = ClientManager.GetClient(clientId);

            TdfList cids = new TdfList("CIDS", TdfBaseType.TDF_TYPE_INTEGER, new ArrayList
            {
                //1, 25, 4, 27, 28, 6, 7, 9, 10, 11, 30720, 30721, 30722, 30723, 20, 30725, 30726, 2000
            });
            cids.list.AddRange((new ulong[] { 1, 25, 4, 27, 28, 6, 7, 9, 10, 11, 30720, 30721, 30722, 30723, 20, 30725, 30726, 2000 }).ToArray());

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfInteger("ANON", 0),
                new TdfString("ASRC", "300294"),
                cids,
                new TdfString("CNGN", ""),
                new TdfStruct("CONF", new List<Tdf>
                {
                    new TdfMap("CONF", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING, new Dictionary<object, object>
                    {
                        { "connIdleTimeout", "90s" },
                        { "defaultRequestTimeout", "80s" },
                        { "pingPeriod", "20s" },
                        { "voipHeadsetUpdateRate", "1000" },
                        { "xlspConnectionIdleTimeout", "300" }
                    })
                }),
                new TdfString("INST", client.service),
                new TdfInteger("MINR", 0),
                new TdfString("NASP", "cem_ea_id"), // TODO: check if present in decoded data
                new TdfString("PILD", ""),
                new TdfString("PLAT", "pc"), // TODO: fetch from decoded data
                new TdfString("PTAG", ""),
                new TdfStruct("QOSS", new List<Tdf>
                {
                    // bandwidth ping site info
                    new TdfStruct("BWPS", new List<Tdf>
                    {
                        new TdfString("PSA", "127.0.0.1"), // ping site address
                        new TdfInteger("PSP", 17502), // ping site port
                        new TdfString("SNA", "ams") // ping site name
                    }),
                    new TdfInteger("LNP", 10), // number of latency probes
                    new TdfMap("LTPS", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRUCT, new Dictionary<object, object>
                    {
                        { "ams", new List<Tdf>
                            {
                                new TdfString("PSA", "127.0.0.1"), // ping site address
                                new TdfInteger("PSP", 17502), // ping site port
                                new TdfString("SNA", "ams") // ping site name
                            }
                        }
                    }),
                    new TdfInteger("SVID", 1161889797) // service ID
                }),
                new TdfString("RSRC", "300294"),
                new TdfString("SVER", "Blaze 3.15.08.0 (CL# 1060080)")
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.UTIL,
                commandId = 0x7,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);
            TdfString etag = (TdfString)data["ETAG"];

            bool onlineAccess = false;

            if (etag.value == "ONLINE_ACCESS")
            {
                onlineAccess = true;
            }

            var client = ClientManager.GetClient(clientId);

            TdfEncoder encoder = new TdfEncoder();

            if (onlineAccess == false)
            {
                TdfList nlst = new TdfList("NLST", TdfBaseType.TDF_TYPE_STRUCT, new ArrayList
                {
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2011-11-02T11:2Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1234632478),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "303566"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "DR:224766400"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "ONLINE_ACCESS"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 1),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2011-11-02T11:2Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1294632417),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "303566"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "303566"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "PROJECT10_CODE_CONSUMED_LE1"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 1),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2013-02-22T14:40Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 5674749135),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "306678"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "OFB-EAST:50401"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:PREMIUM_ACCESS"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2014-05-29T6:15Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1005150961807),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "305060"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "DR:235665900"),
                        new TdfInteger("STAT", 2),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "ONLINE_ACCESS"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 1),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2013-02-22T14:40Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1002134961807),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "305061"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "DR:235663400"),
                        new TdfInteger("STAT", 2),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "ONLINE_ACCESS"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 1),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2012-06-04T21:13Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1771457489),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "306678"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "OFB-EAST:50400"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:PREMIUM_ACCESS"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },

                    // DLC 1 - Back 2 Karkand
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2012-06-04T21:13Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1771457490),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "302777"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "OFB-EAST:50400"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:PC:B2K_PURCHASE"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },

                    // DLC 2
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2012-06-04T21:13Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1771457491),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "302776"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "OFB-EAST:48215"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:PC:XPACK2_PURCHASE"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },

                    // DLC 3
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2014-02-07T20:15Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1004743136441),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "302778"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "OFB-EAST:51080"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:PC:XPACK3_PURCHASE"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },

                    // DLC 4
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2012-11-26T9:4Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1000808118611),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "303129"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "OFB-EAST:55171"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:PC:XPACK4_PURCHASE"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },

                    // DLC 5
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2013-03-07T2:21Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1002246118611),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "306409"),
                        new TdfInteger("PRCA", 2),
                        new TdfString("PRID", "OFB-EAST:109546437"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:PC:XPACK5_PURCHASE"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    },

                    // COOP shortcut
                    new List<Tdf>
                    {
                        new TdfString("DEVI", ""),
                        new TdfString("GDAY", "2012-04-17T15:57Z"),
                        new TdfString("GNAM", "BF3PC"),
                        new TdfInteger("ID", 1684196754),
                        new TdfInteger("ISCO", 0),
                        new TdfInteger("PID", 0),
                        new TdfString("PJID", "306215"),
                        new TdfInteger("PRCA", 1),
                        new TdfString("PRID", "OFB-EAST:48642"),
                        new TdfInteger("STAT", 1),
                        new TdfInteger("STRC", 0),
                        new TdfString("TAG", "BF3:SHORTCUT:COOP"),
                        new TdfString("TDAY", ""),
                        new TdfInteger("TYPE", 5),
                        new TdfInteger("UCNT", 0),
                        new TdfInteger("VER", 0)
                    }
                });

                encoder.WriteTdf(new List<Tdf>
                {
                    nlst
                });
            }

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.AUTHENTICATION,
                commandId = 0x1D,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet)
        {
            var client = ClientManager.GetClient(clientId);

            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfMap attr = (TdfMap)data["ATTR"];
            TdfString gnam = (TdfString)data["GNAM"];
            TdfInteger gset = (TdfInteger)data["GSET"];
            TdfList pcap = (TdfList)data["PCAP"];
            TdfInteger igno = (TdfInteger)data["IGNO"];
            TdfInteger pmax = (TdfInteger)data["PMAX"];
            TdfInteger nres = (TdfInteger)data["NRES"];

            // network topology
            TdfInteger ntop = (TdfInteger)data["NTOP"];
            TdfInteger voip = (TdfInteger)data["VOIP"];

            TdfInteger pres = (TdfInteger)data["PRES"]; // TdfMin
            TdfInteger qcap = (TdfInteger)data["QCAP"];
            //TdfString uuid = (TdfString)data["UUID"];

            TdfList hnet = (TdfList)data["HNET"];

            TdfStruct exip = (TdfStruct)hnet.list[0];
            TdfInteger exipIP = (TdfInteger)exip.data.Find(tdf => tdf.label == "IP");
            TdfInteger exipPort = (TdfInteger)exip.data.Find(tdf => tdf.label == "PORT");

            TdfStruct inip = (TdfStruct)hnet.list[1];
            TdfInteger inipIP = (TdfInteger)inip.data.Find(tdf => tdf.label == "IP");
            TdfInteger inipPort = (TdfInteger)inip.data.Find(tdf => tdf.label == "PORT");

            // TODO: don't get gameId as result but get by clientId after creating the game
            /* ulong gameId = GameManager.CreateGame(

                (int)gset.value,
                (int)igno.value,
                (int)nres.value,
                (int)ntop.value,
                "714b05dc-93bc-49ac-961c-cb38b574f30a"
            ); */

            var level = attr.map["level"].ToString();
            var gametype = attr.map["levellocation"].ToString();

            var game = new Database.Game();
            game.clientId = clientId;
            game.name = gnam.value;
            game.attributes = attr.map;
            game.capacity = pcap.list;
            game.level = attr.map["level"].ToString();
            game.gametype = attr.map["levellocation"].ToString();
            game.maxPlayers = (ushort)pmax.value;
            game.notResetable = (byte)nres.value;
            game.queueCapacity = (ushort)qcap.value;
            game.presenceMode = (PresenceMode)pres.value;
            game.state = GameState.INITIALIZING;
            game.networkTopology = (GameNetworkTopology)ntop.value;
            game.voipTopology = (VoipTopology)voip.value;

            Database.NetworkInfo internalNetworkInfo = new Database.NetworkInfo();
            internalNetworkInfo.ip = inipIP.value;
            internalNetworkInfo.port = (ushort)inipPort.value;

            Database.NetworkInfo externalNetworkInfo = new Database.NetworkInfo();
            externalNetworkInfo.ip = exipIP.value;
            externalNetworkInfo.port = (ushort)exipPort.value;

            game.internalNetworkInfo = internalNetworkInfo;
            game.externalNetworkInfo = externalNetworkInfo;

            ulong gameId = Database.CreateGame(game);

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                // this one is tdfmin
                new TdfInteger("GID", (ulong)gameId)
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x1,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, client.stream);

            GameStateChangeNotification.Notify(gameId, game.state, client.stream);
            GameSetupNotification.Notify(clientId, gameId, client.stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfString mail = (TdfString)data["MAIL"];
            TdfString pass = (TdfString)data["PASS"];

            var client = ClientManager.GetClient(clientId);

            var user = Database.GetUser(mail.value, pass.value);

            if (user.id != 0)
            {
                Log.Info(string.Format("User {0} logging in with mail {1}.", user.id, user.mail));
            }
            else
            {
                Log.Error(string.Format("Could not find user for user {0}.", user.id));
            }

            ClientManager.SetClientUser(clientId, user);

            var persona = Database.GetPersona(user.personaId);

            if (persona.name != null)
            {
                Log.Debug(string.Format("Found persona '{0}' for user {1}.", persona.name, user.id));
            }
            else
            {
                Log.Error(string.Format("Could not find persona for user {0}.", user.id));
            }

            ClientManager.SetClientPersona(clientId, persona);

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfString("LDHT", ""),
                new TdfInteger("NTOS", 0),
                new TdfString("PCTK", "NnQWcHUvUoE4gBscrqJNMx6QzKKrVnnbaZBnD4ZY9kEzKg0cBlW0TrCWil1I8GokLs9p0h_stN5UvWYaS3IrQEK6qvjFwY59k6R_NYIKCp4"),
                new TdfList("PLST", TdfBaseType.TDF_TYPE_STRUCT, new ArrayList
                {
                    new List<Tdf>
                    {
                        new TdfString("DSNM", persona.name),
                        new TdfInteger("LAST", Utilities.GetUnixTime()),
                        new TdfInteger("PID", persona.id),
                        new TdfInteger("STAS", 2), // 'ACTIVE'
                        new TdfInteger("XREF", 0),
                        new TdfInteger("XTYP", (ulong)ExternalRefType.BLAZE_EXTERNAL_REF_TYPE_UNKNOWN)
                    }
                }),
                new TdfString("PRIV", ""),
                new TdfString("SKEY", "10c38a80_a223eb9d6c2c199db1885856a297055d"),
                new TdfInteger("SPAM", 1),
                new TdfString("THST", ""),
                new TdfString("TSUI", ""),
                new TdfString("TURI", ""),
                new TdfInteger("UID", clientId)
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.AUTHENTICATION,
                commandId = 0x28,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Notify(ulong clientId, ulong gameId, SslStream stream)
        {
            var client = ClientManager.GetClient(clientId);
            var game = Database.GetGameByID(gameId);

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new TdfStruct("GAME", new List<Tdf>
            {
                new TdfList("ADMN", TdfBaseType.TDF_TYPE_INTEGER, new ArrayList
                {
                    client.persona.id
                }),
                new TdfMap("ATTR", TdfBaseType.TDF_TYPE_STRING, TdfBaseType.TDF_TYPE_STRING, game.attributes),
                new TdfList("CAP", TdfBaseType.TDF_TYPE_INTEGER, game.capacity),
                // CRIT
                new TdfInteger("GID", game.id),
                new TdfString("GNAM", game.name),
                new TdfInteger("GPVH", 666),
                //new TdfInteger("GSET", game.gset),
                new TdfInteger("GSID", 1),
                new TdfInteger("GSTA", (ulong)game.state),
                new TdfString("GTYP", "frostbite_multiplayer"),
                new TdfList("HNET", TdfBaseType.TDF_TYPE_STRUCT, new ArrayList
                {
                    new List<Tdf>
                    {
                        new TdfStruct("EXIP", new List<Tdf>
                        {
                            new TdfInteger("IP", game.externalNetworkInfo.ip),
                            new TdfInteger("PORT", game.externalNetworkInfo.port)
                        }),
                        new TdfStruct("INIP", new List<Tdf>
                        {
                            new TdfInteger("IP", game.internalNetworkInfo.ip),
                            new TdfInteger("PORT", game.internalNetworkInfo.port)
                        })
                    }
                }, true),
                new TdfInteger("HSES", 13666),
                /* new TdfInteger("IGNO", game.igno), */
                new TdfInteger("MCAP", game.maxPlayers),
                new TdfInteger("NRES", game.notResetable),
                new TdfInteger("NTOP", (ulong)game.networkTopology),
                new TdfString("PGID", "b6852db1-ba37-4b40-aea3-0bd16efba4f9"),
                new TdfBlob("PGSR", new byte[] { }),
                new TdfStruct("PHST", new List<Tdf>
                {
                    new TdfInteger("HPID", client.persona.id),
                    new TdfInteger("HSLT", 1)
                }),
                new TdfInteger("PRES", (ulong)game.presenceMode),
                new TdfString("PSAS", "ams"),
                new TdfInteger("QCAP", (ulong)game.queueCapacity),
                new TdfUnion("REAS", NetworkAddressMember.MEMBER_XBOXCLIENTADDRESS, new List<Tdf> { }),
                new TdfStruct("VALU", new List<Tdf>
                {
                    new TdfInteger("DCTX", 0)
                }),
                new TdfInteger("SEED", 2291),
                new TdfInteger("TCAP", 0),
                new TdfStruct("THST", new List<Tdf>
                {
                    new TdfInteger("HPID", client.gameId),
                    new TdfInteger("HSLT", 0)
                }),
                //new TdfString("UUID", game.uuid),
                new TdfInteger("VOIP", (ulong)game.voipTopology),
                new TdfString("VSTR", "67")
            }));

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.GAMEMANAGER,
                commandId = 0x14,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            var client = ClientManager.GetClient(clientId);

            Log.Info(string.Format("Performing post-auth for user {0}.", client.user.id));

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfStruct("PSS", new List<Tdf>
                {
                    // address
                    new TdfString("ADRS", "127.0.0.1"),
                    new TdfBlob("CSIG", new byte[] { }),
                    //new TdfList("OIDS", 0), // offer IDs, probably a list of Vector3's
                    new TdfString("PJID", "123071"), // project ID
                    new TdfInteger("PORT", 8443), // port
                    new TdfInteger("RPRT", 9), // initial report types
                    new TdfInteger("TIID", 0) // title ID
                }),
                new TdfStruct("TELE", new List<Tdf>
                {
                    new TdfString("ADRS", "127.0.0.1"),
                    new TdfInteger("ANON", 0),

                    // telemetryDisable
                    new TdfString("DISA", "AD,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AW,AX,AZ,BA,BB,BD,BF,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CC,CD,CF,CG,CI,CK,CL,CM,CN,CO,CR,CU,CV,CX,DJ,DM,DO,DZ,EC,EG,EH,ER,ET,FJ,FK,FM,FO,GA,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GS,GT,GU,GW,GY,HM,HN,HT,ID,IL,IM,IN,IO,IQ,IR,IS,JE,JM,JO,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LY,MA,MC,MD,ME,MG,MH,ML,MM,MN,MO,MP,MQ,MR,MS,MU,MV,MW,MY,MZ,NA,NC,NE,NF,NG,NI,NP,NR,NU,OM,PA,PE,PF,PG,PH,PK,PM,PN,PS,PW,PY,QA,RE,RS,RW,SA,SB,SC,SD,SG,SH,SJ,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TT,TV,TZ,UA,UG,UM,UY,UZ,VA,VC,VE,VG,VN,VU,WF,WS,YE,YT,ZM,ZW,ZZ"),
                    new TdfString("FILT", ""),
                    new TdfInteger("LOC", client.localization),

                    // telemetryNoToggleOk
                    new TdfString("NOOK", "US,CA,MX"),
                    new TdfInteger("PORT", 9988),

                    new TdfInteger("SDLY", 15000),
                    new TdfString("SESS", "telemetry_session"),
                    new TdfString("SKEY", "telemetry_key"),
                    new TdfInteger("SPCT", 75),
                    new TdfString("STIM", "Default")
                }),
                new TdfStruct("TICK", new List<Tdf>
                {
                    new TdfString("ADRS", "127.0.0.1"),
                    new TdfInteger("PORT", 8999),
                    new TdfString("SKEY", string.Format("{0},127.0.0.1:8999,battlefield-3-pc,10,50,50,50,50,0,12", client.persona.id))
                }),
                new TdfStruct("UROP", new List<Tdf>
                {
                    new TdfInteger("TMOP", (ulong)TelemetryOpt.TELEMETRY_OPT_IN),
                    new TdfInteger("UID", client.persona.id)
                })
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.UTIL,
                commandId = 0x8,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Handle(ulong clientId, Packet packet, SslStream stream)
        {
            var client = ClientManager.GetClient(clientId);

            string player_awards = "player_awards";
            string player_awards2 = "player_awards2";
            string player_weapons1 = "player_weapons1";
            string player_statcategory = "player_statcategory";
            string player_core = "player_core";
            string coopplayer_coop = "coopplayer_coop";
            string player_reset = "player_reset";

            string[] catg = new string[1433];

            for (int j = 0; j < 993; j++)
                catg[j] = player_awards;
            for (int k = 993; k < 1166; k++)
                catg[k] = player_awards2;
            for (int l = 1166; l < 1296; l++)
                catg[l] = player_weapons1;
            for (int m = 1296; m < 1406; m++)
                catg[m] = player_statcategory;
            for (int n = 1406; n < 1427; n++)
                catg[n] = player_core;
            catg[1427] = coopplayer_coop;
            catg[1428] = player_core;
            catg[1429] = player_core;
            catg[1430] = player_core;
            catg[1431] = player_statcategory;
            catg[1432] = player_reset;

            TdfList stat = new TdfList("STAT", TdfBaseType.TDF_TYPE_STRUCT, new ArrayList { });

            for (int i = 0; i < 1433; i++)
            {
                stat.list.Add(new List<Tdf>
                {
                    new TdfString("CATG", catg[i]),
                    new TdfString("DFLT", "0.00"),
                    new TdfInteger("DRVD", 0x0),
                    new TdfString("FRMT", "%.2f"),
                    new TdfString("KIND", ""),
                    new TdfString("LDSC", ""),
                    new TdfString("META", ""),
                    new TdfString("NAME", Utilities.GetStatName(i)),
                    new TdfString("SDSC", ""),
                    new TdfInteger("TYPE", 0x1)
                });
            }

            Dictionary<string, Tdf> data = Utilities.DecodePayload(packet.payload);

            TdfEncoder encoder = new TdfEncoder();

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfString("CNAM", player_awards),
                new TdfString("DESC", "player_mpdefault2"), // TODO: fetch name from decoded data
                new TdfVector2("ETYP", 30722, 1),
                new TdfString("META", ""),
                new TdfString("NAME", "player_mpdefault2"),
                stat
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.STATS,
                commandId = 0x4,
                errorCode = 0,
                msgType = MessageType.REPLY,
                msgNum = packet.msgNum,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }
        public static void Notify(ulong clientId, SslStream stream, bool joining = false)
        {
            var client = ClientManager.GetClient(clientId);

            TdfEncoder encoder = new TdfEncoder();

            // TODO: check if this is correct
            ulong longid = client.persona.id;
            string pname = client.persona.name;

            if (client.type == ClientType.CLIENT_TYPE_GAMEPLAY_USER && joining)
            {
                longid = client.gameId;
                pname = "bf3-server-pc";

                //user.data.Add(new TdfBlob("EXBB", new byte[] { }));
            }

            encoder.WriteTdf(new List<Tdf>
            {
                new TdfStruct("DATA", new List<Tdf>
                {
                    new TdfUnion("ADDR", NetworkAddressMember.MEMBER_UNSET, new List<Tdf> { }),
                    new TdfString("BPS", ""),
                    new TdfString("CTY", ""),
                    new TdfMap("DMAP", TdfBaseType.TDF_TYPE_INTEGER, TdfBaseType.TDF_TYPE_INTEGER, new Dictionary<object, object>
                    {
                        { (ulong)0x70001, (ulong)55 },
                        { (ulong)0x70002, (ulong)707 }
                    }),
                    new TdfInteger("HWFG", 0),
                    new TdfStruct("QDAT", new List<Tdf>
                    {
                        new TdfInteger("DBPS", 0),
                        new TdfInteger("NATT", (ulong)NatType.NAT_TYPE_OPEN), // TdfMin
                        new TdfInteger("UBPS", 0)
                    }),

                    new TdfInteger("UATT", 0)
                    //new TdfList("ULST", 9)
                }),
                new TdfStruct("USER", new List<Tdf>
                {
                    new TdfInteger("AID", clientId),
                    new TdfInteger("ALOC", client.localization),
                    new TdfInteger("ID", longid),
                    new TdfString("NAME", pname)
                })
            });

            byte[] payload = encoder.Encode();

            Utilities.SendPacket(new Packet
            {
                componentId = Component.USERSESSIONS,
                commandId = 0x2,
                errorCode = 0,
                msgType = MessageType.NOTIFICATION,
                msgNum = 0,

                payload = payload,
                payloadSize = payload.Length
            }, stream);
        }