Exemplo n.º 1
0
        public void TestReadonlyCheck()
        {
            byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
            string text  = "Hello World!";

            using var write = new PacketBuffer();
            write.WriteUInt16(0x3f7a);
            write.WriteDateTime(DateTime.Now);

            using var read = new PacketBuffer(write.GetBuffer());
            Assert.ThrowsException <InvalidOperationException>(() => read.WriteBoolean(true));
            Assert.ThrowsException <InvalidOperationException>(() => read.WriteByte(0x7f));
            Assert.ThrowsException <InvalidOperationException>(() => read.WriteUInt16(0x900a));
            Assert.ThrowsException <InvalidOperationException>(() => read.WriteInt32(0x6502a14c));
            Assert.ThrowsException <InvalidOperationException>(() => read.WriteInt64(0x1a41a174a64c91aa));
            Assert.ThrowsException <InvalidOperationException>(() => read.WriteDateTime(default));
Exemplo n.º 2
0
        public Client(IServiceProvider serviceProvider, ConnectionsService connections, PacketService packets, ILogger <Client> logger,
                      PacketStream stream, CancellationToken ct)
        {
            this.serviceProvider = serviceProvider;
            this.connections     = connections;
            this.packets         = packets;
            this.logger          = logger;

            this.stream = stream;
            this.ct     = ct;
            sendQueue   = new JobQueue <Packet, bool>(async(packet, dispose) =>
            {
                try
                {
                    using var buffer = new PacketBuffer();
                    packet.WritePacket(buffer, PacketRole.Server);
                    await stream.WriteAsync(packet.Id, buffer.GetBuffer()).ConfigureAwait(false);
                    logger.LogInformation("Successfully sent packet {0} to session {1}", packet, SessionId.ToString("x8"));
                }
                catch (IOException ex) when(ex.InnerException is SocketException socketEx)
                {
                    await DisposeAsync(waitForHandling: false).ConfigureAwait(false);
                    if (socketEx.SocketErrorCode == SocketError.TimedOut)
                    {
                        logger.LogInformation("Session {0} timed out", SessionId.ToString("x8"));
                    }
                    else
                    {
                        logger.LogInformation("Session {0} lost connection", SessionId.ToString("x8"));
                    }
                }
                catch (Exception ex)
                {
                    await DisposeAsync(waitForHandling: false).ConfigureAwait(false);
                    logger.LogCritical(ex, "Unexpected exception occurred while sending packet {0} to session {1}",
                                       packet.Id.ToString("x2"), SessionId.ToString("x8"));
                }
                finally
                {
                    if (dispose)
                    {
                        (packet as IDisposable)?.Dispose();
                    }
                }
            });
            handler = Listen();
        }
Exemplo n.º 3
0
        public void SendEntities(User user)
        {
            foreach (var npc in NpcTalk)
            {
                var buffer = new PacketBuffer(0x8, user);
                buffer.WriteUInt16(npc.EntityId);
                buffer.WriteUInt16(2); // Type? 2 = NPC
                buffer.WriteUInt32((uint)npc.Type);
                buffer.WriteUInt32(0); // ?
                buffer.WriteUInt16(0); // ?

                var pos = PointObjects.FirstOrDefault(x => x.Id == npc.PosId);

                if (pos != null)
                {
                    buffer.WriteUInt16((ushort)pos.X);
                    buffer.WriteUInt16((ushort)pos.Y);
                    buffer.WriteUInt16((ushort)pos.X);
                    buffer.WriteUInt16((ushort)pos.Y);
                }
                else
                {
                    Program.logger.Error("------ Entity position {0} not found for NPC {1} in map {2} ({3})", npc.PosId, npc.Type, Name, Id);

                    buffer.WriteUInt16(0);
                    buffer.WriteUInt16(0);
                    buffer.WriteUInt16(0);
                    buffer.WriteUInt16(0);
                }

                buffer.WriteString(Methods.Utf8Convert(Data.CharacterInfo[npc.Type].Name));
                buffer.WriteByte(0x00);

                buffer.WriteHexString("00 80 00 00 00 00 00 00 00 00 00 00"); // ?
                buffer.WriteUInt16((ushort)npc.PosId);
                buffer.WriteUInt16((ushort)npc.HeadMarkType);                 // Head marking
                buffer.WriteUInt16(0);                                        // ?

                Program.logger.Debug("Sending entity packet: {0}", Util.ByteToHex(buffer.GetBuffer()));

                buffer.Send();
            }
        }
Exemplo n.º 4
0
        // 0x05
        public static void HandleSelect2(User user, byte[] packet)
        {
            var p1 = new PacketBuffer(0x2E29, user);

            p1.WriteHexString("00 00 00");
            p1.Send();

            var full = new List <byte>();

            var player = new PacketBuffer(0x07, user);

            player.WriteUInt16(user.Character.EntityId);

            // wrong type?
            //player.WriteHexString("01 00 04 00 09 04 01 00 08 00 00 00 B5 03 B4 08 B5 03 B4 08 64 75 72 61 67 6F 6E 31 32 34 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 60 00 00 00 F7 1A 00 00 29 1B 00 00 00 00 00 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");

            player.WriteUInt16(1); // ? (user.Character.FType);
            player.WriteUInt16(user.Character.Type);
            player.WriteByte((byte)user.Character.Hair);
            player.WriteByte((byte)user.Character.Type);
            player.WriteUInt16(user.Character.Level); // ?
            player.WriteUInt32(8);                    // ?
            player.WriteUInt16(user.Character.X);
            player.WriteUInt16(user.Character.Y);
            player.WriteUInt16(user.Character.X);
            player.WriteUInt16(user.Character.Y);
            player.WriteString(user.Character.Name);

            player.WriteHexString("00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 60 00 00 00");

            // equip
            player.WriteUInt32(0x1AF7);
            // equip
            player.WriteUInt32(0x1B29);

            player.WriteHexString("00 00 00 00 00 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");

            Program.logger.Info("GS Login player packet: {0}", Util.ByteToHex(player.GetBuffer()));

            full.AddRange(player.GetPacket());

            var unk1 = new PacketBuffer(0x135, user);

            full.AddRange(unk1.GetPacket());

            var unk2 = new PacketBuffer(0x25C, user);

            full.AddRange(unk2.GetPacket());

            var unk5 = new PacketBuffer(0x3A6, user);

            unk5.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00");
            full.AddRange(unk5.GetPacket());

            var unk6 = new PacketBuffer(0x3A5, user);

            unk6.WriteUInt16(user.Character.EntityId);
            unk6.WriteHexString("00 00");
            full.AddRange(unk6.GetPacket());

            var unk7 = new PacketBuffer(0x325, user);

            unk7.WriteHexString("AD E6 76 CE");
            full.AddRange(unk7.GetPacket());

            var time = new PacketBuffer(0x477, user);

            time.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00");
            time.WriteUInt64(Methods.DateTimeToUnix(DateTime.UtcNow));
            full.AddRange(time.GetPacket());

            var unk9 = new PacketBuffer(0x4CC, user);

            unk9.WriteHexString("00 00 00 00");
            full.AddRange(unk9.GetPacket());

            var healthStatus = new PacketBuffer(0x24, user);

            healthStatus.WriteHexString("29 00 00 00");
            full.AddRange(healthStatus.GetPacket());

            var manaStatus = new PacketBuffer(0x25, user);

            manaStatus.WriteHexString("05 00 00 00");
            full.AddRange(manaStatus.GetPacket());

            user.Socket.Send(full.ToArray());

            Data.Maps[user.Character.Map].SendEntities(user);
        }
Exemplo n.º 5
0
        // 0x9C
        // 18 00 9C 00 00 00 63 00 9A
        // E2 6E F7 05 00 00 00 00 F3 5F 00 00 02
        public static void EnterMap(User user, InPacket inPacket)
        {
            var enterId   = inPacket.ReadUInt();
            var foundUser = Program._users.Where(x => x.Value != null && x.Value.Character != null && x.Value.Character.Id == enterId).FirstOrDefault();

            if (foundUser.Value == null)
            {
                throw new Exception("Zone change user not found");
            }
            //Program.logger.Info("Old key [user]: {0}", Util.ByteToHex(user.ClientSession.Key));
            //Program.logger.Info("Old key [foundUser.ClientSession]: {0}", Util.ByteToHex(foundUser.Value.ClientSession.Key));

            var currSock          = user.Socket;
            var currClientSession = user.ClientSession;

            //Program.logger.Info("Found user socket: {0} / New: {1}", foundUser.Value.Socket.RemoteEndPoint.ToString(), user.Socket.RemoteEndPoint.ToString());

            Program._users[user.Socket.RemoteEndPoint.ToString()] = foundUser.Value;
            user                      = Program._users[user.Socket.RemoteEndPoint.ToString()];
            user.Socket               = currSock;
            user.ClientSession        = currClientSession;
            user.ClientSession.Client = user;
            user.ServerSession        = new SessionInfo
            {
                Client = user
            };

            Program._users.Remove(foundUser.Key);

            var character = user.Character;

            Program.logger.Info("{0} - Enter Zone: {1} ({2})", character.Name, Data.Maps[character.Map].Name, character.Map);

            character.EntityId = ++Program.EntityId;

            {
                var notifyEntityId = new PacketBuffer(0x3D1, user);
                notifyEntityId.WriteUInt32(character.EntityId);
                notifyEntityId.WriteHexString("00 00 00 00 00 00 00 00");
                notifyEntityId.Send();
            }

            var charInfo = new List <byte>();

            {
                var unk1 = new PacketBuffer(0x377, user);
                unk1.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A8 36 00 00 00 00 00 00 00 00 17 B7 51 38");
                charInfo.AddRange(unk1.GetPacket());
            }

            {
                var unk2 = new PacketBuffer(0x376, user);
                unk2.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A8 36 00 00 00 00 00 00 00 00 17 B7 51 38");
                charInfo.AddRange(unk2.GetPacket());
            }

            {
                var unk3 = new PacketBuffer(0x3D7, user);
                unk3.WriteHexString("01 00 00 00 00 90 85 D5 41 00 00 00 00 00 00 00 00 00 00 00 00 77 86 45 5B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
                charInfo.AddRange(unk3.GetPacket());
            }

            {
                var unk4 = new PacketBuffer(0x2A4, user);
                unk4.WriteUInt16(0);
                charInfo.AddRange(unk4.GetPacket());
            }

            {
                var unk5 = new PacketBuffer(0x3E4, user);
                unk5.WriteUInt32(3);
                charInfo.AddRange(unk5.GetPacket());
            }

            {
                var unk6 = new PacketBuffer(0x3E7, user);
                unk6.WriteUInt16(character.EntityId);
                unk6.WriteHexString("00 00 00 00 00 00 00 00 00 00 00");
                charInfo.AddRange(unk6.GetPacket());
            }

            {
                var unk7 = new PacketBuffer(0x3EA, user);
                unk7.WriteUInt16(0);
                charInfo.AddRange(unk7.GetPacket());
            }

            {
                var unk8 = new PacketBuffer(0x4CC, user);
                unk8.WriteHexString("00 00 00 00");
                charInfo.AddRange(unk8.GetPacket());
            }

            {
                var unk9 = new PacketBuffer(0x1B5, user);
                unk9.WriteUInt16(character.EntityId);
                unk9.WriteUInt16(character.X);
                unk9.WriteUInt16(character.Y);
                unk9.WriteHexString("00 00 00 00 00");
                charInfo.AddRange(unk9.GetPacket());
            }

            {
                var unk10 = new PacketBuffer(0x376, user);
                unk10.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E2 4F 4D 3E 00 00 00 00 00 00 00 00 17 B7 51 38");
                charInfo.AddRange(unk10.GetPacket());
            }

            {
                var unk11 = new PacketBuffer(0x377, user);
                unk11.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E2 4F 4D 3E 00 00 00 00 00 00 00 00 17 B7 51 38");
                charInfo.AddRange(unk11.GetPacket());
            }

            {
                var notifyEntity = new PacketBuffer(0x09, user);
                notifyEntity.WriteUInt16(character.EntityId);
                notifyEntity.WriteUInt16(1);
                notifyEntity.WriteUInt16(character.Job);
                notifyEntity.WriteByte((byte)character.Hair);
                notifyEntity.WriteByte((byte)character.Type);
                notifyEntity.WriteUInt16(character.Level);
                notifyEntity.WriteUInt32(8); // ?
                notifyEntity.WriteUInt16(character.X);
                notifyEntity.WriteUInt16(character.Y);
                notifyEntity.WriteUInt16(character.X);
                notifyEntity.WriteUInt16(character.Y);
                notifyEntity.WriteString(character.Name);
                notifyEntity.WriteUInt32(0x00);
                notifyEntity.WriteUInt32(0x00); // ?
                notifyEntity.WriteUInt32(0x01); // ?
                notifyEntity.WriteUInt32(0);    // ?
                notifyEntity.WriteUInt32(0);    // ?
                notifyEntity.WriteUInt16(0);    // ????
                notifyEntity.WriteByte((byte)character.Job);

                /*
                 * notifyEntity.WriteUInt32(63);
                 * notifyEntity.WriteUInt32(6903); // Item
                 * notifyEntity.WriteUInt32(6953); // Item
                 * notifyEntity.WriteUInt32(0);
                 */
                notifyEntity.WriteHexString("00 00 00 00 63 00 00 00 F6 45 00 00 90 28 01 00 14 1B 00 00 46 1B 00 00 00 00 00 00 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");

                Program.logger.Info("Self entity packet: {0}", Util.ByteToHex(notifyEntity.GetBuffer()));

                charInfo.AddRange(notifyEntity.GetPacket());
            }

            {
                var unk12 = new PacketBuffer(0x25C, user);
                charInfo.AddRange(unk12.GetPacket());
            }

            {
                var unk13 = new PacketBuffer(0x377, user);
                unk13.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 CE 4C 3E 00 00 00 00 00 00 00 00 17 B7 51 38");
                charInfo.AddRange(unk13.GetPacket());
            }

            {
                var unk14 = new PacketBuffer(0x376, user);
                unk14.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 CE 4C 3E 00 00 00 00 00 00 00 00 17 B7 51 38");
                charInfo.AddRange(unk14.GetPacket());
            }

            {
                var unk15 = new PacketBuffer(0x42C, user);
                unk15.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
                charInfo.AddRange(unk15.GetPacket());
            }

            {
                var unk16 = new PacketBuffer(0x9D, user);
                unk16.WriteUInt32(0);
                charInfo.AddRange(unk16.GetPacket());
            }

            {
                var healthStatus = new PacketBuffer(0x24, user);
                healthStatus.WriteHexString("29 00 00 00");
                charInfo.AddRange(healthStatus.GetPacket());
            }

            {
                var manaStatus = new PacketBuffer(0x25, user);
                manaStatus.WriteHexString("05 00 00 00");
                charInfo.AddRange(manaStatus.GetPacket());
            }

            user.Socket.Send(charInfo.ToArray());

            {
                var p1 = new PacketBuffer(0x1D8, user);
                p1.WriteUInt16(character.EntityId);
                p1.WriteByte(0x2E);
                p1.Send();
            }
        }
Exemplo n.º 6
0
        public static void Handle(User user, byte[] packet)
        {
            var numChars = 0;

            try
            {
                using (MySqlCommand cmd = Program._MySQLConn.CreateCommand())
                {
                    cmd.CommandText = "SELECT COUNT(*) FROM characters WHERE user = @userid AND authority != 2;";
                    cmd.Parameters.AddWithValue("@userid", Methods.CleanString(user.Id.ToString()));
                    numChars = Convert.ToInt32(cmd.ExecuteScalar());
                    cmd.Dispose();
                }
            }
            catch (Exception ex)
            {
                Program.logger.Error(ex, "Database error: ");
                return;
            }

            user.NumChars = numChars;

            PacketBuffer chars = new PacketBuffer(0x7D2, user);

            chars.WriteByte((byte)numChars); // Number of characters

            if (numChars > 0)
            {
                byte slotNum = 0;
                using (MySqlCommand cmd = Program._MySQLConn.CreateCommand())
                {
                    cmd.CommandText = "SELECT * FROM characters WHERE user = @userid AND authority != 2 LIMIT 12;";
                    cmd.Parameters.AddWithValue("@userid", Methods.CleanString(user.Id.ToString()));
                    using (MySqlDataReader reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            chars.WriteUInt32(reader.GetUInt32("id")); // Character ID
                            chars.WriteInt32(0);                       // probably part of int64?

                            chars.WriteByte(slotNum);                  // Index

                            // 16 bytes maximum, but 20 is fine
                            var name = Methods.Utf8Convert(reader.GetString("name"));
                            chars.WriteString(name, 20);

                            // Job(1)
                            // 0x09 = (int)9 : Paula
                            chars.WriteUInt16(reader.GetUInt16("job"));

                            // ?
                            // Display job?
                            chars.WriteUInt16(0);

                            // FType (power/magic/sense/charm)
                            chars.WriteByte((byte)reader.GetInt32("ftype")); // (byte)Constants.CharacterTypes[9]);

                            // Type(2)
                            // 0x09 = (int)9 : Paula
                            chars.WriteByte((byte)reader.GetInt32("type")); // 0x09

                            // ?
                            // [Dev]Raymonf = 01 0C
                            chars.WriteHexString("00 01");

                            // hair color
                            // 0x0A
                            chars.WriteUInt16((byte)reader.GetUInt16("hair"));

                            // Galders
                            chars.WriteUInt32((byte)reader.GetUInt32("money"));

                            // Level
                            chars.WriteUInt16(reader.GetUInt16("level"));

                            // Hat (head item)
                            // Rookie Hat
                            chars.WriteUInt32(4030);

                            // Weapon (sword)
                            // Rookie Sword
                            chars.WriteUInt32(3030);

                            // Shield
                            // Rookie Shield
                            //chars.WriteUInt(6530);
                            chars.WriteUInt32(0); // paula can't wear these

                            // Innerwear
                            chars.WriteUInt32(0);

                            // Accessory 1
                            // Duckling Keychain
                            chars.WriteUInt32(19241);

                            // Bear's ears
                            chars.WriteInt32(6932);

                            // Bear's tail
                            chars.WriteInt32(6982);

                            // Drill
                            // Flicker Drill
                            chars.WriteUInt32(19901);

                            // Pet
                            // Peng
                            chars.WriteUInt32(1642);

                            // Accessory 2
                            // Tin tiger amulet
                            chars.WriteUInt32(440004);


                            //////// Unchartered territories
                            // ??
                            chars.WriteUInt32(0);

                            // ??
                            chars.WriteUInt32(0);

                            // ??
                            chars.WriteUInt32(0);

                            // ???
                            chars.WriteUInt32(0);

                            // ???
                            chars.WriteUInt32(0);

                            // ???
                            chars.WriteUInt32(0);

                            // ???
                            chars.WriteUInt32(0);

                            // ???
                            chars.WriteUInt32(0);

                            // Ammo?
                            chars.WriteUInt32(5500);

                            // Cape
                            chars.WriteUInt32(35082);

                            // Sprint
                            chars.WriteUInt32(888887);

                            // TODO
                            // ?
                            chars.WriteHexString("02 01 00");

                            // 3rd job
                            chars.WriteUInt16(22);
                            chars.WriteUInt16(29);

                            chars.WriteHexString("00 01 00 00 00 00");
                            //chars.WriteByte(0x00);
                            chars.WriteUInt32(0);
                            chars.WriteUInt32(0);
                            chars.WriteUInt32(0);
                            chars.WriteHexString("00 00");

                            slotNum++;
                        }
                    }
                }
            }

            chars.WriteHexString("00 00 00 00 00 00 00 00 00 00 00");
            chars.WriteByte((byte)user.SlotsAllowed); // Number of character slots

            Program.logger.Debug("Character select packet: {0}", Util.ByteToHex(chars.GetBuffer()));

            chars.Send();
        }
Exemplo n.º 7
0
        public static void Handle(User user, byte[] packet)
        {
            Program.logger.Debug("Received packet: {0}", Util.ByteToHex(packet));

            var nameBytes = Methods.ReadTerminatedStringToBytes(packet);

            var startIdx = nameBytes.Length + 1;

            byte type = packet[startIdx];          // 0x09
            byte job  = packet[startIdx + 3];      // 0x09

            byte hairColor = packet[startIdx + 2]; // 0x0A - hair color

            int stat_p = packet[startIdx + 5];
            int stat_m = packet[startIdx + 6];
            int stat_s = packet[startIdx + 7];
            int stat_c = packet[startIdx + 8];

            var name = Constants.Encoding.GetString(nameBytes);

            // Check the name
            try
            {
                using (MySqlCommand cmd = Program._MySQLConn.CreateCommand())
                {
                    cmd.CommandText = "SELECT COUNT(*) FROM characters WHERE name LIKE @name AND authority != 2;";
                    cmd.Parameters.AddWithValue("@name", Methods.CleanString(name));

                    if (Convert.ToInt32(cmd.ExecuteScalar()) >= 1)
                    {
                        var fail = new PacketBuffer(0x7D7, user);
                        fail.WriteUInt32(0x3FF);
                        fail.Send();

                        cmd.Dispose();
                        return;
                    }

                    cmd.Dispose();
                }
            }
            catch (Exception ex)
            {
                Program.logger.Error(ex, "Database error: ");
                return;
            }


            uint newCharId = 0;

            using (MySqlCommand cmd = Program._MySQLConn.CreateCommand())
            {
                cmd.CommandText = "INSERT INTO characters (user, name, job, type, ftype, hair, build) VALUES (@userid, @charname, @job, @type, @ftype, @hair, @build); select last_insert_id();";
                cmd.Parameters.AddWithValue("@userid", user.Id);
                cmd.Parameters.AddWithValue("@charname", name);
                cmd.Parameters.AddWithValue("@job", job);
                cmd.Parameters.AddWithValue("@type", type);
                cmd.Parameters.AddWithValue("@ftype", Constants.CharacterTypes[type]);
                cmd.Parameters.AddWithValue("@hair", hairColor);
                cmd.Parameters.AddWithValue("@build", stat_p + "," + stat_m + "," + stat_s + "," + stat_c);
                newCharId = Convert.ToUInt32(cmd.ExecuteScalar());
            }

            Program.logger.Debug("New character ID: {0}", newCharId);

            user.NumChars++;

            PacketBuffer res = new PacketBuffer(0x7D8, user);

            res.WriteUInt32(newCharId);               // Character ID
            res.WriteInt32(0);                        // probably part of int64?

            res.WriteByte((byte)(user.NumChars - 1)); // Index

            // 16 bytes maximum, but 20 is fine
            res.WriteString(name, 20);

            // Job(1)
            // 0x09 = (int)9 : Paula
            res.WriteUInt16(job);

            // ?
            // Display job?
            res.WriteUInt16(0);

            // FType (power/magic/sense/charm)
            res.WriteByte((byte)Constants.CharacterTypes[type]);

            // Type(2)
            // 0x09 = (int)9 : Paula
            res.WriteByte((byte)type); // 0x09

            // ?
            // [Dev]Raymonf = 0C 03
            res.WriteHexString("00 01");

            // hair color
            // 0x0A
            res.WriteUInt16(hairColor);

            // Galders
            res.WriteUInt32(0);

            // Level
            res.WriteUInt16(1);

            // Hat (head item)
            // Rookie Hat
            res.WriteUInt32(0);

            // Weapon (sword)
            // Rookie Sword
            res.WriteUInt32(0);

            // Shield
            // Rookie Shield
            res.WriteUInt32(0);

            // ??
            res.WriteUInt32(0);

            // Accessory 1
            // Jeweled Egg 40
            res.WriteUInt32(0);

            // Bear's ears
            res.WriteInt32(6932);

            // Bear's tail
            res.WriteInt32(6982);

            // Flicker Drill
            res.WriteUInt32(0);

            // ??
            res.WriteUInt32(0);

            // Accessory 2
            // Pocket pouch
            res.WriteUInt32(7000);

            // ??
            res.WriteUInt32(0);

            // ??
            res.WriteUInt32(0);

            // ??
            res.WriteUInt32(0);

            // TODO
            res.WriteHexString("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");

            Program.logger.Debug("Create packet: {0}", Util.ByteToHex(res.GetBuffer()));

            res.Send();
        }