public override void Handle(BinaryReader reader, LuClient client)
        {
            var objectId = reader.ReadInt64();
            //var flags = "";
            //reader.BaseStream.Position = reader.BaseStream.Position - 4;
            //for (uint k = 0; k < 4; k++)
            //{
            //    var flag = reader.ReadBoolean();
            //    if (flag)
            //    {
            //        flags += $"[{k}]";
            //    }
            //}

            var messageId = reader.ReadUInt16();

            if (!_handlers.ContainsKey(messageId))
            {
                Console.WriteLine($"Received unhandled client game message. ObjectId = \"{objectId}\", MessageId = \"{messageId}\"");
                if (LuServer.LogUnknownPackets)
                {
                    reader.BaseStream.Position = 0;
                    var bytes = ReadFully(reader.BaseStream);
                    File.WriteAllBytes("Packets/Game Messages/" + objectId + "_" + messageId + ".bin", bytes);
                }
            }
            else
            {
                _handlers[messageId].Handle(objectId, reader);
            }
        }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                if (!client.Authenticated) return;

                var id = reader.ReadInt64(); // The object id of the characte
                Console.WriteLine(id);

                var character = database.GetCharacter(id, true); // Retrieve the character from the database

                Console.WriteLine($"{client.Username} requested to delete their character {character.Name}.");

                using (var bitStream = new WBitStream()) // Create the new bitstream
                {
                    bitStream.WriteHeader(RemoteConnection.Client, (uint) MsgClientDeleteCharacterResponse);
                        // Always write the packet header!
                    if (!string.Equals(character.Owner, client.Username,
                        StringComparison.CurrentCultureIgnoreCase)) // You can't delete someone else's character!
                    {
                        bitStream.Write((byte) 0x02); // Maybe that's the fail code?
                        Console.WriteLine("Failed: Can't delete someone else's character!");
                    }
                    else // Good to go, that's their character, they can delete it if they want.
                    {
                        database.DeleteCharacter(character); // Remove the character from the Redis database
                        bitStream.Write((byte) 0x01); // Success code
                        Console.WriteLine("Successfully deleted character.");
                    }

                    // Send the packet
                    WorldServer.Server.Send(bitStream, SystemPriority, ReliableOrdered, 0, client.Address, false);
                }
            }
        }
 public override void Handle(BinaryReader reader, LuClient client)
 {
     var subPacketLength = reader.ReadUInt32();
     var remoteConnection = (PacketEnums.RemoteConnection) reader.ReadUInt16();
     var packetId = reader.ReadUInt32();
     reader.ReadByte();
     Console.WriteLine($"Received route packet. Length = {subPacketLength}, RemoteConnection = {remoteConnection}, PacketId = {packetId.ToString("X")}");
 }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                // Read packet
                var objectId = reader.ReadInt64();
                var newName = reader.ReadWString(66);

                // Gather info
                var account = database.GetAccount(client.Username);
                var character = database.GetCharacter(objectId, true);

                Console.WriteLine(
                    $"Got character rename request from {client.Username}. Old name: {character.Name}. New name: {newName}");

                using (var bitStream = new WBitStream()) // Create packet
                {
                    // Always write packet header
                    bitStream.WriteHeader(RemoteConnection.Client, (uint) MsgClientCharacterRenameResponse);

                    // Make sure they own the accounta
                    if (
                        !string.Equals(account.Username, character.Name,
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        Console.WriteLine("Failed to rename character: You can't rename someone else!");
                        bitStream.Write((byte) 0x01); // Fail code
                    }
                    else if (database.CharacterExists(newName)) // Make sure nobody already has that name
                    {
                        bitStream.Write((byte) 0x03); // Code for username taken
                        Console.WriteLine("Failed to rename character: Name already taken.");
                    }
                    else // Good to go!
                    {
                        try
                        {
                            character.Name = newName; // Set their new name
                            database.UpdateCharacter(character); // Update the character
                            bitStream.Write((byte) 0x00); // Success code, everything worked just fine.
                            Console.WriteLine("Successfully renamed character!");
                        }
                        catch (Exception exception)
                        {
                            Console.WriteLine($"Error while trying to rename user - {exception}");
                            bitStream.Write(0x01); // Some error?
                        }
                    }

                    // Send the packet
                    WorldServer.Server.Send(bitStream, WPacketPriority.SystemPriority,
                        WPacketReliability.ReliableOrdered, 0, client.Address, false);
                }
            }
        }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                if (!client.Authenticated) return; // Make sure they've authenticated first!

                // Retrieve their account
                var account = database.GetAccount(client.Username);
                // Call the C++ code that generates and sends the character list packet of the specified account
                WorldPackets.SendCharacterListResponse(client.Address, account, WorldServer.Server);

                Console.WriteLine($"Sent character list packet to {client.Username}. Users: " +
                                  JsonConvert.SerializeObject(account.Characters));
            }
        }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                var username = reader.ReadWString(66); // Read the username
                reader.BaseStream.Position = 74; // Set the position to 74, to get the user key.
                var userKey = reader.ReadWString(66); // Read the user key

                Console.WriteLine($"Got client validation request. Username: {username}, User Key: {userKey}.");

                // Set the user to authenticated
                client.Authenticated = true;
                client.Username = username;
                // TODO: Verify user key (Maybe it should expire, instead of just being stored? Otherwise, I'd just cache it.)

                // commented to try and make world single-server

                //if (!client.OutOfChar) return;

                //var account = database.GetAccount(client.Username);
                //client.Character = account.SelectedCharacter; // Store the selected character

                //var character = database.GetCharacter(client.Character);

                //using (var bitStream = new WBitStream()) // Create the zone load packet
                //{
                //    bitStream.WriteHeader(RemoteConnection.Client, (uint) MsgClientLoadStaticZone);
                //    // Always write the header.

                //    bitStream.Write(character.ZoneId); // Write the zone id
                //    bitStream.Write(character.MapInstance); // Write the map instance
                //    bitStream.Write(character.MapClone); // Write the map clone
                //    for (var i = 0; i < 4; i++)
                //        bitStream.Write(ZoneChecksums.Checksums[(ZoneId) character.ZoneId][i]); // Write the checksum
                //    bitStream.Write((ushort) 0); // ???
                //    for (var i = 0; i < 3; i++) bitStream.Write(character.Position[i]); // Write the position
                //    bitStream.Write((uint) 0); // Supposed to be 4, if in battle...

                //    // Send the packet
                //    WorldServer.Server.Send(bitStream, WPacketPriority.SystemPriority,
                //        WPacketReliability.ReliableOrdered, 0, client.Address, false);

                //    Console.WriteLine(
                //        $"Sent world info to client - ZoneId = {character.ZoneId}, Map Instance = {character.MapInstance}, Map Clone = {character.MapClone}");
                //}
            }
        }
 protected override void OnConnect(string address)
 {
     Clients[address] = new LuClient(address);
     Console.WriteLine("Client of IP {0} joined.", address);
 }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                if (!client.Authenticated) return;

                var zone = (ZoneId) reader.ReadUInt16();
                var instance = reader.ReadUInt16();
                var clone = reader.ReadInt32();

                Console.WriteLine(
                    $"Got clientside level load complete packet from {client.Username}. Zone: {zone}, Instance: {instance}, Clone: {clone}.");

                var account = database.GetAccount(client.Username);
                var character = database.GetCharacter(account.SelectedCharacter);

                using (var bitStream = new WBitStream())
                {
                    bitStream.WriteHeader(RemoteConnection.Client, (uint) MsgClientCreateCharacter);

                    using (var ldf = new Ldf())
                    {
                        // TODO: Improve LDF code here
                        ldf.WriteS64("accountID", account.Id);
                        ldf.WriteS32("chatmode", 0);
                        ldf.WriteBool("editor_enabled", false);
                        ldf.WriteS32("editor_level", 0);
                        ldf.WriteBool("freetrial", false);
                        ldf.WriteS32("gmlevel", character.GmLevel);
                        ldf.WriteBool("legoclub", true);
                        var levelid = character.ZoneId + (((long) character.MapInstance) << 16) +
                                      (((long) character.MapClone) << 32);
                        ldf.WriteS64("levelid", levelid);
                        ldf.WriteWString("name", character.Name);
                        ldf.WriteId("objid", Character.GetObjectId(character));
                        ldf.WriteFloat("position.x", character.Position[0]);
                        ldf.WriteFloat("position.y", character.Position[1]);
                        ldf.WriteFloat("position.z", character.Position[2]);
                        ldf.WriteS64("reputation", character.Reputation);
                        ldf.WriteS32("template", 1);
                        using (var xmlData = GenXmlData(character)) ldf.WriteBytes("xmlData", xmlData);

                        bitStream.Write(ldf.GetSize() + 1);
                        bitStream.Write((byte) 0);
                        ldf.WriteToPacket(bitStream);
                        WorldServer.Server.Send(bitStream, WPacketPriority.SystemPriority,
                            WPacketReliability.ReliableOrdered, 0, client.Address, false);
                        File.WriteAllBytes("Temp/" + character.Name + ".world_2a.bin", bitStream.GetBytes());
                    }
                }

                WorldServer.Server.SendGameMessage(client.Address, Character.GetObjectId(character), 1642);
                WorldServer.Server.SendGameMessage(client.Address, Character.GetObjectId(character), 509);
                using (var gameMessage = LuServer.CreateGameMessage(Character.GetObjectId(character), 472))
                {
                    gameMessage.Write((uint) 185);
                    gameMessage.Write((byte) 0);
                    WorldServer.Server.Send(gameMessage, WPacketPriority.SystemPriority,
                        WPacketReliability.ReliableOrdered, 0, client.Address, false);
                }

                var playerObject = new PlayerObject(Character.GetObjectId(character), character.Name);
                playerObject.Construct(WorldServer.Server, client.Address);
            }
        }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                var loginRequest = new LoginRequest(reader);
                WriteLine($"{loginRequest.Username} sent authentication request.");

                byte valid = 0x01;
                if (!database.AccountExists(loginRequest.Username))
                {
                    valid = 0x06;
                }

                if (valid == 0x01)
                {
                    var account = database.GetAccount(loginRequest.Username);
                    var hash =
                        SHA512.Create()
                            .ComputeHash(Encoding.Unicode.GetBytes(loginRequest.Password).Concat(account.Salt).ToArray());
                    if (!account.Password.SequenceEqual(hash)) valid = 0x06;
                    if (valid == 0x01 && account.Banned) valid = 0x02;
                }

                var message = "screwed up.";
                switch (valid)
                {
                    case 0x01:
                        message = "was successful.";
                        break;
                    case 0x06:
                        message = "failed: invalid credentials.";
                        break;
                    case 0x02:
                        message = "failed: banned.";
                        break;
                    default:
                        WriteLine(
                            "FATAL: Magically, the valid variable was not 0x01, 0x06, or 0x02! (How is that even possible..? I'm only checking because resharper is making me.)");
                        break;
                }

                WriteLine("User login " + message);

                if (valid == 0x01)
                {
                    // TODO: Store user key
                }

                // Use C++ auth for now (I hope to eliminate this sometime)
                SendLoginResponse(client.Address, valid, RandomString(66), AuthServer.Server);
                // C# auth, not working atm
/*
            using (var bitStream = new WBitStream())
            {
                bitStream.WriteHeader(PacketEnums.RemoteConnection.Client, 0);

                bitStream.Write(valid);
                bitStream.WriteString("Talk_Like_A_Pirate", 33);
                for (var i = 0; i < 7; i++)
                {
                    bitStream.WriteString("_", 0, 33);
                }
                // client version
                bitStream.Write((ushort)1);
                bitStream.Write((ushort)10);
                bitStream.Write((ushort)64);
                //bitStream.WriteWString(RandomString(32), false, true); // user key
                bitStream.WriteString(RandomString(66), 66, 66);
                bitStream.WriteString("localhost", 33); // redirect ip
                bitStream.WriteString("localhost", 33); // chat ip
                bitStream.Write((ushort)2006); // redirect port
                bitStream.Write((ushort)2003); // chat port
                bitStream.WriteString("localhost", 33); // another ip
                bitStream.WriteString("00000000-0000-0000-0000-000000000000",  37); // possible guid
                bitStream.Write((ushort)0); // zero short

                // localization
                bitStream.Write((byte)0x55);
                bitStream.Write((byte)0x53);
                bitStream.Write((byte)0x00);

                bitStream.Write((byte)0); // first login subscription
                bitStream.Write((byte)0); // subscribed
                bitStream.Write((ulong)0); // zero long
                bitStream.Write((ushort)0); // error message length
                bitStream.WriteString("T", 0, 1); // error message
                bitStream.Write((ushort)324); // extra data length

                CreateExtraPacketData(0, 0, 2803442767, bitStream);
                CreateExtraPacketData(7, 37381, 2803442767, bitStream);
                CreateExtraPacketData(8, 6, 2803442767, bitStream);
                CreateExtraPacketData(9, 0, 2803442767, bitStream);
                CreateExtraPacketData(10, 0, 2803442767, bitStream);
                CreateExtraPacketData(11, 1, 2803442767, bitStream);
                CreateExtraPacketData(14, 1, 2803442767, bitStream);
                CreateExtraPacketData(15, 0, 2803442767, bitStream);
                CreateExtraPacketData(17, 1, 2803442767, bitStream);
                CreateExtraPacketData(5, 0, 2803442767, bitStream);
                CreateExtraPacketData(6, 1, 2803442767, bitStream);
                CreateExtraPacketData(20, 1, 2803442767, bitStream);
                CreateExtraPacketData(19, 30854, 2803442767, bitStream);
                CreateExtraPacketData(21, 0, 2803442767, bitStream);
                CreateExtraPacketData(22, 0, 2803442767, bitStream);
                CreateExtraPacketData(23, 4114, 2803442767, bitStream);
                CreateExtraPacketData(27, 4114, 2803442767, bitStream);
                CreateExtraPacketData(28, 1, 2803442767, bitStream);
                CreateExtraPacketData(29, 0, 2803442767, bitStream);
                CreateExtraPacketData(30, 30854, 2803442767, bitStream);

                File.WriteAllBytes("Temp/loginresponse.bin", bitStream.GetBytes());

                LuServer.CurrentServer.Send(bitStream, WPacketPriority.SystemPriority,
                    WPacketReliability.ReliableOrdered, 0, client.Address, false); // Send the packet.
            }
*/
            }
        }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                var objectId = reader.ReadInt64(); // Read the object ID.
                Console.WriteLine("Received Login Request from {0} - ObjectID = {1}", client.Address, objectId);

                var account = database.GetAccount(client.Username); // Get the account.
                var character = database.GetCharacter(objectId, true);

                if (!string.Equals(character.Owner, account.Username, StringComparison.CurrentCultureIgnoreCase))
                    // Make sure they selected their own character
                {
                    Console.WriteLine("USER {0} SENT OBJECT ID THAT IS NOT ONE OF THEIR CHARACTER'S!!!", client.Username);
                    // TODO: Kick user
                    return;
                }

                account.SelectedCharacter = character.Name;
                database.UpdateAccount(account);

                client.OutOfChar = true;

                Console.WriteLine("User has selected character {0}. Sending them to zone {1}.", character.Name,
                    character.ZoneId);

                using (var bitStream = new WBitStream()) // Create the zone load packet
                {
                    bitStream.WriteHeader(RemoteConnection.Client, (uint)MsgClientLoadStaticZone);
                    // Always write the header.

                    bitStream.Write(character.ZoneId); // Write the zone id
                    bitStream.Write(character.MapInstance); // Write the map instance
                    bitStream.Write(character.MapClone); // Write the map clone
                    for (var i = 0; i < 4; i++)
                        bitStream.Write(ZoneChecksums.Checksums[(ZoneId)character.ZoneId][i]); // Write the checksum
                    bitStream.Write((ushort)0); // ???
                    for (var i = 0; i < 3; i++) bitStream.Write(character.Position[i]); // Write the position
                    bitStream.Write((uint)0); // Supposed to be 4, if in battle...

                    // Send the packet
                    WorldServer.Server.Send(bitStream, WPacketPriority.SystemPriority,
                        WPacketReliability.ReliableOrdered, 0, client.Address, false);

                    Console.WriteLine(
                        $"Sent world info to client - ZoneId = {character.ZoneId}, Map Instance = {character.MapInstance}, Map Clone = {character.MapClone}");
                }

                // commented to make world single server
                /*
                                using (var bitStream = new WBitStream()) // Create the redirect packet
                                {
                                    bitStream.WriteHeader(RemoteConnection.Client, (uint)MsgClientTransferToWorld);
                                    // Always write the header.
                                    bitStream.WriteString("127.0.0.1", 33);
                                    // Write the IP to redirect to (TODO: Make this the broadcast IP)
                                    bitStream.Write(2006);
                                    // Write the port of the server.
                                    bitStream.Write((byte)0);
                                    // Don't say that this was a mythran dimensional shift, because it wasn't.

                                    WorldServer.Server.Send(bitStream, WPacketPriority.SystemPriority,
                                        WPacketReliability.ReliableOrdered, 0, client.Address, false); // Send the redirect packet.
                                }
                */
            }
        }
        public override void Handle(BinaryReader reader, LuClient client)
        {
            using (var database = new DbUtils())
            {
                if (!client.Authenticated)
                    return; // You need to have an account and be signed into it to make a character!

                var name = reader.ReadWString(66); // Read the name of the new character
                reader.BaseStream.Position = 74; // Set the position to right after the username
                var name1 = reader.ReadUInt32(); // Read
                var name2 = reader.ReadUInt32(); // FTP
                var name3 = reader.ReadUInt32(); // Names

                // TODO: Implement FTP names

                reader.ReadBytes(9); // Read 9 ... unknown bytes?

                var shirtColor = reader.ReadUInt32(); // Read their choices in appearance
                var shirtStyle = reader.ReadUInt32();
                var pantsColor = reader.ReadUInt32();
                var hairStyle = reader.ReadUInt32();
                var hairColor = reader.ReadUInt32();
                var lh = reader.ReadUInt32();
                var rh = reader.ReadUInt32();
                var eyebrows = reader.ReadUInt32();
                var eyes = reader.ReadUInt32();
                var mouth = reader.ReadUInt32();

                var responseId =
                    (byte) (database.CharacterExists(name) ? 0x04 : 0x00);
                // Generate the respond ID

                var account = database.GetAccount(client.Username);

                if (account.Characters.Count >= 4) // Don't want any cheaters getting more than 4!
                {
                    responseId = 0x04;
                }

                if (responseId == 0x00) // Make sure to actually make it, if the character does not exist.
                {
                    // Create the new character
                    var character = new Character
                    {
                        Name = name,
                        Eyebrows = eyebrows,
                        Eyes = eyes,
                        HairColor = hairColor,
                        HairStyle = hairStyle,
                        Lh = lh,
                        Rh = rh,
                        Mouth = mouth,
                        Name1 = name1,
                        Name2 = name2,
                        Name3 = name3,
                        PantsColor = pantsColor,
                        ShirtColor = shirtColor,
                        ShirtStyle = shirtStyle,
                        // Initialize the other character data
                        Position = ZonePositions.VentureExplorer,
                        Owner = client.Username,
                        MapInstance = 0,
                        MapClone = 0,
                        ZoneId = (ushort) ZoneId.VentureExplorer,
                        Armor = 0,
                        MaxArmor = 0,
                        Health = 4,
                        MaxHealth = 4,
                        Imagination = 0,
                        MaxImagination = 0,
                        GmLevel = 0,
                        Reputation = 0,
                        Items = new List<BackpackItem>(),
                        BackpackSpace = 20,
                        Level = 0,
                        Missions = new List<string>()
                    };

                    character.Items.Add(
                        new BackpackItem
                        {
                            Lot = WorldPackets.FindCharShirtID(shirtColor, shirtStyle),
                            Linked = false,
                            Count = 1,
                            Slot = 0
                        });
                    //character.AddItem(WorldPackets.);

                    database.AddCharacter(character); // Add the character to the database.

                    account.Characters.Add(character.Name); // Add the character to the account
                    database.UpdateAccount(account); // Update the account
                }

                // Output the code
                Console.WriteLine($"Got character create request from {client.Username}. Response Code: {responseId}");

                // Create the response
                using (var bitStream = new WBitStream())
                {
                    bitStream.WriteHeader(RemoteConnection.Client, (uint) MsgClientCharacterCreateResponse);
                    // Always write the packet header.
                    bitStream.Write((responseId)); // Write the response code.
                    WorldServer.Server.Send(bitStream, SystemPriority,
                        ReliableOrdered, 0, client.Address, false); // Send the response.
                }

                if (responseId == 0x00)
                    WorldPackets.SendCharacterListResponse(client.Address, database.GetAccount(client.Username),
                        WorldServer.Server);
                // Send the updated character list.
            }
        }