Example #1
0
        public static void BanAccount(this GameClient client, string reason)
        {
			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 = reason;
			GameServer.Database.AddObject(b);
			GameServer.Database.SaveObject(b);
			GameServer.Instance.LogCheatAction(string.Format("{1}. Client Account: {0}", client.Account.Name, b.Reason));
        }
Example #2
0
		public void OnCommand(GameClient client, string[] args)
		{
			if (args.Length < 3)
			{
				DisplaySyntax(client);
				return;
			}

			GameClient gc = null;

			if (args[2].StartsWith("#"))
			{
				try
				{
					int sessionID = Convert.ToInt32(args[1].Substring(1));
					gc = WorldMgr.GetClientFromID(sessionID);
				}
				catch
				{
					DisplayMessage(client, "Invalid client ID");
				}
			}
			else
			{
				gc = WorldMgr.GetClientByPlayerName(args[2], false, false);
			}

			Account acc = gc != null ? gc.Account : GameServer.Database.SelectObjects<Account>("`Name` LIKE @Name", new QueryParameter("@Name", args[2])).FirstOrDefault();
			if (acc == null)
			{
				client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.Ban.UnableToFindPlayer"), eChatType.CT_System, eChatLoc.CL_SystemWindow);
				return;
			}

			if (client.Account.PrivLevel < acc.PrivLevel)
			{
				DisplayMessage(client, "Your privlevel is not high enough to ban this player.");
				return;
			}

			if (client.Account.Name == acc.Name)
			{
				DisplayMessage(client, "Your can't ban yourself!");
				return;
			}

			try
			{
				DBBannedAccount b = new DBBannedAccount
				                    {
				                    	DateBan = DateTime.Now,
				                    	Author = client.Player.Name,
				                    	Ip = acc.LastLoginIP,
				                    	Account = acc.Name
				                    };

				if (args.Length >= 4)
					b.Reason = String.Join(" ", args, 3, args.Length - 3);
				else
					b.Reason = "No Reason.";

				switch (args[1].ToLower())
				{
						#region Account
					case "account":
						var acctBans = GameServer.Database.SelectObjects<DBBannedAccount>("(`Type` = @TypeA OR `Type` = @TypeB) AND `Account` = @Account", new[] { new QueryParameter("@TypeA", "A"), new QueryParameter("@TypeB", "B"), new QueryParameter("@Account", acc.Name) });
						if (acctBans.Count > 0)
						{
							client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.Ban.AAlreadyBanned"), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
							return;
						}

						b.Type = "A";
						client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.Ban.ABanned", acc.Name), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
						break;
						#endregion Account
						#region IP
					case "ip":
						var ipBans = GameServer.Database.SelectObjects<DBBannedAccount>("(`Type` = @TypeI OR `Type` = @TypeB) AND `Ip` = @Ip", new[] { new QueryParameter("@TypeI", "I"), new QueryParameter("@TypeB", "B"), new QueryParameter("@Ip", acc.LastLoginIP) });
						if (ipBans.Count > 0)
						{
							client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.Ban.IAlreadyBanned"), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
							return;
						}

						b.Type = "I";
						client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.Ban.IBanned", acc.LastLoginIP), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
						break;
						#endregion IP
						#region Both
					case "both":
						var acctIpBans = GameServer.Database.SelectObjects<DBBannedAccount>("`Type` = @Type AND `Account` = @Account AND `Ip` = @Ip", new[] { new QueryParameter("@Type", "B"), new QueryParameter("@Account", acc.Name), new QueryParameter("@Ip", acc.LastLoginIP) });
						if (acctIpBans.Count > 0)
						{
							client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.Ban.BAlreadyBanned"), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
							return;
						}

						b.Type = "B";
						client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.Ban.BBanned", acc.Name, acc.LastLoginIP), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
						break;
						#endregion Both
						#region Default
					default:
						{
							DisplaySyntax(client);
							return;
						}
						#endregion Default
				}
				GameServer.Database.AddObject(b);

				if (log.IsInfoEnabled)
					log.Info("Ban added [" + args[1].ToLower() + "]: " + acc.Name + "(" + acc.LastLoginIP + ")");
				return;
			}
			catch (Exception e)
			{
				if (log.IsErrorEnabled)
					log.Error("/ban Exception", e);
			}

			// if not returned here, there is an error
			DisplaySyntax(client);
		}
Example #3
0
		public void OnCommand(GameClient client, string[] args)
		{
			if (args.Length < 3)
			{
				DisplaySyntax(client);
				return;
			}

			GameClient gc = null;

			if (args[1].StartsWith("#"))
			{
				try
				{
					int sessionID = Convert.ToInt32(args[1].Substring(1));
					gc = WorldMgr.GetClientFromID(sessionID);
				}
				catch
				{
					DisplayMessage(client, "Invalid client ID");
				}
			}
			else
			{
				gc = WorldMgr.GetClientByPlayerName(args[1], false, false);
			}

			if (gc == null)
			{
				client.Out.SendMessage(LanguageMgr.GetTranslation(client, "GMCommands.Ban.UnableToFindPlayer"), eChatType.CT_System, eChatLoc.CL_SystemWindow);
				return;
			}

			if (client.Account.PrivLevel < gc.Account.PrivLevel)
			{
				DisplayMessage(client, "Your privlevel is not high enough to ban this player.");
				return;
			}

			if (client == gc)
			{
				DisplayMessage(client, "Your can't ban yourself!");
				return;
			}

			try
			{
				DBBannedAccount b = new DBBannedAccount();
				string accip = gc.TcpEndpointAddress;
				string accname = GameServer.Database.Escape(gc.Account.Name);
				string reason;

				if (args.Length >= 4)
					reason = String.Join(" ", args, 2, args.Length - 2);
				else reason = "No Reason.";

				switch (args[1].ToLower())
				{
						#region Account
					case "account":
						var acctBans = GameServer.Database.SelectObjects<DBBannedAccount>("((Type='A' OR Type='B') AND Account ='" + GameServer.Database.Escape(accname) + "')");
						if (acctBans.Count > 0)
						{
							client.Out.SendMessage(LanguageMgr.GetTranslation(client, "GMCommands.Ban.AAlreadyBanned"), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
							return;
						}

						b.Type = "A";
						client.Out.SendMessage(LanguageMgr.GetTranslation(client, "GMCommands.Ban.ABanned", accname), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
						break;
						#endregion Account
						#region IP
					case "ip":
						var ipBans = GameServer.Database.SelectObjects<DBBannedAccount>("((Type='I' OR Type='B') AND Ip ='" + GameServer.Database.Escape(accip) + "')");
						if (ipBans.Count > 0)
						{
							client.Out.SendMessage(LanguageMgr.GetTranslation(client, "GMCommands.Ban.IAlreadyBanned"), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
							return;
						}

						b.Type = "I";
						client.Out.SendMessage(LanguageMgr.GetTranslation(client, "GMCommands.Ban.IBanned", accip), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
						break;
						#endregion IP
						#region Both
					case "both":
						var acctIpBans = GameServer.Database.SelectObjects<DBBannedAccount>("Type='B' AND Account ='" + GameServer.Database.Escape(accname) + "' AND Ip ='" + GameServer.Database.Escape(accip) + "'");
						if (acctIpBans.Count > 0)
						{
							client.Out.SendMessage(LanguageMgr.GetTranslation(client, "GMCommands.Ban.BAlreadyBanned"), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
							return;
						}

						b.Type = "B";
						client.Out.SendMessage(LanguageMgr.GetTranslation(client, "GMCommands.Ban.BBanned", accname, accip), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
						break;
						#endregion Both
						#region Default
					default:
						{
							DisplaySyntax(client);
							return;
						}
						#endregion Default
				}

				b.Author = client.Player.DBCharacter.Name;
				b.Ip = accip;
				b.Account = accname;
				b.DateBan = DateTime.Now;
				b.Reason = reason;
				GameServer.Database.AddObject(b);
				GameServer.Database.SaveObject(b);

				if (log.IsInfoEnabled)
					log.Info("Ban added [" + args[1].ToLower() + "]: " + accname + "(" + accip + ")");
				return;
			}
			catch (Exception e)
			{
				if (log.IsErrorEnabled)
					log.Error("/ban Exception", e);
			}

			// if not returned here, there is an error
			DisplaySyntax(client);
		}
        //static int lastZ=int.MinValue;
        public void HandlePacket(GameClient client, GSPacketIn packet)
        {
            //Tiv: in very rare cases client send 0xA9 packet before sending S<=C 0xE8 player world initialize
            if ((client.Player.ObjectState != GameObject.eObjectState.Active) ||
                (client.ClientState != GameClient.eClientState.Playing))
                return;

            int environmentTick = Environment.TickCount;
            int packetVersion;
            if (client.Version > GameClient.eClientVersion.Version171)
            {
                packetVersion = 172;
            }
            else
            {
                packetVersion = 168;
            }

            int oldSpeed = client.Player.CurrentSpeed;

            //read the state of the player
            packet.Skip(2); //PID
            ushort data = packet.ReadShort();
            int speed = (data & 0x1FF);

            //			if(!GameServer.ServerRules.IsAllowedDebugMode(client)
            //				&& (speed > client.Player.MaxSpeed + SPEED_TOL))

            if ((data & 0x200) != 0)
                speed = -speed;

            if (client.Player.IsMezzed || client.Player.IsStunned)
            {
                // Nidel: updating client.Player.CurrentSpeed instead of speed
                client.Player.CurrentSpeed = 0;
            }
            else
            {
                client.Player.CurrentSpeed = (short)speed;
            }

            client.Player.IsStrafing = ((data & 0xe000) != 0);

            int realZ = packet.ReadShort();
            ushort xOffsetInZone = packet.ReadShort();
            ushort yOffsetInZone = packet.ReadShort();
            ushort currentZoneID;
            if (packetVersion == 168)
            {
                currentZoneID = (ushort)packet.ReadByte();
                packet.Skip(1); //0x00 padding for zoneID
            }
            else
            {
                currentZoneID = packet.ReadShort();
            }

            //Dinberg - Instance considerations.
            //Now this gets complicated, so listen up! We have told the client a lie when it comes to the zoneID.
            //As a result, every movement update, they are sending a lie back to us. Two liars could get confusing!

            //BUT, the lie we sent has a truth to it - the geometry and layout of the zone. As a result, the zones
            //x and y offsets will still actually be relevant to our current zone. And for the clones to have been
            //created, there must have been a real zone to begin with, of id == instanceZone.SkinID.

            //So, although our client is lying to us, and thinks its in another zone, that zone happens to coincide
            //exactly with the zone we are instancing - and so all the positions still ring true.

            //Philosophically speaking, its like looking in a mirror and saying 'Am I a reflected, or reflector?'
            //What it boils down to has no bearing whatsoever on the result of anything, so long as someone sitting
            //outside of the unvierse knows not to listen to whether you say which you are, and knows the truth to the
            //answer. Then, he need only know what you are doing ;)

            Zone newZone = WorldMgr.GetZone(currentZoneID);
            if (newZone == null)
            {
                if (client.Player == null) return;
                if (!client.Player.TempProperties.getProperty("isbeingbanned", false))
                {
                    if (log.IsErrorEnabled)
                        log.Error(client.Player.Name + "'s position in unknown zone! => " + currentZoneID);
                    GamePlayer player = client.Player;
                    player.TempProperties.setProperty("isbeingbanned", true);
                    player.MoveToBind();
                }

                return; // TODO: what should we do? player lost in space
            }

            // move to bind if player fell through the floor
            if (realZ == 0)
            {
                client.Player.MoveTo(
                    (ushort)client.Player.DBCharacter.BindRegion,
                    client.Player.DBCharacter.BindXpos,
                    client.Player.DBCharacter.BindYpos,
                    (ushort)client.Player.DBCharacter.BindZpos,
                    (ushort)client.Player.DBCharacter.BindHeading
                );
                return;
            }

            int realX = newZone.XOffset + xOffsetInZone;
            int realY = newZone.YOffset + yOffsetInZone;

            bool zoneChange = newZone != client.Player.LastPositionUpdateZone;
            if (zoneChange)
            {
                //If the region changes -> make sure we don't take any falling damage
                if (client.Player.LastPositionUpdateZone != null && newZone.ZoneRegion.ID != client.Player.LastPositionUpdateZone.ZoneRegion.ID)
                    client.Player.MaxLastZ = int.MinValue;

                // Update water level and diving flag for the new zone
                client.Out.SendPlayerPositionAndObjectID();
                zoneChange = true;

                /*
                 * "You have entered Burial Tomb."
                 * "Burial Tomb"
                 * "Current area is adjusted for one level 1 player."
                 * "Current area has a 50% instance bonus."
                 */

                string description = newZone.Description;
                string screenDescription = description;

                DataObject translation = LanguageMgr.GetTranslation(client, newZone);
                if (translation != null)
                {
                    if (!Util.IsEmpty(((DBLanguageZone)translation).Description))
                        description = ((DBLanguageZone)translation).Description;

                    if (!Util.IsEmpty(((DBLanguageZone)translation).ScreenDescription))
                        screenDescription = ((DBLanguageZone)translation).ScreenDescription;
                }

                client.Out.SendMessage(LanguageMgr.GetTranslation(client, "PlayerPositionUpdateHandler.Entered", description),
                                       eChatType.CT_System, eChatLoc.CL_SystemWindow);
                client.Out.SendMessage(screenDescription, eChatType.CT_ScreenCenterSmaller, eChatLoc.CL_SystemWindow);

                client.Player.LastPositionUpdateZone = newZone;
            }

            int coordsPerSec = 0;
            int jumpDetect = 0;
            int timediff = Environment.TickCount - client.Player.LastPositionUpdateTick;
            int distance = 0;

            if (timediff > 0)
            {
                distance = client.Player.LastPositionUpdatePoint.GetDistanceTo(new Point3D(realX, realY, realZ));
                coordsPerSec = distance * 1000 / timediff;

                if (distance < 100 && client.Player.LastPositionUpdatePoint.Z > 0)
                {
                    jumpDetect = realZ - client.Player.LastPositionUpdatePoint.Z;
                }
            }

            #region DEBUG

#if OUTPUT_DEBUG_INFO
			if (client.Player.LastPositionUpdatePoint.X != 0 && client.Player.LastPositionUpdatePoint.Y != 0)
			{
				log.Debug(client.Player.Name + ": distance = " + distance + ", speed = " + oldSpeed + ",  coords/sec=" + coordsPerSec);
			}
			if (jumpDetect > 0)
			{
				log.Debug(client.Player.Name + ": jumpdetect = " + jumpDetect);
			}
#endif

            #endregion DEBUG

            client.Player.LastPositionUpdateTick = Environment.TickCount;
            client.Player.LastPositionUpdatePoint.X = realX;
            client.Player.LastPositionUpdatePoint.Y = realY;
            client.Player.LastPositionUpdatePoint.Z = realZ;

            int tolerance = ServerProperties.Properties.CPS_TOLERANCE;

            if (client.Player.Steed != null && client.Player.Steed.MaxSpeed > 0)
            {
                tolerance += client.Player.Steed.MaxSpeed;
            }
            else if (client.Player.MaxSpeed > 0)
            {
                tolerance += client.Player.MaxSpeed;
            }

            if (client.Player.IsJumping)
            {
                coordsPerSec = 0;
                jumpDetect = 0;
                client.Player.IsJumping = false;
            }

            if (client.Player.CanFly == false && (coordsPerSec > tolerance || jumpDetect > ServerProperties.Properties.JUMP_TOLERANCE))
            {
                bool isHackDetected = true;

                if (coordsPerSec > tolerance)
                {
                    // check to see if CPS time tolerance is exceeded
                    int lastCPSTick = client.Player.TempProperties.getProperty<int>(LASTCPSTICK, 0);

                    if (environmentTick - lastCPSTick > ServerProperties.Properties.CPS_TIME_TOLERANCE)
                    {
                        isHackDetected = false;
                    }
                }

                if (isHackDetected)
                {
                    StringBuilder builder = new StringBuilder();
                    builder.Append("MOVEHACK_DETECT");
                    builder.Append(": CharName=");
                    builder.Append(client.Player.Name);
                    builder.Append(" Account=");
                    builder.Append(client.Account.Name);
                    builder.Append(" IP=");
                    builder.Append(client.TcpEndpointAddress);
                    builder.Append(" CPS:=");
                    builder.Append(coordsPerSec);
                    builder.Append(" JT=");
                    builder.Append(jumpDetect);
                    ChatUtil.SendDebugMessage(client, builder.ToString());

                    if (client.Account.PrivLevel == 1)
                    {
                        GameServer.Instance.LogCheatAction(builder.ToString());

                        if (ServerProperties.Properties.ENABLE_MOVEDETECT)
                        {
                            if (ServerProperties.Properties.BAN_HACKERS && false) // banning disabled until this technique is proven accurate
                            {
                                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 MOVEHACK:(CPS:{0}, JT:{1}) on player:{2}", coordsPerSec, jumpDetect, client.Player.Name);
                                GameServer.Database.AddObject(b);
                                GameServer.Database.SaveObject(b);

                                string message = "";

                                message = "You have been auto kicked and banned due to movement hack detection!";
                                for (int i = 0; i < 8; i++)
                                {
                                    client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow);
                                    client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow);
                                }

                                client.Out.SendPlayerQuit(true);
                                client.Player.SaveIntoDatabase();
                                client.Player.Quit(true);
                            }
                            else
                            {
                                string message = "";

                                message = "You have been auto kicked due to movement hack detection!";
                                for (int i = 0; i < 8; i++)
                                {
                                    client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow);
                                    client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow);
                                }

                                client.Out.SendPlayerQuit(true);
                                client.Player.SaveIntoDatabase();
                                client.Player.Quit(true);
                            }
                            client.Disconnect();
                            return;
                        }
                    }
                }

                client.Player.TempProperties.setProperty(LASTCPSTICK, environmentTick);
            }

            ushort headingflag = packet.ReadShort();
            client.Player.Heading = (ushort)(headingflag & 0xFFF);
            ushort flyingflag = packet.ReadShort();
            byte flags = (byte)packet.ReadByte();

            if (client.Player.X != realX || client.Player.Y != realY)
            {
                client.Player.TempProperties.setProperty(LASTMOVEMENTTICK, client.Player.CurrentRegion.Time);
            }
            client.Player.X = realX;
            client.Player.Y = realY;
            client.Player.Z = realZ;

            if (zoneChange)
            {
                // update client zone information for waterlevel and diving
                client.Out.SendPlayerPositionAndObjectID();
            }

            // used to predict current position, should be before
            // any calculation (like fall damage)
            client.Player.MovementStartTick = Environment.TickCount;

            // Begin ---------- New Area System -----------
            if (client.Player.CurrentRegion.Time > client.Player.AreaUpdateTick) // check if update is needed
            {
                IList oldAreas = client.Player.CurrentAreas;

                // Because we may be in an instance we need to do the area check from the current region
                // rather than relying on the zone which is in the skinned region.  - Tolakram

                IList newAreas = client.Player.CurrentRegion.GetAreasOfZone(newZone, client.Player);

                // Check for left areas
                if (oldAreas != null)
                {
                    foreach (IArea area in oldAreas)
                    {
                        if (!newAreas.Contains(area))
                        {
                            area.OnPlayerLeave(client.Player);
                        }
                    }
                }
                // Check for entered areas
                foreach (IArea area in newAreas)
                {
                    if (oldAreas == null || !oldAreas.Contains(area))
                    {
                        area.OnPlayerEnter(client.Player);
                    }
                }
                // set current areas to new one...
                client.Player.CurrentAreas = newAreas;
                client.Player.AreaUpdateTick = client.Player.CurrentRegion.Time + 2000; // update every 2 seconds
            }
            // End ---------- New Area System -----------

            client.Player.TargetInView = ((flags & 0x10) != 0);
            client.Player.GroundTargetInView = ((flags & 0x08) != 0);
            //7  6  5  4  3  2  1 0
            //15 14 13 12 11 10 9 8
            //                1 1

            const string SHLASTUPDATETICK = "SHPLAYERPOSITION_LASTUPDATETICK";
            const string SHLASTFLY = "SHLASTFLY_STRING";
            const string SHLASTSTATUS = "SHLASTSTATUS_STRING";
            int SHlastTick = client.Player.TempProperties.getProperty<int>(SHLASTUPDATETICK);
            int SHlastFly = client.Player.TempProperties.getProperty<int>(SHLASTFLY);
            int SHlastStatus = client.Player.TempProperties.getProperty<int>(SHLASTSTATUS);
            int SHcount = client.Player.TempProperties.getProperty<int>(SHSPEEDCOUNTER);
            int status = (data & 0x1FF ^ data) >> 8;
            int fly = (flyingflag & 0x1FF ^ flyingflag) >> 8;

            if (client.Player.IsJumping)
            {
                SHcount = 0;
            }

            if (SHlastTick != 0 && SHlastTick != environmentTick)
            {
                if (((SHlastStatus == status || (status & 0x8) == 0)) && ((fly & 0x80) != 0x80) && (SHlastFly == fly || (SHlastFly & 0x10) == (fly & 0x10) || !((((SHlastFly & 0x10) == 0x10) && ((fly & 0x10) == 0x0) && (flyingflag & 0x7FF) > 0))))
                {
                    if ((environmentTick - SHlastTick) < 400)
                    {
                        SHcount++;

                        if (SHcount > 1 && client.Account.PrivLevel > 1)
                        {
                            //Apo: ?? no idea how to name the first parameter for language translation: 1: ??, 2: {detected} ?, 3: {count} ?
                            client.Out.SendMessage(string.Format("SH: ({0}) detected: {1}, count {2}", 500 / (environmentTick - SHlastTick), environmentTick - SHlastTick, SHcount), eChatType.CT_Staff, eChatLoc.CL_SystemWindow);
                        }

                        if (SHcount % 5 == 0)
                        {
                            StringBuilder builder = new StringBuilder();
                            builder.Append("TEST_SH_DETECT[");
                            builder.Append(SHcount);
                            builder.Append("] (");
                            builder.Append(environmentTick - SHlastTick);
                            builder.Append("): CharName=");
                            builder.Append(client.Player.Name);
                            builder.Append(" Account=");
                            builder.Append(client.Account.Name);
                            builder.Append(" IP=");
                            builder.Append(client.TcpEndpointAddress);
                            GameServer.Instance.LogCheatAction(builder.ToString());

                            if (client.Account.PrivLevel > 1)
                            {
                                client.Out.SendMessage("SH: Logging SH cheat.", eChatType.CT_Damaged, eChatLoc.CL_SystemWindow);

                                if (SHcount >= ServerProperties.Properties.SPEEDHACK_TOLERANCE)
                                    client.Out.SendMessage("SH: Player would have been banned!", eChatType.CT_Damaged, eChatLoc.CL_SystemWindow);
                            }

                            if ((client.Account.PrivLevel == 1) && SHcount >= ServerProperties.Properties.SPEEDHACK_TOLERANCE)
                            {
                                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 SH:({0},{1}) on player:{2}", SHcount, environmentTick - SHlastTick, client.Player.Name);
                                    GameServer.Database.AddObject(b);
                                    GameServer.Database.SaveObject(b);

                                    string message = "";

                                    message = "You have been auto kicked and banned for speed hacking!";
                                    for (int i = 0; i < 8; i++)
                                    {
                                        client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow);
                                        client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow);
                                    }

                                    client.Out.SendPlayerQuit(true);
                                    client.Player.SaveIntoDatabase();
                                    client.Player.Quit(true);
                                }
                                else
                                {
                                    string message = "";

                                    message = "You have been auto kicked for speed hacking!";
                                    for (int i = 0; i < 8; i++)
                                    {
                                        client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_SystemWindow);
                                        client.Out.SendMessage(message, eChatType.CT_Help, eChatLoc.CL_ChatWindow);
                                    }

                                    client.Out.SendPlayerQuit(true);
                                    client.Player.SaveIntoDatabase();
                                    client.Player.Quit(true);
                                }
                                client.Disconnect();
                                return;
                            }
                        }
                    }
                    else
                    {
                        SHcount = 0;
                    }

                    SHlastTick = environmentTick;
                }
            }
            else
            {
                SHlastTick = environmentTick;
            }

            int state = ((data >> 10) & 7);
            client.Player.IsClimbing = (state == 7);
            client.Player.IsSwimming = (state == 1);
            if (state == 3 && client.Player.TempProperties.getProperty<object>(GamePlayer.DEBUG_MODE_PROPERTY, null) == null && !client.Player.CanFly) //debugFly on, but player not do /debug on (hack)
            {
                StringBuilder builder = new StringBuilder();
                builder.Append("HACK_FLY");
                builder.Append(": CharName=");
                builder.Append(client.Player.Name);
                builder.Append(" Account=");
                builder.Append(client.Account.Name);
                builder.Append(" IP=");
                builder.Append(client.TcpEndpointAddress);
                GameServer.Instance.LogCheatAction(builder.ToString());
                {
                    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 flying hack: on player:{0}", client.Player.Name);
                        GameServer.Database.AddObject(b);
                        GameServer.Database.SaveObject(b);
                    }
                    string message = "";

                    message = "Client Hack Detected!";
                    for (int i = 0; i < 6; i++)
                    {
                        client.Out.SendMessage(message, eChatType.CT_System, eChatLoc.CL_SystemWindow);
                        client.Out.SendMessage(message, eChatType.CT_System, eChatLoc.CL_ChatWindow);
                    }
                    client.Out.SendPlayerQuit(true);
                    client.Disconnect();
                    return;
                }
            }

            SHlastFly = fly;
            SHlastStatus = status;
            client.Player.TempProperties.setProperty(SHLASTUPDATETICK, SHlastTick);
            client.Player.TempProperties.setProperty(SHLASTFLY, SHlastFly);
            client.Player.TempProperties.setProperty(SHLASTSTATUS, SHlastStatus);
            client.Player.TempProperties.setProperty(SHSPEEDCOUNTER, SHcount);
            lock (client.Player.LastUniqueLocations)
            {
                GameLocation[] locations = client.Player.LastUniqueLocations;
                GameLocation loc = locations[0];
                if (loc.X != realX || loc.Y != realY || loc.Z != realZ || loc.RegionID != client.Player.CurrentRegionID)
                {
                    loc = locations[locations.Length - 1];
                    Array.Copy(locations, 0, locations, 1, locations.Length - 1);
                    locations[0] = loc;
                    loc.X = realX;
                    loc.Y = realY;
                    loc.Z = realZ;
                    loc.Heading = client.Player.Heading;
                    loc.RegionID = client.Player.CurrentRegionID;
                }
            }

            //**************//
            //FALLING DAMAGE//
            //**************//
            if (GameServer.ServerRules.CanTakeFallDamage(client.Player) && client.Player.IsSwimming == false)
            {
                int maxLastZ = client.Player.MaxLastZ;
                /* Are we on the ground? */
                if ((flyingflag >> 15) != 0)
                {
                    int safeFallLevel = client.Player.GetAbilityLevel(Abilities.SafeFall);
                    int fallSpeed = (flyingflag & 0xFFF) - 100 * safeFallLevel; // 0x7FF fall speed and 0x800 bit = fall speed overcaped
                    int fallMinSpeed = 400;
                    int fallDivide = 6;
                    if (client.Version >= GameClient.eClientVersion.Version188)
                    {
                        fallMinSpeed = 500;
                        fallDivide = 15;
                    }

                    int fallPercent = Math.Min(99, (fallSpeed - (fallMinSpeed + 1)) / fallDivide);

                    if (fallSpeed > fallMinSpeed)
                    {
                        client.Out.SendMessage(LanguageMgr.GetTranslation(client, "PlayerPositionUpdateHandler.FallingDamage"),
                        eChatType.CT_Damaged, eChatLoc.CL_SystemWindow);
                        client.Player.CalcFallDamage(fallPercent);
                    }

                    client.Player.MaxLastZ = client.Player.Z;
                }

                else
                {
                    // always set Z if on the ground
                    if (flyingflag == 0)
                        client.Player.MaxLastZ = client.Player.Z;
                    // set Z if in air and higher than old Z
                    else if (maxLastZ < client.Player.Z)
                        client.Player.MaxLastZ = client.Player.Z;
                }
            }
            //**************//

            byte[] con168 = packet.ToArray();
            //Riding is set here!
            if (client.Player.Steed != null && client.Player.Steed.ObjectState == GameObject.eObjectState.Active)
            {
                client.Player.Heading = client.Player.Steed.Heading;

                con168[2] = 0x18; // Set ride flag 00011000
                con168[3] = 0; // player speed = 0 while ride
                con168[12] = (byte)(client.Player.Steed.ObjectID >> 8); //heading = steed ID
                con168[13] = (byte)(client.Player.Steed.ObjectID & 0xFF);
                con168[14] = (byte)0;
                con168[15] = (byte)(client.Player.Steed.RiderSlot(client.Player)); // there rider slot this player
            }
            else if (!client.Player.IsAlive)
            {
                con168[2] &= 0xE3; //11100011
                con168[2] |= 0x14; //Set dead flag 00010100
            }
            //diving is set here
            con168[16] &= 0xFB; //11 11 10 11
            if ((con168[16] & 0x02) != 0x00)
            {
                client.Player.IsDiving = true;
                con168[16] |= 0x04;
            }
            else
                client.Player.IsDiving = false;

            con168[16] &= 0xFC; //11 11 11 00 cleared Wireframe & Stealth bits
            if (client.Player.IsWireframe)
            {
                con168[16] |= 0x01;
            }
            //stealth is set here
            if (client.Player.IsStealthed)
            {
                con168[16] |= 0x02;
            }

            con168[17] = (byte)((con168[17] & 0x80) | client.Player.HealthPercent);
            // zone ID has changed in 1.72, fix bytes 11 and 12
            byte[] con172 = (byte[])con168.Clone();
            if (packetVersion == 168)
            {
                // client sent v168 pos update packet, fix 172 version
                con172[10] = 0;
                con172[11] = con168[10];
            }
            else
            {
                // client sent v172 pos update packet, fix 168 version
                con168[10] = con172[11];
                con168[11] = 0;
            }

            GSUDPPacketOut outpak168 = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition));
            //Now copy the whole content of the packet
            outpak168.Write(con168, 0, 18/*con168.Length*/);
            outpak168.WritePacketLength();

            GSUDPPacketOut outpak172 = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition));
            //Now copy the whole content of the packet
            outpak172.Write(con172, 0, 18/*con172.Length*/);
            outpak172.WritePacketLength();

            //			byte[] pak168 = outpak168.GetBuffer();
            //			byte[] pak172 = outpak172.GetBuffer();
            //			outpak168 = null;
            //			outpak172 = null;
            GSUDPPacketOut outpak190 = null;

            foreach (GamePlayer player in client.Player.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE))
            {
                if (player == null)
                    continue;
                //No position updates for ourselves
                if (player == client.Player)
                    continue;
                //no position updates in different houses
                if ((client.Player.InHouse || player.InHouse) && player.CurrentHouse != client.Player.CurrentHouse)
                    continue;

                if (client.Player.MinotaurRelic != null)
                {
                    MinotaurRelic relic = client.Player.MinotaurRelic;
                    if (!relic.Playerlist.Contains(player) && player != client.Player)
                    {
                        relic.Playerlist.Add(player);
                        player.Out.SendMinotaurRelicWindow(client.Player, client.Player.MinotaurRelic.Effect, true);
                    }
                }

                if (!client.Player.IsStealthed || player.CanDetect(client.Player))
                {
                    //forward the position packet like normal!
                    if (player.Client.Version >= GameClient.eClientVersion.Version190)
                    {
                        if (outpak190 == null)
                        {
                            outpak190 = new GSUDPPacketOut(client.Out.GetPacketCode(eServerPackets.PlayerPosition));
                            outpak190.Write(con172, 0, 18/*con172.Length*/);
                            outpak190.WriteByte(client.Player.ManaPercent);
                            outpak190.WriteByte(client.Player.EndurancePercent);
                            outpak190.FillString(client.Player.CharacterClass.Name, 32);
                            // roleplay flag, if == 1, show name (RP) with gray color
                            if (client.Player.RPFlag)
                                outpak190.WriteByte(1);
                            else outpak190.WriteByte(0);
                            outpak190.WriteByte((con168.Length == 54) ? con168[53] : (byte)0); // send last byte for 190+ packets
                            outpak190.WritePacketLength();
                        }
                        player.Out.SendUDPRaw(outpak190);
                    }
                    else if (player.Client.Version >= GameClient.eClientVersion.Version172)
                        player.Out.SendUDPRaw(outpak172);
                    else
                        player.Out.SendUDPRaw(outpak168);
                }
                else
                    player.Out.SendObjectDelete(client.Player); //remove the stealthed player from view
            }

            if (client.Player.CharacterClass.ID == (int)eCharacterClass.Warlock)
            {
                //Send Chamber effect
                client.Player.Out.SendWarlockChamberEffect(client.Player);
            }

            //handle closing of windows
            //trade window
            if (client.Player.TradeWindow != null)
            {
                if (client.Player.TradeWindow.Partner != null)
                {
                    if (!client.Player.IsWithinRadius(client.Player.TradeWindow.Partner, WorldMgr.GIVE_ITEM_DISTANCE))
                        client.Player.TradeWindow.CloseTrade();
                }
            }
        }
		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;
		}
		public void HandlePacket(GameClient client, GSPacketIn packet)
		{
			string accountName = packet.ReadString(24);

			log.Debug("CharacterCreateRequestHandler for account " + accountName + " using version " + client.Version);

			if (!accountName.StartsWith(client.Account.Name))// TODO more correctly check, client send accountName as account-S, -N, -H (if it not fit in 20, then only account)
			{
				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 wrong Account '{0}'", GameServer.Database.Escape(accountName));
					GameServer.Database.AddObject(b);
					GameServer.Database.SaveObject(b);
					GameServer.Instance.LogCheatAction(b.Reason + ". Account: " + b.Account);
				}

				client.Disconnect();
				return;
			}

			if (client.Version >= GameClient.eClientVersion.Version1104)
			{
				packet.ReadIntLowEndian(); //unk - probably indicates customize or create
			}

			int charsCount = client.Version < GameClient.eClientVersion.Version173 ? 8 : 10;
			for (int i = 0; i < charsCount; i++)
			{
				string charName = packet.ReadString(24);

				//log.DebugFormat("Character[{0}] = {1}", i, charName);

				if (charName.Length == 0)
				{
					// 1.104+  if character is not in list but is in DB then delete the character
					if (client.Version >= GameClient.eClientVersion.Version1104)
					{
						CheckForDeletedCharacter(accountName, client, i);
					}

					//If the charname is empty, skip the other bytes
					packet.Skip(160);
					if (client.Version >= GameClient.eClientVersion.Version199)
					{
						// skip 4 bytes added in 1.99
						packet.Skip(4);
					}
				}
				else
				{
					// Graveen: changed the following to allow GMs to have special chars in their names (_,-, etc..)
					Regex nameCheck = new Regex("^[A-Z][a-zA-Z]");
					if (charName.Length < 3 || !nameCheck.IsMatch(charName))
					{
						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 bad CharName '{0}'", GameServer.Database.Escape(charName));
								GameServer.Database.AddObject(b);
								GameServer.Database.SaveObject(b);
								GameServer.Instance.LogCheatAction(b.Reason + ". Account: " + b.Account);
							}

							client.Disconnect();
							return;
						}
					}

					String select = String.Format("Name = '{0}'", GameServer.Database.Escape(charName));
					DOLCharacters character = GameServer.Database.SelectObject<DOLCharacters>(select);
					if (character != null)
					{
						if (character.AccountName != client.Account.Name)
						{
							if (Properties.BAN_HACKERS == true)
							{
								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 CharName '{0}' on wrong Account '{1}'", GameServer.Database.Escape(charName), GameServer.Database.Escape(client.Account.Name));
								GameServer.Database.AddObject(b);
								GameServer.Database.SaveObject(b);
								GameServer.Instance.LogCheatAction(string.Format(b.Reason + ". Client Account: {0}, DB Account: {1}", client.Account.Name, character.AccountName));
							}

							client.Disconnect();
							return;
						}

						byte customizationMode = (byte)packet.ReadByte();

						// log.DebugFormat("CustomizationMode = {0} for charName {1}", customizationMode, charName);

						// check for update to existing character
						CheckCharacterForUpdates(client, packet, character, charName, customizationMode);
					}
					else
					{
						// create new character and return
						CreateCharacter(client, packet, charName, i);
					}
				}
			}
		}
		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;
		}