public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            if (client.Player == null)
            {
                return;
            }
            Region region = client.Player.CurrentRegion;

            if (region == null)
            {
                return;
            }

            ushort id;

            if (client.Version >= GameClient.eClientVersion.Version1126)
            {
                id = packet.ReadShortLowEndian();                 // Dre: disassembled game.dll show a write of uint, is it a wip in the game.dll?
            }
            else
            {
                id = packet.ReadShort();
            }
            GameNPC npc = region.GetObject(id) as GameNPC;

            if (npc == null || !client.Player.IsWithinRadius(npc, WorldMgr.OBJ_UPDATE_DISTANCE))
            {
                client.Out.SendObjectDelete(id);
                return;
            }

            if (npc != null)
            {
                Tuple <ushort, ushort> key = new Tuple <ushort, ushort>(npc.CurrentRegionID, (ushort)npc.ObjectID);

                long updatetime;
                if (!client.GameObjectUpdateArray.TryGetValue(key, out updatetime))
                {
                    updatetime = 0;
                }

                client.Out.SendNPCCreate(npc);
                // override update from npc create as this is a client request !
                if (updatetime > 0)
                {
                    client.GameObjectUpdateArray[key] = updatetime;
                }

                if (npc.Inventory != null)
                {
                    client.Out.SendLivingEquipmentUpdate(npc);
                }

                //DO NOT SEND A NPC UPDATE, it is done in Create anyway
                //Sending a Update causes a UDP packet to be sent and
                //the client will get the UDP packet before the TCP Create packet
                //Causing the client to issue another NPC CREATION REQUEST!
                //client.Out.SendNPCUpdate(npc); <-- BIG NO NO
            }
        }
Exemple #2
0
        public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            // we don't handle Encryption for 1.115c
            // the rc4 secret can't be unencrypted from RSA.

            // register client type
            byte clientType = (byte)packet.ReadByte();

            client.ClientType   = (GameClient.eClientType)(clientType & 0x0F);
            client.ClientAddons = (GameClient.eClientAddons)(clientType & 0xF0);

            // if the DataSize is above 7 then the RC4 key is bundled
            // this is stored in case we find a way to handle encryption someday !
            if (packet.DataSize > 7)
            {
                packet.Skip(6);
                ushort length = packet.ReadShortLowEndian();
                packet.Read(client.PacketProcessor.Encoding.SBox, 0, length);

                // ((PacketEncoding168)client.PacketProcessor.Encoding).EncryptionState=PacketEncoding168.eEncryptionState.PseudoRC4Encrypted;
            }

            // Send the crypt key to the client
            client.Out.SendVersionAndCryptKey();
        }
        public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            // for 1.115c+ The First client packet Changes.
            if (client.Version < GameClient.eClientVersion.Version1115)
            {
                int  rc4        = packet.ReadByte();
                byte clientType = (byte)packet.ReadByte();
                client.ClientType   = (GameClient.eClientType)(clientType & 0x0F);
                client.ClientAddons = (GameClient.eClientAddons)(clientType & 0xF0);
                byte major = (byte)packet.ReadByte();
                byte minor = (byte)packet.ReadByte();
                byte build = (byte)packet.ReadByte();
                if (rc4 == 1)
                {
                    //DOLConsole.Log("SBox=\n");
                    //DOLConsole.LogDump(client.PacketProcessor.Encoding.SBox);
                    packet.Read(((PacketEncoding168)client.PacketProcessor.Encoding).SBox, 0, 256);
                    ((PacketEncoding168)client.PacketProcessor.Encoding).EncryptionState = PacketEncoding168.eEncryptionState.PseudoRC4Encrypted;
                    //DOLConsole.WriteLine(client.Socket.RemoteEndPoint.ToString()+": SBox set!");
                    //DOLConsole.Log("SBox=\n");
                    //DOLConsole.LogDump(((PacketEncoding168)client.PacketProcessor.Encoding).SBox);
                }
                else
                {
                    //Send the crypt key to the client
                    client.Out.SendVersionAndCryptKey();
                }
            }
            else
            {
                // we don't handle Encryption for 1.115c
                // the rc4 secret can't be unencrypted from RSA.

                // register client type
                byte clientType = (byte)packet.ReadByte();
                client.ClientType   = (GameClient.eClientType)(clientType & 0x0F);
                client.ClientAddons = (GameClient.eClientAddons)(clientType & 0xF0);

                // if the DataSize is above 7 then the RC4 key is bundled
                // this is stored in case we find a way to handle encryption someday !
                if (packet.DataSize > 7)
                {
                    packet.Skip(6);
                    ushort length = packet.ReadShortLowEndian();
                    packet.Read(client.PacketProcessor.Encoding.SBox, 0, length);
                    // ((PacketEncoding168)client.PacketProcessor.Encoding).EncryptionState=PacketEncoding168.eEncryptionState.PseudoRC4Encrypted;
                }

                //Send the crypt key to the client
                client.Out.SendVersionAndCryptKey();
            }
        }
		public void HandlePacket(GameClient client, GSPacketIn packet)
		{
			// for 1.115c+ The First client packet Changes.
			if (client.Version < GameClient.eClientVersion.Version1115)
			{
				int rc4 = packet.ReadByte();
				byte clientType = (byte)packet.ReadByte();
				client.ClientType = (GameClient.eClientType)(clientType & 0x0F);
				client.ClientAddons = (GameClient.eClientAddons)(clientType & 0xF0);
				byte major = (byte)packet.ReadByte();
				byte minor = (byte)packet.ReadByte();
				byte build = (byte)packet.ReadByte();
				if(rc4==1)
				{
					//DOLConsole.Log("SBox=\n");
					//DOLConsole.LogDump(client.PacketProcessor.Encoding.SBox);
					packet.Read(((PacketEncoding168)client.PacketProcessor.Encoding).SBox,0,256);
					((PacketEncoding168)client.PacketProcessor.Encoding).EncryptionState=PacketEncoding168.eEncryptionState.PseudoRC4Encrypted;
					//DOLConsole.WriteLine(client.Socket.RemoteEndPoint.ToString()+": SBox set!");
					//DOLConsole.Log("SBox=\n");
					//DOLConsole.LogDump(((PacketEncoding168)client.PacketProcessor.Encoding).SBox);
				}
				else
				{
				  //Send the crypt key to the client
					client.Out.SendVersionAndCryptKey();
				}
			}
			else
			{
				// we don't handle Encryption for 1.115c
				// the rc4 secret can't be unencrypted from RSA.
				
				// register client type
				byte clientType = (byte)packet.ReadByte();
				client.ClientType = (GameClient.eClientType)(clientType & 0x0F);
				client.ClientAddons = (GameClient.eClientAddons)(clientType & 0xF0);
				
				// if the DataSize is above 7 then the RC4 key is bundled
				// this is stored in case we find a way to handle encryption someday !
				if (packet.DataSize > 7)
				{
					packet.Skip(6);
					ushort length = packet.ReadShortLowEndian();
					packet.Read(client.PacketProcessor.Encoding.SBox, 0, length);
					// ((PacketEncoding168)client.PacketProcessor.Encoding).EncryptionState=PacketEncoding168.eEncryptionState.PseudoRC4Encrypted;
				}
				
				//Send the crypt key to the client
				client.Out.SendVersionAndCryptKey();
			}
		}
Exemple #5
0
        public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            ushort id;

            if (client.Version >= GameClient.eClientVersion.Version1126)
            {
                id = packet.ReadShortLowEndian();
            }
            else
            {
                id = packet.ReadShort();
            }

            Region region = client.Player?.CurrentRegion;

            if (region?.GetObject(id) is GameNPC npc)
            {
                Tuple <ushort, ushort> key = new Tuple <ushort, ushort>(npc.CurrentRegionID, (ushort)npc.ObjectID);

                if (!client.GameObjectUpdateArray.TryGetValue(key, out var updatetime))
                {
                    updatetime = 0;
                }

                client.Out.SendNPCCreate(npc);

                // override update from npc create as this is a client request !
                if (updatetime > 0)
                {
                    client.GameObjectUpdateArray[key] = updatetime;
                }

                if (npc.Inventory != null)
                {
                    client.Out.SendLivingEquipmentUpdate(npc);
                }

                // DO NOT SEND A NPC UPDATE, it is done in Create anyway
                // Sending a Update causes a UDP packet to be sent and
                // the client will get the UDP packet before the TCP Create packet
                // Causing the client to issue another NPC CREATION REQUEST!
                // client.Out.SendNPCUpdate(npc); <-- BIG NO NO
            }
        }
            /// <summary>
            /// Reads up ONE character iteration on the packet stream
            /// </summary>
            /// <param name="packet"></param>
            /// <param name="client"></param>
            public CreationCharacterData(GSPacketIn packet, GameClient client)
            {
                //unk - probably indicates customize or create (these are moved from 1.99 4 added bytes)
                if (client.Version >= GameClient.eClientVersion.Version1104)
                {
                    packet.ReadIntLowEndian();
                }

                CharName   = packet.ReadString(24);
                CustomMode = packet.ReadByte();
                EyeSize    = packet.ReadByte();
                LipSize    = packet.ReadByte();
                EyeColor   = packet.ReadByte();
                HairColor  = packet.ReadByte();
                FaceType   = packet.ReadByte();
                HairStyle  = packet.ReadByte();
                packet.Skip(3);
                MoodType = packet.ReadByte();
                packet.Skip(8);

                Operation = packet.ReadInt();
                var unk = packet.ReadByte();

                packet.Skip(24);                 //Location String
                packet.Skip(24);                 //Skip class name
                packet.Skip(24);                 //Skip race name

                var level = packet.ReadByte();   //not safe!

                Class = packet.ReadByte();
                Realm = packet.ReadByte();

                //The following byte contains
                //1bit=start location ... in ShroudedIsles you can choose ...
                //1bit=first race bit
                //1bit=unknown
                //1bit=gender (0=male, 1=female)
                //4bit=race
                byte startRaceGender = (byte)packet.ReadByte();

                Race            = (startRaceGender & 0x0F) + ((startRaceGender & 0x40) >> 2);
                Gender          = ((startRaceGender >> 4) & 0x01);
                SIStartLocation = ((startRaceGender >> 7) != 0);

                CreationModel = packet.ReadShortLowEndian();
                Region        = packet.ReadByte();
                packet.Skip(1);                 //TODO second byte of region unused currently
                packet.Skip(4);                 //TODO Unknown Int / last used?

                Strength     = packet.ReadByte();
                Dexterity    = packet.ReadByte();
                Constitution = packet.ReadByte();
                Quickness    = packet.ReadByte();
                Intelligence = packet.ReadByte();
                Piety        = packet.ReadByte();
                Empathy      = packet.ReadByte();
                Charisma     = packet.ReadByte();

                packet.Skip(40);                         //TODO equipment

                var activeRightSlot = packet.ReadByte(); // 0x9C
                var activeLeftSlot  = packet.ReadByte(); // 0x9D
                var siZone          = packet.ReadByte(); // 0x9E

                // skip 4 bytes added in 1.99
                if (client.Version >= GameClient.eClientVersion.Version199 && client.Version < GameClient.eClientVersion.Version1104)
                {
                    packet.Skip(4);
                }

                // New constitution must be read before skipping 4 bytes
                NewConstitution = packet.ReadByte();                 // 0x9F
            }
        public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            ushort jumpSpotId;

            jumpSpotId = client.Version >= GameClient.eClientVersion.Version1127 ? packet.ReadShortLowEndian() : packet.ReadShort();

            eRealm targetRealm = client.Player.Realm;

            if (client.Player.CurrentRegion.Expansion == (int)eClientExpansion.TrialsOfAtlantis && client.Player.CurrentZone.Realm != eRealm.None)
            {
                // if we are in TrialsOfAtlantis then base the target jump on the current region realm instead of the players realm
                // this is only used if zone table has the proper realms defined, otherwise it reverts to old behavior - Tolakram
                targetRealm = client.Player.CurrentZone.Realm;
            }

            var zonePoint = GameServer.Database.SelectObjects <ZonePoint>(
                "`Id` = @Id AND (`Realm` = @Realm OR `Realm` = @DefaultRealm OR `Realm` IS NULL)",
                new[]
            {
                new QueryParameter("@Id", jumpSpotId), new QueryParameter("@Realm", (byte)targetRealm),
                new QueryParameter("@DefaultRealm", 0)
            })
                            .FirstOrDefault();

            if (zonePoint == null || zonePoint.TargetRegion == 0)
            {
                ChatUtil.SendDebugMessage(client, $"Invalid Jump (ZonePoint table): [{jumpSpotId}]{((zonePoint == null) ? ". Entry missing!" : ". TargetRegion is 0!")}");
                zonePoint = new ZonePoint
                {
                    Id = jumpSpotId
                };
            }

            if (client.Account.PrivLevel > 1)
            {
                client.Out.SendMessage($"JumpSpotID = {jumpSpotId}", eChatType.CT_System, eChatLoc.CL_SystemWindow);
                client.Out.SendMessage($"ZonePoint Target: Region = {zonePoint.TargetRegion}, ClassType = \'{zonePoint.ClassType}\'", eChatType.CT_System, eChatLoc.CL_SystemWindow);
            }

            // Dinberg: Fix - some jump points are handled code side, such as instances.
            // As such, region MAY be zero in the database, so this causes an issue.
            if (zonePoint.TargetRegion != 0)
            {
                Region reg = WorldMgr.GetRegion(zonePoint.TargetRegion);
                if (reg != null)
                {
                    // check for target region disabled if player is in a standard region
                    // otherwise the custom region should handle OnZonePoint for this check
                    if (client.Player.CurrentRegion.IsCustom == false && reg.IsDisabled)
                    {
                        if ((client.Player.Mission is TaskDungeonMission mission &&
                             mission.TaskRegion.Skin == reg.Skin) == false)
                        {
                            client.Out.SendMessage("This region has been disabled!", eChatType.CT_System, eChatLoc.CL_SystemWindow);
                            if (client.Account.PrivLevel == 1)
                            {
                                return;
                            }
                        }
                    }
                }
            }

            // Allow the region to either deny exit or handle the zonepoint in a custom way
            if (client.Player.CurrentRegion.OnZonePoint(client.Player, zonePoint) == false)
            {
                return;
            }

            // check caps for battleground
            Battleground bg = GameServer.KeepManager.GetBattleground(zonePoint.TargetRegion);

            if (client.Player.Level < bg?.MinLevel && client.Player.Level > bg.MaxLevel &&
                client.Player.RealmLevel >= bg.MaxRealmLevel)
            {
                return;
            }

            IJumpPointHandler customHandler = null;

            if (string.IsNullOrEmpty(zonePoint.ClassType) == false)
            {
                customHandler = (IJumpPointHandler)_customJumpPointHandlers[zonePoint.ClassType];

                // check for db change to update cached handler
                if (customHandler != null && customHandler.GetType().FullName != zonePoint.ClassType)
                {
                    customHandler = null;
                }

                if (customHandler == null)
                {
                    // Dinberg - Instances need to use a special handler. This is because some instances will result
                    // in duplicated zonepoints, such as if Tir Na Nog were to be instanced for a quest.
                    string type = client.Player.CurrentRegion.IsInstance
                        ? "DOL.GS.ServerRules.InstanceDoorJumpPoint"
                        : zonePoint.ClassType;
                    Type t = ScriptMgr.GetType(type);

                    if (t == null)
                    {
                        Log.Error($"jump point {zonePoint.Id}: class {zonePoint.ClassType} not found!");
                    }
                    else if (!typeof(IJumpPointHandler).IsAssignableFrom(t))
                    {
                        Log.Error($"jump point {zonePoint.Id}: class {zonePoint.ClassType} must implement IJumpPointHandler interface!");
                    }
                    else
                    {
                        try
                        {
                            customHandler = (IJumpPointHandler)Activator.CreateInstance(t);
                        }
                        catch (Exception e)
                        {
                            customHandler = null;
                            Log.Error($"jump point {zonePoint.Id}: error creating a new instance of jump point handler {zonePoint.ClassType}", e);
                        }
                    }
                }

                if (customHandler != null)
                {
                    _customJumpPointHandlers[zonePoint.ClassType] = customHandler;
                }
            }

            new RegionChangeRequestHandler(client.Player, zonePoint, customHandler).Start(1);
        }
Exemple #8
0
        public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            var    player = client.Player;
            ushort jumpSpotId;

            if (client.Version < GameClient.eClientVersion.Version1126)
            {
                jumpSpotId = packet.ReadShort();
            }
            else
            {
                jumpSpotId = packet.ReadShortLowEndian();
            }

            eRealm targetRealm = player.Realm;

            if (player.CurrentRegion.Expansion == (int)eClientExpansion.TrialsOfAtlantis && player.CurrentZone.Realm != eRealm.None)
            {
                // if we are in TrialsOfAtlantis then base the target jump on the current region realm instead of the players realm
                // this is only used if zone table has the proper realms defined, otherwise it reverts to old behavior - Tolakram
                targetRealm = player.CurrentZone.Realm;
            }

            var filterRealm = DB.Column(nameof(ZonePoint.Realm)).IsEqualTo((byte)targetRealm).Or(DB.Column(nameof(ZonePoint.Realm)).IsEqualTo(0)).Or(DB.Column(nameof(ZonePoint.Realm)).IsNull());
            var zonePoint   = DOLDB <ZonePoint> .SelectObject(DB.Column(nameof(ZonePoint.Id)).IsEqualTo(jumpSpotId).And(filterRealm));

            if (zonePoint == null || zonePoint.TargetRegion == 0)
            {
                ChatUtil.SendDebugMessage(client, $"Invalid Jump (ZonePoint table): [{jumpSpotId}]{((zonePoint == null) ? ". Entry missing!" : ". TargetRegion is 0!")}");
                zonePoint    = new ZonePoint();
                zonePoint.Id = jumpSpotId;
                string zonePointLocation = $"Region {player.CurrentRegionID} and coordinates ({player.X},{player.Y},{player.Z})";
                Log.Error($"ZonePoint {jumpSpotId} at {zonePointLocation} on client {client.Version} missing. Either ZonePoint missing or RegionChangeRequestHandler needs to be updated.");
            }

            if (client.Account.PrivLevel > 1)
            {
                client.Out.SendMessage($"JumpSpotID = {jumpSpotId}", eChatType.CT_System, eChatLoc.CL_SystemWindow);
                client.Out.SendMessage($"ZonePoint Target: Region = {zonePoint.TargetRegion}, ClassType = \'{zonePoint.ClassType}\'", eChatType.CT_System, eChatLoc.CL_SystemWindow);
            }

            //Dinberg: Fix - some jump points are handled code side, such as instances.
            //As such, region MAY be zero in the database, so this causes an issue.

            if (zonePoint.TargetRegion != 0)
            {
                Region reg = WorldMgr.GetRegion(zonePoint.TargetRegion);
                if (reg != null)
                {
                    // check for target region disabled if player is in a standard region
                    // otherwise the custom region should handle OnZonePoint for this check
                    if (player.CurrentRegion.IsCustom == false && reg.IsDisabled)
                    {
                        if ((player.Mission is TaskDungeonMission &&
                             (player.Mission as TaskDungeonMission).TaskRegion.Skin == reg.Skin) == false)
                        {
                            client.Out.SendMessage("This region has been disabled!", eChatType.CT_System, eChatLoc.CL_SystemWindow);
                            if (client.Account.PrivLevel == 1)
                            {
                                return;
                            }
                        }
                    }
                }
            }

            // Allow the region to either deny exit or handle the zonepoint in a custom way
            if (player.CurrentRegion.OnZonePoint(player, zonePoint) == false)
            {
                return;
            }

            //check caps for battleground
            Battleground bg = GameServer.KeepManager.GetBattleground(zonePoint.TargetRegion);

            if (bg != null)
            {
                if (player.Level < bg.MinLevel && player.Level > bg.MaxLevel &&
                    player.RealmLevel >= bg.MaxRealmLevel)
                {
                    return;
                }
            }

            IJumpPointHandler customHandler = null;

            if (string.IsNullOrEmpty(zonePoint.ClassType) == false)
            {
                customHandler = (IJumpPointHandler)m_customJumpPointHandlers[zonePoint.ClassType];

                // check for db change to update cached handler
                if (customHandler != null && customHandler.GetType().FullName != zonePoint.ClassType)
                {
                    customHandler = null;
                }

                if (customHandler == null)
                {
                    //Dinberg - Instances need to use a special handler. This is because some instances will result
                    //in duplicated zonepoints, such as if Tir Na Nog were to be instanced for a quest.
                    string type = player.CurrentRegion.IsInstance
                                                ? "DOL.GS.ServerRules.InstanceDoorJumpPoint"
                                                : zonePoint.ClassType;
                    Type t = ScriptMgr.GetType(type);

                    if (t == null)
                    {
                        Log.ErrorFormat("jump point {0}: class {1} not found!", zonePoint.Id, zonePoint.ClassType);
                    }
                    else if (!typeof(IJumpPointHandler).IsAssignableFrom(t))
                    {
                        Log.ErrorFormat("jump point {0}: class {1} must implement IJumpPointHandler interface!", zonePoint.Id,
                                        zonePoint.ClassType);
                    }
                    else
                    {
                        try
                        {
                            customHandler = (IJumpPointHandler)Activator.CreateInstance(t);
                        }
                        catch (Exception e)
                        {
                            customHandler = null;
                            Log.Error(
                                string.Format("jump point {0}: error creating a new instance of jump point handler {1}", zonePoint.Id,
                                              zonePoint.ClassType), e);
                        }
                    }
                }

                if (customHandler != null)
                {
                    m_customJumpPointHandlers[zonePoint.ClassType] = customHandler;
                }
            }

            new RegionChangeRequestHandler(player, zonePoint, customHandler).Start(1);
        }
        private int CheckCharacterForUpdates(GameClient client, GSPacketIn packet, DOLCharacters character, string charName, byte customizationMode)
        {
            int newModel = character.CurrentModel;

            if (customizationMode == 1 || customizationMode == 2 || customizationMode == 3)
            {
                bool flagChangedStats = false;
                character.EyeSize = (byte)packet.ReadByte();
                character.LipSize = (byte)packet.ReadByte();
                character.EyeColor = (byte)packet.ReadByte();
                character.HairColor = (byte)packet.ReadByte();
                character.FaceType = (byte)packet.ReadByte();
                character.HairStyle = (byte)packet.ReadByte();
                packet.Skip(3);
                character.MoodType = (byte)packet.ReadByte();
                packet.Skip(89); // Skip location string, race string, classe string, level ,class ,realm and startRaceGender
                newModel = packet.ReadShortLowEndian(); //read new model

                if (customizationMode != 3 && client.Version >= GameClient.eClientVersion.Version189)
                {
                    packet.Skip(6); // Region ID + character Internal ID
                    int[] stats = new int[8];
                    stats[0] = (byte)packet.ReadByte(); // Strength
                    stats[2] = (byte)packet.ReadByte(); // Dexterity
                    stats[1] = (byte)packet.ReadByte(); // Constitution
                    stats[3] = (byte)packet.ReadByte(); // Quickness
                    stats[4] = (byte)packet.ReadByte(); // Intelligence
                    stats[5] = (byte)packet.ReadByte(); // Piety
                    stats[6] = (byte)packet.ReadByte(); // Empathy
                    stats[7] = (byte)packet.ReadByte(); // Charisma

                    packet.Skip(43);// armor models/armor color/weapon models/active weapon slots/siZone
                    if (client.Version >= GameClient.eClientVersion.Version199)
                    {
                        // skip 4 bytes added in 1.99
                        packet.Skip(4);
                    }

                    // what is this?
                    byte newConstitution = (byte)packet.ReadByte();
                    if (newConstitution > 0 && newConstitution < 255) // added 255 check, still not sure why this is here - tolakram
                        stats[1] = newConstitution;

                    flagChangedStats |= stats[0] != character.Strength;
                    flagChangedStats |= stats[1] != character.Constitution;
                    flagChangedStats |= stats[2] != character.Dexterity;
                    flagChangedStats |= stats[3] != character.Quickness;
                    flagChangedStats |= stats[4] != character.Intelligence;
                    flagChangedStats |= stats[5] != character.Piety;
                    flagChangedStats |= stats[6] != character.Empathy;
                    flagChangedStats |= stats[7] != character.Charisma;

                    //
                    // !! Stat changes disabled by Tolakram until someone figures out why this can create invalid stats !!
                    //
                    flagChangedStats = false;

                    if (flagChangedStats)
                    {
                        ICharacterClass charClass = ScriptMgr.FindCharacterClass(character.Class);

                        if (charClass != null)
                        {
                            int points = 0;
                            int[] leveledStats = new int[8];
                            int[] raceStats = new int[8];
                            bool valid = true;
                            for (int j = 0; j < 8; j++)
                            {
                                eStat stat = (eStat)ValidateCharacter.eStatIndex[j];
                                raceStats[j] = ValidateCharacter.STARTING_STATS[character.Race][j];
                                for (int level = character.Level; level > 5; level--)
                                {
                                    if (charClass.PrimaryStat != eStat.UNDEFINED && charClass.PrimaryStat == stat)
                                    {
                                        leveledStats[j]++;
                                    }
                                    if (charClass.SecondaryStat != eStat.UNDEFINED && charClass.SecondaryStat == stat)
                                    {
                                        if ((level - 6) % 2 == 0)
                                            leveledStats[j]++;
                                    }
                                    if (charClass.TertiaryStat != eStat.UNDEFINED && charClass.TertiaryStat == stat)
                                    {
                                        if ((level - 6) % 3 == 0)
                                            leveledStats[j]++;
                                    }
                                }

                                int result = stats[j] - leveledStats[j] - raceStats[j];

                                bool validBeginStat = result >= 0;
                                int pointsUsed = result;
                                string statCategory = "";

                                if (charClass.PrimaryStat != eStat.UNDEFINED && charClass.PrimaryStat == stat)
                                    statCategory = "1)";
                                if (charClass.SecondaryStat != eStat.UNDEFINED && charClass.SecondaryStat == stat)
                                    statCategory = "2)";
                                if (charClass.TertiaryStat != eStat.UNDEFINED && charClass.TertiaryStat == stat)
                                    statCategory = "3)";

                                pointsUsed += Math.Max(0, result - 10); //two points used
                                pointsUsed += Math.Max(0, result - 15); //three points used

                                log.Info(string.Format("{0,-2} {1,-3}:{2, 3} {3,3} {4,3} {5,3} {6,2} {7} {8}",
                                                       statCategory,
                                                       (stat == eStat.STR) ? "STR" : stat.ToString(),
                                                       stats[j],
                                                       leveledStats[j],
                                                       stats[j] - leveledStats[j],
                                                       raceStats[j],
                                                       result,
                                                       pointsUsed,
                                                       (validBeginStat) ? "" : "Not Valid"));

                                points += pointsUsed;

                                if (!validBeginStat)
                                {
                                    valid = false;
                                    if (client.Account.PrivLevel == 1)
                                    {
                                        if (ServerProperties.Properties.BAN_HACKERS)
                                        {
                                            DBBannedAccount b = new DBBannedAccount();
                                            b.Author = "SERVER";
                                            b.Ip = client.TcpEndpointAddress;
                                            b.Account = client.Account.Name;
                                            b.DateBan = DateTime.Now;
                                            b.Type = "B";
                                            b.Reason = String.Format("Autoban Hack char update : Wrong {0} point:{1}", (stat == eStat.STR) ? "STR" : stat.ToString(), result);
                                            GameServer.Database.AddObject(b);
                                            GameServer.Database.SaveObject(b);
                                            GameServer.Instance.LogCheatAction(b.Reason + ". Account: " + b.Account);
                                        }

                                        client.Disconnect();
                                        return 1;
                                    }
                                }
                            }

                            if (valid)
                            {
                                character.Strength = (byte)stats[0];
                                character.Constitution = (byte)stats[1];
                                character.Dexterity = (byte)stats[2];
                                character.Quickness = (byte)stats[3];
                                character.Intelligence = (byte)stats[4];
                                character.Piety = (byte)stats[5];
                                character.Empathy = (byte)stats[6];
                                character.Charisma = (byte)stats[7];

                                DOLCharacters[] chars = client.Account.Characters;

                                for (int z = 0; z < chars.Length; z++)
                                {
                                    if (chars[z].Name != character.Name) continue;

                                    //Log.Error(string.Format("found activePlayer:[{0}] {1} {2}", client.ActiveCharIndex, client.Player.Name, character.Name));

                                    if (log.IsInfoEnabled)
                                        log.Info(String.Format("Character {0} updated in cache!\n", charName));

                                    if (client.Player != null)
                                    {
                                        client.Player.DBCharacter.Strength = (byte)stats[0];
                                        client.Player.DBCharacter.Constitution = (byte)stats[1];
                                        client.Player.DBCharacter.Dexterity = (byte)stats[2];
                                        client.Player.DBCharacter.Quickness = (byte)stats[3];
                                        client.Player.DBCharacter.Intelligence = (byte)stats[4];
                                        client.Player.DBCharacter.Piety = (byte)stats[5];
                                        client.Player.DBCharacter.Empathy = (byte)stats[6];
                                        client.Player.DBCharacter.Charisma = (byte)stats[7];
                                    }

                                    client.Account.Characters[z].Strength = (byte)stats[0];
                                    client.Account.Characters[z].Constitution = (byte)stats[1];
                                    client.Account.Characters[z].Dexterity = (byte)stats[2];
                                    client.Account.Characters[z].Quickness = (byte)stats[3];
                                    client.Account.Characters[z].Intelligence = (byte)stats[4];
                                    client.Account.Characters[z].Piety = (byte)stats[5];
                                    client.Account.Characters[z].Empathy = (byte)stats[6];
                                    client.Account.Characters[z].Charisma = (byte)stats[7];
                                }
                            }
                        }
                        else
                        {
                            if (log.IsErrorEnabled)
                                log.Error("No CharacterClass with ID " + character.Class + " found");
                        }
                    }
                }
                else
                {
                    packet.Skip(58); // skip all other things
                    if (client.Version >= GameClient.eClientVersion.Version199)
                    {
                        // skip 4 bytes added in 1.99
                        packet.Skip(4);
                    }
                }

                if (customizationMode == 2) // change player customization
                {
                    if (client.Account.PrivLevel == 1 && ((newModel >> 11) & 3) == 0) // Player size must be > 0 (from 1 to 3)
                    {
                        DBBannedAccount b = new DBBannedAccount();
                        b.Author = "SERVER";
                        b.Ip = client.TcpEndpointAddress;
                        b.Account = client.Account.Name;
                        b.DateBan = DateTime.Now;
                        b.Type = "B";
                        b.Reason = String.Format("Autoban Hack char update : zero character size in model:{0}", newModel);
                        GameServer.Database.AddObject(b);
                        GameServer.Database.SaveObject(b);
                        GameServer.Instance.LogCheatAction(b.Reason + ". Account: " + b.Account);
                        client.Disconnect();
                        return 1;
                    }

                    if ((ushort)newModel != character.CreationModel)
                    {
                        character.CurrentModel = newModel;
                    }

                    character.CustomisationStep = 2; // disable config button

                    GameServer.Database.SaveObject(character);

                    if (log.IsInfoEnabled)
                        log.Info(String.Format("Character {0} face proprieties configured by account {1}!\n", charName, client.Account.Name));
                }
                else if (customizationMode == 3) //auto config -- seems someone thinks this is not possible?
                {
                    character.CustomisationStep = 3; // enable config button to player

                    GameServer.Database.SaveObject(character);

                    //if (log.IsInfoEnabled)
                    //	log.Info(String.Format("Character {0} face proprieties auto updated!\n", charName));
                }
                else if (customizationMode == 1 && flagChangedStats) //changed stat only for 1.89+
                {
                    GameServer.Database.SaveObject(character);

                    if (log.IsInfoEnabled)
                        log.Info(String.Format("Character {0} stat updated!\n", charName));
                }
            }

            return 1;
        }
        private void CreateCharacter(GameClient client, GSPacketIn packet, string charName, int accountSlot)
        {
            Account account = client.Account;
            DOLCharacters ch = new DOLCharacters();
            ch.AccountName = account.Name;
            ch.Name = charName;

            if (packet.ReadByte() == 0x01)
            {
                ch.EyeSize = (byte)packet.ReadByte();
                ch.LipSize = (byte)packet.ReadByte();
                ch.EyeColor = (byte)packet.ReadByte();
                ch.HairColor = (byte)packet.ReadByte();
                ch.FaceType = (byte)packet.ReadByte();
                ch.HairStyle = (byte)packet.ReadByte();
                packet.Skip(3);
                ch.MoodType = (byte)packet.ReadByte();
                ch.CustomisationStep = 2; // disable config button
                packet.Skip(13);
                log.Debug("Disable Config Button");
            }
            else
            {
                packet.Skip(23);
            }

            packet.Skip(24); //Location String
            ch.LastName = "";
            ch.GuildID = "";
            packet.Skip(24); //Skip class name
            packet.Skip(24); //Skip race name
            ch.Level = packet.ReadByte(); //not safe!
            ch.Level = 1;
            ch.Class = packet.ReadByte();
            if (ServerProperties.Properties.START_AS_BASE_CLASS)
            {
                ch.Class = RevertClass(ch);
            }
            ch.Realm = packet.ReadByte();

            if (log.IsDebugEnabled)
                log.Debug("Creation " + client.Version + " character, class:" + ch.Class + ", realm:" + ch.Realm);

            // Is class disabled ?
            int occurences = 0;
            List<string> disabled_classes = Properties.DISABLED_CLASSES.SplitCSV(true);
            occurences = (from j in disabled_classes
                          where j == ch.Class.ToString()
                          select j).Count();

            if (occurences > 0 && (ePrivLevel)client.Account.PrivLevel == ePrivLevel.Player)
            {
                log.Debug("Client " + client.Account.Name + " tried to create a disabled classe: " + (eCharacterClass)ch.Class);
                client.Out.SendCharacterOverview((eRealm)ch.Realm);
                return;
            }

            if (client.Version >= GameClient.eClientVersion.Version193)
            {
                ValidateCharacter.init_post193_tables();
            }
            else
            {
                ValidateCharacter.init_pre193_tables();
            }

            if (!Enum.IsDefined(typeof(eCharacterClass), (eCharacterClass)ch.Class))
            {
                log.Error(client.Account.Name + " tried to create a character with wrong class ID: " + ch.Class + ", realm:" + ch.Realm);
                if (ServerProperties.Properties.BAN_HACKERS)
                {
                    DBBannedAccount b = new DBBannedAccount();
                    b.Author = "SERVER";
                    b.Ip = client.TcpEndpointAddress;
                    b.Account = client.Account.Name;
                    b.DateBan = DateTime.Now;
                    b.Type = "B";
                    b.Reason = string.Format("Autoban character create class: id:{0} realm:{1} name:{2} account:{3}", ch.Class, ch.Realm, ch.Name, account.Name);
                    GameServer.Database.AddObject(b);
                    GameServer.Database.SaveObject(b);
                    GameServer.Instance.LogCheatAction(b.Reason + ". Account: " + b.Account);
                    client.Disconnect();
                }
                return;
            }

            ch.AccountSlot = accountSlot + ch.Realm * 100;

            //The following byte contains
            //1bit=start location ... in ShroudedIsles you can choose ...
            //1bit=first race bit
            //1bit=unknown
            //1bit=gender (0=male, 1=female)
            //4bit=race
            byte startRaceGender = (byte)packet.ReadByte();

            ch.Race = (startRaceGender & 0x0F) + ((startRaceGender & 0x40) >> 2);

            List<string> disabled_races = new List<string>(Properties.DISABLED_RACES.SplitCSV(true));
            occurences = (from j in disabled_races
                          where j == ch.Race.ToString()
                          select j).Count();
            if (occurences > 0 && (ePrivLevel)client.Account.PrivLevel == ePrivLevel.Player)
            {
                log.Debug("Client " + client.Account.Name + " tried to create a disabled race: " + (eRace)ch.Race);
                client.Out.SendCharacterOverview((eRealm)ch.Realm);
                return;
            }

            ch.Gender = ((startRaceGender >> 4) & 0x01);

            bool siStartLocation = ((startRaceGender >> 7) != 0);

            ch.CreationModel = packet.ReadShortLowEndian();
            ch.CurrentModel = ch.CreationModel;
            ch.Region = packet.ReadByte();
            packet.Skip(1); //TODO second byte of region unused currently
            packet.Skip(4); //TODO Unknown Int / last used?

            ch.Strength = (byte)packet.ReadByte();
            ch.Dexterity = (byte)packet.ReadByte();
            ch.Constitution = (byte)packet.ReadByte();
            ch.Quickness = (byte)packet.ReadByte();
            ch.Intelligence = (byte)packet.ReadByte();
            ch.Piety = (byte)packet.ReadByte();
            ch.Empathy = (byte)packet.ReadByte();
            ch.Charisma = (byte)packet.ReadByte();

            packet.Skip(44); //TODO equipment

            if (client.Version >= GameClient.eClientVersion.Version199)
            {
                // skip 4 bytes added in 1.99
                packet.Skip(4);
            }

            // log.DebugFormat("STR {0}, CON {1}, DEX {2}, QUI {3}, INT {4}, PIE {5}, EMP {6}, CHA {7}", ch.Strength, ch.Constitution, ch.Dexterity, ch.Quickness, ch.Intelligence, ch.Piety, ch.Empathy, ch.Charisma);

            // check if client tried to create invalid char
            if (!ValidateCharacter.IsCharacterValid(ch))
            {
                if (log.IsWarnEnabled)
                {
                    log.Warn(ch.AccountName + " tried to create invalid character:" +
                             "\nchar name=" + ch.Name + ", gender=" + ch.Gender + ", race=" + ch.Race + ", realm=" + ch.Realm + ", class=" + ch.Class + ", region=" + ch.Region +
                             "\nstr=" + ch.Strength + ", con=" + ch.Constitution + ", dex=" + ch.Dexterity + ", qui=" + ch.Quickness + ", int=" + ch.Intelligence + ", pie=" + ch.Piety + ", emp=" + ch.Empathy + ", chr=" + ch.Charisma);
                }

                // This is not live like but unfortunately we are missing code / packet support to stay on character create screen if something is invalid
                client.Out.SendCharacterOverview((eRealm)ch.Realm);
                return;
            }

            ch.CreationDate = DateTime.Now;

            ch.Endurance = 100;
            ch.MaxEndurance = 100;
            ch.Concentration = 100;
            ch.MaxSpeed = GamePlayer.PLAYER_BASE_SPEED;

            #region Starting Locations

            //if the server property for disable tutorial is set, we load in the classic starting locations
            if (ch.Region == 27 && ServerProperties.Properties.DISABLE_TUTORIAL)
            {
                switch (ch.Realm)
                {
                    case 1: ch.Region = 1; break;
                    case 2: ch.Region = 100; break;
                    case 3: ch.Region = 200; break;
                }
            }

            ch.Xpos = 505603;
            ch.Ypos = 494709;
            ch.Zpos = 2463;
            ch.Direction = 5947;

            if (ch.Region == 51 && ch.Realm == 1)//Albion ShroudedIsles start point (I hope)
            {
                ch.Xpos = 526252;
                ch.Ypos = 542415;
                ch.Zpos = 3165;
                ch.Direction = 5286;
            }
            if (ch.Region != 51 && ch.Realm == 1)//Albion start point (Church outside Camelot/humberton)
            {
                ch.Xpos = 505603;
                ch.Ypos = 494709;
                ch.Zpos = 2463;
                ch.Direction = 5947;
                //ch.Region = 1;
                //DOLConsole.WriteLine(String.Format("Character ClassName:"+ch.ClassName+" created!"));
                //DOLConsole.WriteLine(String.Format("Character RaceName:"+ch.RaceName+" created!"));
            }
            if (ch.Region == 151 && ch.Realm == 2)//Midgard ShroudedIsles start point
            {
                ch.Xpos = 293720;
                ch.Ypos = 356408;
                ch.Zpos = 3488;
                ch.Direction = 6670;
            }
            if (ch.Region != 151 && ch.Realm == 2)//Midgard start point (Fort Atla)
            {
                ch.Xpos = 749103;
                ch.Ypos = 815835;
                ch.Zpos = 4408;
                ch.Direction = 7915;
                //ch.Region = 100;
                //DOLConsole.WriteLine(String.Format("Character ClassName:"+ch.ClassName+" created!"));
                //DOLConsole.WriteLine(String.Format("Character RaceName:"+ch.RaceName+" created!"));
            }
            if (ch.Region == 181 && ch.Realm == 3)//Hibernia ShroudedIsles start point
            {
                ch.Xpos = 426483;
                ch.Ypos = 440626;
                ch.Zpos = 5952;
                ch.Direction = 2403;
            }
            if (ch.Region != 181 && ch.Realm == 3)//Hibernia start point (Mag Mel)
            {
                ch.Xpos = 345900;
                ch.Ypos = 490867;
                ch.Zpos = 5200;
                ch.Direction = 4826;
                //ch.Region = 200;
                //DOLConsole.WriteLine(String.Format("Character ClassName:"+ch.ClassName+" created!"));
                //DOLConsole.WriteLine(String.Format("Character RaceName:"+ch.RaceName+" created!"));
            }

            // chars are bound on creation
            ch.BindRegion = ch.Region;
            ch.BindHeading = ch.Direction;
            ch.BindXpos = ch.Xpos;
            ch.BindYpos = ch.Ypos;
            ch.BindZpos = ch.Zpos;

            #endregion Starting Locations

            #region starting guilds

            if (account.PrivLevel == 1 && Properties.STARTING_GUILD)
            {
                switch (ch.Realm)
                {
                    case 1:
                        switch (ServerProperties.Properties.SERV_LANGUAGE)
                        {
                            case "EN":
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Clan Cotswold");
                                break;
                            case "DE":
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Klan Cotswold");
                                break;
                            default:
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Clan Cotswold");
                                break;
                        }
                        break;
                    case 2:
                        switch (ServerProperties.Properties.SERV_LANGUAGE)
                        {
                            case "EN":
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Mularn Protectors");
                                break;
                            case "DE":
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Beschützer von Mularn");
                                break;
                            default:
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Mularn Protectors");
                                break;
                        }
                        break;
                    case 3:
                        switch (ServerProperties.Properties.SERV_LANGUAGE)
                        {
                            case "EN":
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Tir na Nog Adventurers");
                                break;
                            case "DE":
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Tir na Nog-Abenteurer");
                                break;
                            default:
                                ch.GuildID = GuildMgr.GuildNameToGuildID("Tir na Nog Adventurers");
                                break;
                        }
                        break;
                    default: break;
                }

                if (ch.GuildID != "")
                    ch.GuildRank = 8;
            }

            #endregion starting guilds

            if (Properties.STARTING_BPS > 0)
                ch.BountyPoints = Properties.STARTING_BPS;

            if (Properties.STARTING_MONEY > 0)
            {
                long value = Properties.STARTING_MONEY;
                ch.Copper = Money.GetCopper(value);
                ch.Silver = Money.GetSilver(value);
                ch.Gold = Money.GetGold(value);
                ch.Platinum = Money.GetPlatinum(value);
            }

            if (Properties.STARTING_REALM_LEVEL > 0)
            {
                int realmLevel = Properties.STARTING_REALM_LEVEL;
                long rpamount = 0;
                if (realmLevel < GamePlayer.REALMPOINTS_FOR_LEVEL.Length)
                    rpamount = GamePlayer.REALMPOINTS_FOR_LEVEL[realmLevel];

                // thanks to Linulo from http://daoc.foren.4players.de/viewtopic.php?t=40839&postdays=0&postorder=asc&start=0
                if (rpamount == 0)
                    rpamount = (long)(25.0 / 3.0 * (realmLevel * realmLevel * realmLevel) - 25.0 / 2.0 * (realmLevel * realmLevel) + 25.0 / 6.0 * realmLevel);

                ch.RealmPoints = rpamount;
                ch.RealmLevel = realmLevel;
                ch.RealmSpecialtyPoints = realmLevel;
            }

            ch.RespecAmountRealmSkill += 2;

            SetBasicCraftingForNewCharacter(ch);

            //Save the character in the database
            GameServer.Database.AddObject(ch);
            //Fire the character creation event
            GameEventMgr.Notify(DatabaseEvent.CharacterCreated, null, new CharacterEventArgs(ch, client));
            //add equipment
            StartupEquipment.AddEquipment(ch);
            //write changes
            GameServer.Database.SaveObject(ch);

            // Log creation
            AuditMgr.AddAuditEntry(client, AuditType.Account, AuditSubtype.CharacterCreate, "", charName);

            client.Account.Characters = null;

            if (log.IsInfoEnabled)
                log.Info(String.Format("Character {0} created!", charName));

            GameServer.Database.FillObjectRelations(client.Account);
            client.Out.SendCharacterOverview((eRealm)ch.Realm);

            return;
        }
        public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            ushort     id     = client.Version >= GameClient.eClientVersion.Version1126 ? packet.ReadShortLowEndian() : packet.ReadShort();
            GameClient target = WorldMgr.GetClientFromID(id);

            if (target == null)
            {
                if (Log.IsWarnEnabled)
                {
                    Log.Warn($"Client {client.SessionID}:{client.TcpEndpointAddress} account {(client.Account == null ? "null" : client.Account.Name)} requested invalid client {id} --- disconnecting");
                }

                client.Disconnect();
                return;
            }

            // DOLConsole.WriteLine("player creation request "+target.Player.Name);
            if (target.IsPlaying && target.Player != null && target.Player.ObjectState == GameObject.eObjectState.Active)
            {
                client.Out.SendPlayerCreate(target.Player);
                client.Out.SendLivingEquipmentUpdate(target.Player);
            }
        }