[TIP]Fixing login freeze and MySQL problems on LOTF for sure!

04/28/2009 04:37 jkaton#1
Those who downloaded some sort of a LOTF source and get it to work, soon faces a problem: login freezes, portal freezes, etc. In the worst cases, even the character account data is corrupted. Well, as this is my first post on elitepvpers, I hope to do a rich contribution for ya all, because this forum helped me to create my own server and learn a new programming language.

Well, let's work:

What you need:
- some CO server source installed and running (if you are reading this, you already have it.)
- Visual C# Express (if you don't have yet, download from microsoft)

If u agree, I will not give u the fishes, but I will teach u how to fish, so u become able to do it anytime, ok? So in this we'll analyze some techniques:

1 - redundant connections
2 - close connections after use
3 - cut unnecessary sql queries
04/28/2009 04:48 jkaton#2
For LOTF, almost all SQL queries are in database.cs; open it in visual C# and you will know you are near one when u see a word containing mysql. Let's start with the connections. Find something similar to this:

Code:
public static bool Connect(string dbserver, string dbname, string user, string pass)
        {
            try
            {
                Connection = new MySqlConnection("Server='" + dbserver + "';Database='" + dbname + "';Username='" + user + "';Password='" + pass + "'");
                Connection.Open();
                return true;
            }
            catch (Exception Exc) { General.WriteLine(Exc.ToString()); return false; }
        }
Create a copy of this code block, just changing name, as below:

Code:
public static bool [b]Connect2[/b](string dbserver, string dbname, string user, string pass)
        {
            try
            {
                [b]Connection2[/b] = new MySqlConnection("Server='" + dbserver + "';Database='" + dbname + "';Username='" + user + "';Password='" + pass + "'");
                [b]Connection2[/b].Open();
                return true;
            }
            catch (Exception Exc) { General.WriteLine(Exc.ToString()); return false; }
        }
Now, u need to invoke this second connection in case the first fails. I will take as example the SaveChar method, but u must do this in all SQL queries:
04/28/2009 05:04 jkaton#3
In database.cs:

Code:
public static void SaveChar(Character Charr)
        {
            try
            {
                Charr.PackInventory();
                Charr.PackEquips();
                Charr.PackSkills();
                Charr.PackProfs();
                Charr.PackWarehouses();
                Charr.PackEnemies();
                Charr.PackFriends();
                if (ExternalDatabase.AllowQuerys)
                    ExternalDatabase.DatabaseQueue.Enqueue(new MySqlCommand("UPDATE `Characters` SET `CharName` = '" + Charr.Name + "', `Level` = " + Charr.Level + ",`Exp` = " + Charr.Exp + ",`GuildDonation` = " + Charr.GuildDonation + ",`Strength` = " + Charr.Str + ",`Agility` = " + Charr.Agi + ",`Vitality` = " + Charr.Vit + ",`Spirit` = " + Charr.Spi + ",`Job` = " + Charr.Job + ",`Model` = " + Charr.RealModel + ",`Money` = " + Charr.Silvers + ",`CPs` = " + Charr.CPs + ",`CurrentHP` = " + Charr.CurHP + ",`StatPoints` = " + Charr.StatP + ",`MyGuild` = " + Charr.GuildID + ",`GuildPos` = " + Charr.GuildPosition + ",`LocationMap` = " + Charr.LocMap + ",`LocationX` = " + Charr.LocX + ",`LocationY` = " + Charr.LocY + ",`Hair` = " + Charr.Hair + ",`Equipment` = '" + Charr.PackedEquips + "',`Inventory` = '" + Charr.PackedInventory + "',`PKPoints` = " + Charr.PKPoints + ",`PrevMap` = " + Charr.PrevMap + ", `Skills` = '" + Charr.PackedSkills + "', `Profs` = '" + Charr.PackedProfs + "',`RBCount` = " + Charr.RBCount + ",`Avatar` = " + Charr.Avatar + ",`WHMoney` = " + Charr.WHSilvers + ",`VP` = " + Charr.VP + ",`Warehouses` = '" + Charr.PackedWHs + "',`Friends` = '" + Charr.PackedFriends + "',`Enemies` = '" + Charr.PackedEnemies + "',`QuestMob` = '" + Charr.QuestMob + "',`QuestKO` = " + Charr.QuestKO + " WHERE `Account` = '" + Charr.MyClient.Account + "'", ExternalDatabase.Connection));
            }
            catch (Exception Exc) { General.WriteLine(Convert.ToString(Exc));}
        }
Now, transform that into this:

Code:
public static void SaveChar(Character Charr)
        {
            try
            {
                Charr.PackInventory();
                Charr.PackEquips();
                Charr.PackSkills();
                Charr.PackProfs();
                Charr.PackWarehouses();
                Charr.PackEnemies();
                Charr.PackFriends();
                if (ExternalDatabase.AllowQuerys)
                    ExternalDatabase.DatabaseQueue.Enqueue(new MySqlCommand("UPDATE `Characters` SET `CharName` = '" + Charr.Name + "', `Level` = " + Charr.Level + ",`Exp` = " + Charr.Exp + ",`GuildDonation` = " + Charr.GuildDonation + ",`Strength` = " + Charr.Str + ",`Agility` = " + Charr.Agi + ",`Vitality` = " + Charr.Vit + ",`Spirit` = " + Charr.Spi + ",`Job` = " + Charr.Job + ",`Model` = " + Charr.RealModel + ",`Money` = " + Charr.Silvers + ",`CPs` = " + Charr.CPs + ",`CurrentHP` = " + Charr.CurHP + ",`StatPoints` = " + Charr.StatP + ",`MyGuild` = " + Charr.GuildID + ",`GuildPos` = " + Charr.GuildPosition + ",`LocationMap` = " + Charr.LocMap + ",`LocationX` = " + Charr.LocX + ",`LocationY` = " + Charr.LocY + ",`Hair` = " + Charr.Hair + ",`Equipment` = '" + Charr.PackedEquips + "',`Inventory` = '" + Charr.PackedInventory + "',`PKPoints` = " + Charr.PKPoints + ",`PrevMap` = " + Charr.PrevMap + ", `Skills` = '" + Charr.PackedSkills + "', `Profs` = '" + Charr.PackedProfs + "',`RBCount` = " + Charr.RBCount + ",`Avatar` = " + Charr.Avatar + ",`WHMoney` = " + Charr.WHSilvers + ",`VP` = " + Charr.VP + ",`Warehouses` = '" + Charr.PackedWHs + "',`Friends` = '" + Charr.PackedFriends + "',`Enemies` = '" + Charr.PackedEnemies + "',`QuestMob` = '" + Charr.QuestMob + "',`QuestKO` = " + Charr.QuestKO + " WHERE `Account` = '" + Charr.MyClient.Account + "'", ExternalDatabase.Connection));
            }
            catch 
            {
               // You can put some  log feature here, like
               // General.WriteLine("Using alternate connection");
try
{
        if (ExternalDatabase.AllowQuerys)
                    ExternalDatabase.DatabaseQueue.Enqueue(new MySqlCommand("UPDATE `Characters` SET `CharName` = '" + Charr.Name + "', `Level` = " + Charr.Level + ",`Exp` = " + Charr.Exp + ",`GuildDonation` = " + Charr.GuildDonation + ",`Strength` = " + Charr.Str + ",`Agility` = " + Charr.Agi + ",`Vitality` = " + Charr.Vit + ",`Spirit` = " + Charr.Spi + ",`Job` = " + Charr.Job + ",`Model` = " + Charr.RealModel + ",`Money` = " + Charr.Silvers + ",`CPs` = " + Charr.CPs + ",`CurrentHP` = " + Charr.CurHP + ",`StatPoints` = " + Charr.StatP + ",`MyGuild` = " + Charr.GuildID + ",`GuildPos` = " + Charr.GuildPosition + ",`LocationMap` = " + Charr.LocMap + ",`LocationX` = " + Charr.LocX + ",`LocationY` = " + Charr.LocY + ",`Hair` = " + Charr.Hair + ",`Equipment` = '" + Charr.PackedEquips + "',`Inventory` = '" + Charr.PackedInventory + "',`PKPoints` = " + Charr.PKPoints + ",`PrevMap` = " + Charr.PrevMap + ", `Skills` = '" + Charr.PackedSkills + "', `Profs` = '" + Charr.PackedProfs + "',`RBCount` = " + Charr.RBCount + ",`Avatar` = " + Charr.Avatar + ",`WHMoney` = " + Charr.WHSilvers + ",`VP` = " + Charr.VP + ",`Warehouses` = '" + Charr.PackedWHs + "',`Friends` = '" + Charr.PackedFriends + "',`Enemies` = '" + Charr.PackedEnemies + "',`QuestMob` = '" + Charr.QuestMob + "',`QuestKO` = " + Charr.QuestKO + " WHERE `Account` = '" + Charr.MyClient.Account + "'", ExternalDatabase.[b]Connection2[/b]));
}
catch (Exception Exc) {General.WriteLine(Convert.ToString(Exc)); }
            }
        }


Resuming: find the query block code, put it inside a try statement and repeat the same query inside a catch, but using the other connection. Do it for all mysql related code.

RESULTS: the capacity of the server is enlarged, but after some time the alternative connection starts to work as much as the main connection, and after some more players log in, both connections start to fail. So, this is not a definitive solution, and is because of that we analyze the 2nd technique:
04/28/2009 05:16 jkaton#4
This, even not resolved the problem, enlarged the server capacity some more and accelerated the database response, diminishing lags, so, it's a good practice. For better understanding, let's use some short code block as example this time:

Code:
public static void Change_GMStatus5(string Acc)
        {
            MySqlCommand Command = null;
            Command = new MySqlCommand("UPDATE `Accounts` SET `Status` = 5 WHERE `AccountID` = '" + Acc + "'", Connection);
            Command.ExecuteNonQuery();
        }
Add some code, to verify if connection is open and to close it after use. Make it look like this:

Code:
public static void Change_GMStatus5(string Acc)
        {
[B]            if (Connection.State == ConnectionState.Broken || Connection.State == ConnectionState.Closed)
            {
                Connection.Open();
            }[/B]
            MySqlCommand Command = null;
            Command = new MySqlCommand("UPDATE `Accounts` SET `Status` = 5 WHERE `AccountID` = '" + Acc + "'", Connection);
            Command.ExecuteNonQuery();
           [B] Connection.Close();
            Connection.Dispose();[/B]
        }
Just remember: if u adopt this technique to your server, u must do it around ALL MySQL queries, to put a way to verify connection state, because the connections will be closed, and the system verifier (State.Changed) doesn't work.
04/28/2009 05:40 jkaton#5
LOTF sources have a 5 minute system timer that saves all chars when elapsed, and when we close the server the right way, they are saved too, and some sources have the command /save available for the players, so we can cut some Char.Save() invocations without risk:

in character.cs, find:

Code:
           if (DateTime.Now > LastSave.AddMilliseconds(15000))
               Save();
just comment these 2 lines with //
(this lines was just saving each char every 15 seconds, causing some overload after we have 6 or more players logged in)

in client.cs, find this:
Code:
case 79:
                                    {
                                        MyChar.Ready = false;
                                        MyChar.Direction = Data[20];
                                        World.PlayerMoves(MyChar, Data);
                                        MyChar.Save();
                                        MyChar.Ready = true;
                                        break;
                                    }
                                case 81:
                                    {
                                        MyChar.Ready = false;
                                        MyChar.Action = Data[12];
                                        World.PlayerMoves(MyChar, Data);
                                        MyChar.Save();
                                        MyChar.Ready = true;
                                        break;
                                    }
                                case 85:
                                    {
                                        MyChar.Ready = false;
                                        ulong CharID = (ulong)((Data[11] << 24) + (Data[10] << 16) + (Data[9] << 8) + (Data[8]));
                                        int x = (Data[13] << 8) + (Data[12]);
                                        int y = (Data[15] << 8) + (Data[14]);

                                        if (MyChar.UID == CharID)
                                            MyChar.UsePortal();
                                        MyChar.Save();
                                        MyChar.Ready = true;
                                        break;
                                    }
Comment all Save(); making it as below:

Code:
case 79:
                                    {
                                        MyChar.Ready = false;
                                        MyChar.Direction = Data[20];
                                        World.PlayerMoves(MyChar, Data);
                                        [B]//MyChar.Save();[/B]
                                        MyChar.Ready = true;
                                        break;
                                    }
                                case 81:
                                    {
                                        MyChar.Ready = false;
                                        MyChar.Action = Data[12];
                                        World.PlayerMoves(MyChar, Data);
                                        [B]//MyChar.Save();[/B]
                                        MyChar.Ready = true;
                                        break;
                                    }
                                case 85:
                                    {
                                        MyChar.Ready = false;
                                        ulong CharID = (ulong)((Data[11] << 24) + (Data[10] << 16) + (Data[9] << 8) + (Data[8]));
                                        int x = (Data[13] << 8) + (Data[12]);
                                        int y = (Data[15] << 8) + (Data[14]);

                                        if (MyChar.UID == CharID)
                                            MyChar.UsePortal();
                                        [B]//MyChar.Save();[/B]
                                        MyChar.Ready = true;
                                        break;
                                    }
(we need save when the char move? When crossing a portal? NOOOOO!)

If u know C# a little, is possible to find and cut other queries. but be aware: understand what the code does first. In any case, you can debug the server step by step to see the most invoked queries and decide if they must remain or not.

This technique is really effective, although using it alone, the server is not optimized. I recommend use the three improvements together. If u do it, u will have a PRO server.
04/28/2009 11:19 YukiXian#6
WooW ! 5 posts in a row,
You should edit your first post and add all the stuff in there...
04/28/2009 11:39 IcedEarth#7
It would be too long and would not be allowed :P
04/29/2009 02:39 scottdavey#8
ExternalDatabase doesn't exist in untouched LOTF sources.
04/30/2009 00:03 jkaton#9
Quote:
ExternalDatabase doesn't exist in untouched LOTF sources.
Doesn`t matter... Some command in that region code connects to mysql, and u can apply the same improvements around it, the same way, like this:

Code:
 public static void SaveChar(Character Charr)
        {
                try
                {
                    Charr.LogoutTime = (uint)Environment.TickCount;
                    Charr.PackInventory();
                    Charr.PackEquips();
                    Charr.PackSkills();
                    Charr.PackProfs();
                    Charr.PackWarehouses();
                    Charr.PackEnemies();
                    Charr.PackFriends();

                    try
                    {
                        [B]if (Connection.State == ConnectionState.Broken || Connection.State == ConnectionState.Closed)
                        {
                            Connection.Open();
                        }[/B]              [U]MySqlCommand Command4 =null;[/U]

                   [U] Command4 = new MySqlCommand[/U]("UPDATE `Characters` SET `CharName` = '" + Charr.Name + "',`Spouse` = '" + Charr.Spouse + "', `Level` = " + Charr.Level + ",`Exp` = " + Charr.Exp + ",`GuildDonation` = " + Charr.GuildDonation + ",`Strength` = " + Charr.Str + ",`Agility` = " + Charr.Agi + ",`Vitality` = " + Charr.Vit + ",`Spirit` = " + Charr.Spi + ",`Job` = " + Charr.Job + ",`Model` = " + Charr.RealModel + ",`Money` = " + Charr.Silvers + ",`CPs` = " + Charr.CPs + ",`CurrentHP` = " + Charr.CurHP + ",`StatPoints` = " + Charr.StatP + ",`MyGuild` = " + Charr.GuildID + ",`GuildPos` = " + Charr.GuildPosition + ",`LocationMap` = " + Charr.LocMap + ",`LocationX` = " + Charr.LocX + ",`LocationY` = " + Charr.LocY + ",`Hair` = " + Charr.Hair + ",`Equipment` = '" + Charr.PackedEquips + "',`Inventory` = '" + Charr.PackedInventory + "',`PKPoints` = " + Charr.PKPoints + ",`PrevMap` = " + Charr.PrevMap + ", `Skills` = '" + Charr.PackedSkills + "', `Profs` = '" + Charr.PackedProfs + "',`RBCount` = " + Charr.RBCount + ",`Avatar` = " + Charr.Avatar + ",`WHMoney` = " + Charr.WHSilvers + ",`VP` = " + Charr.VP + ",`Warehouses` = '" + Charr.PackedWHs + "',`Friends` = '" + Charr.PackedFriends + "',`Enemies` = '" + Charr.PackedEnemies + "',`QuestKO` = '" + Charr.QuestKO + "',`QuestMob` = '" + Charr.QuestMob + "',`QuestFrom` = '" + Charr.QuestFrom + "',`Prize` = '" + Charr.Prize + "',`ClaimPrize` = '" + Charr.ClaimPrize + "',`LuckyTime` = '" + Charr.LuckTime + "',`DoubleExp` = '" + Charr.DExp2 + "',`VIPClaimDate` = '" + Charr.VIPClaimDateS + "',`CurseTime` = '" + Charr.CurseTime + "',`DisKo` = '" + Charr.DisKO + "',`DisToKill` = '" + Charr.DisToKill + "',`LogoutTime` = " + Charr.LogoutTime + ",`OfflineTG` = " + Charr.OfflineTG + " WHERE `Account` = '" + Charr.MyClient.Account + "'", Connection);
                        [U]Command4.ExecuteNonQuery();[/U]
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("Saving character " + Charr.Name + " with normal connection");
                        [B]Connection.Close();
                        Connection.Dispose();[/B]                    }
                    catch //(Exception Exc)
                    {
                        //General.WriteLine(Convert.ToString(Exc));
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine("Saving character " + Charr.Name + " with alternative connection");
                        [B]if (Connection2.State == ConnectionState.Broken || Connection2.State == ConnectionState.Closed)
                        {
                            Connection2.Open();
                        }[/B]                        [U]MySqlCommand Command5 = null;[/U]

                        [U]Command5 = new MySqlCommand[/U]("UPDATE `Characters` SET `CharName` = '" + Charr.Name + "',`Spouse` = '" + Charr.Spouse + "', `Level` = " + Charr.Level + ",`Exp` = " + Charr.Exp + ",`GuildDonation` = " + Charr.GuildDonation + ",`Strength` = " + Charr.Str + ",`Agility` = " + Charr.Agi + ",`Vitality` = " + Charr.Vit + ",`Spirit` = " + Charr.Spi + ",`Job` = " + Charr.Job + ",`Model` = " + Charr.RealModel + ",`Money` = " + Charr.Silvers + ",`CPs` = " + Charr.CPs + ",`CurrentHP` = " + Charr.CurHP + ",`StatPoints` = " + Charr.StatP + ",`MyGuild` = " + Charr.GuildID + ",`GuildPos` = " + Charr.GuildPosition + ",`LocationMap` = " + Charr.LocMap + ",`LocationX` = " + Charr.LocX + ",`LocationY` = " + Charr.LocY + ",`Hair` = " + Charr.Hair + ",`Equipment` = '" + Charr.PackedEquips + "',`Inventory` = '" + Charr.PackedInventory + "',`PKPoints` = " + Charr.PKPoints + ",`PrevMap` = " + Charr.PrevMap + ", `Skills` = '" + Charr.PackedSkills + "', `Profs` = '" + Charr.PackedProfs + "',`RBCount` = " + Charr.RBCount + ",`Avatar` = " + Charr.Avatar + ",`WHMoney` = " + Charr.WHSilvers + ",`VP` = " + Charr.VP + ",`Warehouses` = '" + Charr.PackedWHs + "',`Friends` = '" + Charr.PackedFriends + "',`Enemies` = '" + Charr.PackedEnemies + "',`QuestKO` = '" + Charr.QuestKO + "',`QuestMob` = '" + Charr.QuestMob + "',`QuestFrom` = '" + Charr.QuestFrom + "',`Prize` = '" + Charr.Prize + "',`ClaimPrize` = '" + Charr.ClaimPrize + "',`LuckyTime` = '" + Charr.LuckTime + "',`DoubleExp` = '" + Charr.DExp2 + "',`VIPClaimDate` = '" + Charr.VIPClaimDateS + "',`CurseTime` = '" + Charr.CurseTime + "',`DisKo` = '" + Charr.DisKO + "',`DisToKill` = '" + Charr.DisToKill + "',`LogoutTime` = " + Charr.LogoutTime + ",`OfflineTG` = " + Charr.OfflineTG + " WHERE `Account` = '" + Charr.MyClient.Account + "'", [B]Connection2[/B]);
                        [U]Command5.ExecuteNonQuery();[/U]                        Connection2.Close();
                        [B]Connection2.Dispose();
                        Console.ResetColor();[/B]
                    }
                }
                catch (Exception Exc)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    General.WriteLine(Convert.ToString(Exc));
                    Console.ResetColor();
                }
        }
This is my full SaveChar(); note the mysql commands without external database in underlined area.
04/30/2009 20:27 martoon#10
It really works?
05/01/2009 09:06 jkaton#11
I can post my results, serving CO on an old Athlon XP 2000+, 512MB ram, Windows XP SP3:

At beginning: server takes about 20 seconds to start; about 6-8 players logged and mysql was denying connections;

Step 1 done (replication): server takes about 20 seconds to start; working without mysql errors at 9 players;

Step 2 done (replication AND closing connections): server takes not even 5 seconds to start, and handled 11 players without errors;

Step 3 done (replication + closing conns - unnecessary queries): server takes less than 5 seconds to start, and worked without mysql errors till now, not even once I registered it using alternate connection; for now I was able to login only 27 characters, being 8 actively playing (but Im sure it handles more, cause we have just 8 computers here :D )
05/05/2009 16:13 reborn666#12
the save donr workwhit this code
Quote:
try
{
if (ExternalDatabase.Connection.State == ConnectionState.Broken || ExternalDatabase.Connection.State == ConnectionState.Closed)
{
ExternalDatabase.Connection.Open();
if (ExternalDatabase.AllowQuerys)
ExternalDatabase.DatabaseQueue.Enqueue(new MySqlCommand("UPDATE `Characters` SET `CharName` = '" + Charr.Name + "', `Level` = " + Charr.Level + ",`Exp` = " + Charr.Exp + ",`GuildDonation` = " + Charr.GuildDonation + ",`Strength` = " + Charr.Str + ",`Agility` = " + Charr.Agi + ",`Vitality` = " + Charr.Vit + ",`Spirit` = " + Charr.Spi + ",`Job` = " + Charr.Job + ",`Model` = " + Charr.RealModel + ",`Money` = " + Charr.Silvers + ",`CPs` = " + Charr.CPs + ",`CurrentHP` = " + Charr.CurHP + ",`StatPoints` = " + Charr.StatP + ",`MyGuild` = " + Charr.GuildID + ",`GuildPos` = " + Charr.GuildPosition + ",`LocationMap` = " + Charr.LocMap + ",`LocationX` = " + Charr.LocX + ",`LocationY` = " + Charr.LocY + ",`Hair` = " + Charr.Hair + ",`Equipment` = '" + Charr.PackedEquips + "',`Inventory` = '" + Charr.PackedInventory + "',`PKPoints` = " + Charr.PKPoints + ",`PrevMap` = " + Charr.PrevMap + ", `Skills` = '" + Charr.PackedSkills + "', `Profs` = '" + Charr.PackedProfs + "',`RBCount` = " + Charr.RBCount + ",`Avatar` = " + Charr.Avatar + ",`WHMoney` = " + Charr.WHSilvers + ",`VP` = " + Charr.VP + ",`Warehouses` = '" + Charr.PackedWHs + "',`Friends` = '" + Charr.PackedFriends + "',`Enemies` = '" + Charr.PackedEnemies + "',`QuestMob` = '" + Charr.QuestMob + "',`QuestKO` = " + Charr.QuestKO + " WHERE `Account` = '" + Charr.MyClient.Account + "'", ExternalDatabase.Connection));
ExternalDatabase.Connection.Close();
ExternalDatabase.Connection.Dispose();
}
}
catch //(Exception Exc)
{
//General.WriteLine(Convert.ToString(Exc));
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Saving character " + Charr.Name + " with alternative connection");
if (ExternalDatabase.LoginConnection.State == ConnectionState.Broken || ExternalDatabase.LoginConnection.State == ConnectionState.Closed)
{
ExternalDatabase.LoginConnection.Open();
if (ExternalDatabase.AllowQuerys)
ExternalDatabase.DatabaseQueue.Enqueue(new MySqlCommand("UPDATE `Characters` SET `CharName` = '" + Charr.Name + "', `Level` = " + Charr.Level + ",`Exp` = " + Charr.Exp + ",`GuildDonation` = " + Charr.GuildDonation + ",`Strength` = " + Charr.Str + ",`Agility` = " + Charr.Agi + ",`Vitality` = " + Charr.Vit + ",`Spirit` = " + Charr.Spi + ",`Job` = " + Charr.Job + ",`Model` = " + Charr.RealModel + ",`Money` = " + Charr.Silvers + ",`CPs` = " + Charr.CPs + ",`CurrentHP` = " + Charr.CurHP + ",`StatPoints` = " + Charr.StatP + ",`MyGuild` = " + Charr.GuildID + ",`GuildPos` = " + Charr.GuildPosition + ",`LocationMap` = " + Charr.LocMap + ",`LocationX` = " + Charr.LocX + ",`LocationY` = " + Charr.LocY + ",`Hair` = " + Charr.Hair + ",`Equipment` = '" + Charr.PackedEquips + "',`Inventory` = '" + Charr.PackedInventory + "',`PKPoints` = " + Charr.PKPoints + ",`PrevMap` = " + Charr.PrevMap + ", `Skills` = '" + Charr.PackedSkills + "', `Profs` = '" + Charr.PackedProfs + "',`RBCount` = " + Charr.RBCount + ",`Avatar` = " + Charr.Avatar + ",`WHMoney` = " + Charr.WHSilvers + ",`VP` = " + Charr.VP + ",`Warehouses` = '" + Charr.PackedWHs + "',`Friends` = '" + Charr.PackedFriends + "',`Enemies` = '" + Charr.PackedEnemies + "',`QuestMob` = '" + Charr.QuestMob + "',`QuestKO` = " + Charr.QuestKO + " WHERE `Account` = '" + Charr.MyClient.Account + "'", ExternalDatabase.Connection));
ExternalDatabase.LoginConnection.Close();
ExternalDatabase.LoginConnection.Dispose();
}
}
05/08/2009 02:42 jkaton#13
Of course not! my database structure must be very different compared to yours!

This script is just an example, DON'T just copy and paste... read the entire article!:rtfm: