All pastes #624804 Raw Edit

Someone

public text v1 · immutable
·published 2007-07-18 15:12 UTC
rendered paste body
Index: src/game/CharacterHandler.cpp
===================================================================
--- src/game/CharacterHandler.cpp	(revision 4123)
+++ src/game/CharacterHandler.cpp	(working copy)
@@ -38,27 +38,31 @@
 // check used symbols in player name at creating and rename
 std::string notAllowedChars = "\t\v\b\f\a\n\r\\\"\'\? <>[](){}_=+-|/!@#$%^&*~`.,0123456789\0";
 
-void WorldSession::HandleCharEnumOpcode( WorldPacket & recv_data )
+class CharacterHandler
 {
-    // keys can be non cleared if player open realm list and close it by 'cancel'
-    loginDatabase.PExecute("UPDATE `account` SET `v` = '0', `s` = '0' WHERE `id` = '%u'", GetAccountId());
+    public:
+        void HandleCharEnum(QueryResult * result, uint32 account);
+} chrHandler;
 
+void CharacterHandler::HandleCharEnum(QueryResult * result, uint32 account)
+{
+    WorldSession * session = sWorld.FindSession(account);
+    if(!session) return;
+
     WorldPacket data(SMSG_CHAR_ENUM, 100);                  // we guess size
-
-    QueryResult *result = sDatabase.PQuery("SELECT `guid` FROM `character` WHERE `account` = '%u' ORDER BY `guid`", GetAccountId());
-
+    
     uint8 num = 0;
 
     data << num;
 
     if( result )
     {
-        Player *plr = new Player(this);
+        Player *plr = new Player(session);
         do
         {
-            sLog.outDetail("Loading char guid %u from account %u.",(*result)[0].GetUInt32(),GetAccountId());
+            sLog.outDetail("Loading char guid %u from account %u.",(*result)[0].GetUInt32(),session->GetAccountId());
 
-            if(plr->MinimalLoadFromDB( (*result)[0].GetUInt32() ))
+            if(plr->MinimalLoadFromDB( result, (*result)[0].GetUInt32() ))
             {
                 plr->BuildEnumData( &data );
                 num++;
@@ -72,9 +76,17 @@
 
     data.put<uint8>(0, num);
 
-    SendPacket( &data );
+    session->SendPacket( &data );
 }
 
+void WorldSession::HandleCharEnumOpcode( WorldPacket & recv_data )
+{
+    // keys can be non cleared if player open realm list and close it by 'cancel'
+    loginDatabase.PExecute("UPDATE `account` SET `v` = '0', `s` = '0' WHERE `id` = '%u'", GetAccountId());
+    sDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnum, GetAccountId(),
+        "SELECT `data`,`name`,`position_x`,`position_y`,`position_z`,`map`,`totaltime`,`leveltime`,`rename` FROM `character` WHERE `account` = '%u' ORDER BY `guid`", GetAccountId());
+}
+
 void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
 {
     // in Player::Create:
Index: src/game/Player.cpp
===================================================================
--- src/game/Player.cpp	(revision 4123)
+++ src/game/Player.cpp	(working copy)
@@ -1084,7 +1084,7 @@
         uint32 petFamily  = 0;
 
         // show pet at selection character in character list  only for non-ghost character
-        if(isAlive()&&(pClass==CLASS_WARLOCK||pClass==CLASS_HUNTER))
+        /*if(isAlive()&&(pClass==CLASS_WARLOCK||pClass==CLASS_HUNTER))
         {
             QueryResult *result = sDatabase.PQuery("SELECT `entry`,`modelid`,`level` FROM `character_pet` WHERE `owner` = '%u' AND `slot` = '0'", GetGUIDLow() );
             if(result)
@@ -1101,14 +1101,14 @@
                 }
                 delete result;
             }
-        }
+        }*/
 
         *p_data << (uint32)petDisplayId;
         *p_data << (uint32)petLevel;
         *p_data << (uint32)petFamily;
     }
 
-    ItemPrototype const *items[EQUIPMENT_SLOT_END];
+    /*ItemPrototype const *items[EQUIPMENT_SLOT_END];
     for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
         items[i] = NULL;
 
@@ -1131,14 +1131,18 @@
             }
         } while (result->NextRow());
         delete result;
-    }
+    }*/
 
-    for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
+    for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++)
     {
-        if (items[i] != NULL)
+        int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 16);
+        uint32 item_id = GetUInt32Value(VisibleBase);
+        const ItemPrototype * proto = objmgr.GetItemPrototype(item_id);
+
+        if (proto != NULL)
         {
-            *p_data << (uint32)items[i]->DisplayInfoID;
-            *p_data << (uint8)items[i]->InventoryType;
+            *p_data << (uint32)proto->DisplayInfoID;
+            *p_data << (uint8)proto->InventoryType;
         }
         else
         {
@@ -11506,19 +11510,23 @@
 /***                   LOAD SYSTEM                     ***/
 /*********************************************************/
 
-bool Player::MinimalLoadFromDB( uint32 guid )
+bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid )
 {
-    //                                             0      1      2            3            4            5     6           7           8
-    QueryResult *result = sDatabase.PQuery("SELECT `data`,`name`,`position_x`,`position_y`,`position_z`,`map`,`totaltime`,`leveltime`,`rename` FROM `character` WHERE `guid` = '%u'",guid);
+    bool delete_query = true;
     if(!result)
-        return false;
+    {
+        //                                             0      1      2            3            4            5     6           7           8
+        QueryResult *result = sDatabase.PQuery("SELECT `data`,`name`,`position_x`,`position_y`,`position_z`,`map`,`totaltime`,`leveltime`,`rename` FROM `character` WHERE `guid` = '%u'",guid);
+        if(!result) return false;
+    }
+    else delete_query = false;
 
     Field *fields = result->Fetch();
 
     if(!LoadValues( fields[0].GetString()))
     {
         sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
-        delete result;
+        if(delete_query) delete result;
         return false;
     }
 
@@ -11536,7 +11544,7 @@
 
     _LoadBoundInstances();
 
-    delete result;
+    if (delete_query) delete result;
 
     for (int i = 0; i < PLAYER_SLOTS_COUNT; i++)
         m_items[i] = NULL;
Index: src/game/Player.h
===================================================================
--- src/game/Player.h	(revision 4123)
+++ src/game/Player.h	(working copy)
@@ -898,7 +898,7 @@
         /*********************************************************/
 
         bool LoadFromDB(uint32 guid);
-        bool MinimalLoadFromDB(uint32 guid);
+        bool MinimalLoadFromDB(QueryResult *result, uint32 guid);
         static bool   LoadValuesArrayFromDB(vector<string>& data,uint64 guid);
         static uint32 GetUInt32ValueFromArray(vector<string> const& data, uint16 index);
         static float  GetFloatValueFromArray(vector<string> const& data, uint16 index);
Index: src/game/World.cpp
===================================================================
--- src/game/World.cpp	(revision 4123)
+++ src/game/World.cpp	(working copy)
@@ -815,6 +815,9 @@
         sBattleGroundMgr.Update(diff);
     }
 
+    // execute callbacks from sql queries that were queued recently
+    UpdateResultQueue();
+
     /// </ul>
     ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
     ObjectAccessor::Instance().DoDelayedMovesAndRemoves();
@@ -1348,3 +1351,15 @@
     // print the console message here so it looks right
     zprintf("mangos>");
 }
+
+void World::InitResultQueue()
+{
+    m_resultQueue = new SqlResultQueue;
+    sDatabase.SetResultQueue(m_resultQueue);
+}
+
+void World::UpdateResultQueue()
+{
+    m_resultQueue->Update();
+}
+
Index: src/game/World.h
===================================================================
--- src/game/World.h	(revision 4123)
+++ src/game/World.h	(working copy)
@@ -36,6 +36,7 @@
 struct ScriptAction;
 struct ScriptInfo;
 class CliCommandHolder;
+class SqlResultQueue;
 
 /// Timers for different object refresh rates
 enum WorldTimers
@@ -313,6 +314,9 @@
         void ProcessCliCommands();
         void QueueCliCommand(CliCommandHolder* command) { cliCmdQueue.add(command); }
 
+        void UpdateResultQueue();
+        void InitResultQueue();
+
     protected:
         void _UpdateGameTime();
         void ScriptsProcess();
@@ -355,6 +359,7 @@
 
         // CLI command holder to be thread safe
         ZThread::LockedQueue<CliCommandHolder*, ZThread::FastMutex> cliCmdQueue;
+        SqlResultQueue *m_resultQueue;
 };
 
 extern uint32 realmID;
Index: src/mangosd/WorldRunnable.cpp
===================================================================
--- src/mangosd/WorldRunnable.cpp	(revision 4123)
+++ src/mangosd/WorldRunnable.cpp	(working copy)
@@ -35,6 +35,7 @@
 {
     ///- Init new SQL thread for the world database
     sDatabase.ThreadStart();                                // let thread do safe mySQL requests (one connection call enough)
+    sWorld.InitResultQueue();
 
     uint32 realCurrTime = 0;
     uint32 realPrevTime = getMSTime();
Index: src/shared/Database/Database.cpp
===================================================================
--- src/shared/Database/Database.cpp	(revision 4123)
+++ src/shared/Database/Database.cpp	(working copy)
@@ -103,4 +103,9 @@
     }
 
     return Execute(szQuery);
+}
+
+void Database::SetResultQueue(SqlResultQueue * queue)
+{
+    m_queryQueues[ZThread::ThreadImpl::current()] = queue;
 }
\ No newline at end of file
Index: src/shared/Database/Database.h
===================================================================
--- src/shared/Database/Database.h	(revision 4123)
+++ src/shared/Database/Database.h	(working copy)
@@ -20,14 +20,15 @@
 #define DATABASE_H
 
 #include "zthread/Thread.h"
+#include "../src/zthread/ThreadImpl.h"
 #include "Utilities/HashMap.h"
 #include "Database/SqlDelayThread.h"
+#include "Database/SqlOperations.h"
 
-#include <queue>
-
 class SqlTransaction;
 
 typedef HM_NAMESPACE::hash_map<ZThread::ThreadImpl*, SqlTransaction*> TransactionQueues;
+typedef HM_NAMESPACE::hash_map<ZThread::ThreadImpl*, SqlResultQueue*> QueryQueues;
 
 #define MAX_QUERY_LEN   1024
 
@@ -36,7 +37,8 @@
     protected:
         Database() : m_threadBody(NULL), m_delayThread(NULL) {};
         
-        TransactionQueues m_tranQueues;                     ///< Transaction queue from diff. threads
+        TransactionQueues m_tranQueues;                     ///< Transaction queues from diff. threads
+        QueryQueues m_queryQueues;                          ///< Query queues from diff threads
         SqlDelayThread* m_threadBody;                       ///< Pointer to delay sql executer
         ZThread::Thread* m_delayThread;                     ///< Pointer to executer thread
 
@@ -51,6 +53,68 @@
         virtual QueryResult* Query(const char *sql) = 0;
         virtual QueryResult* PQuery(const char *format,...) = 0;
 
+        template<class Class>
+            bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql)
+        {
+            if (!sql) return false;
+            ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
+            QueryQueues::iterator itr = m_queryQueues.find(queryThread);
+            if (itr == m_queryQueues.end()) return false;
+            m_threadBody->Delay(new SqlQuery(sql, new _SqlResultHolder<Class>(object, method), itr->second));
+            return true;
+        }
+
+        template<class Class, typename ParamType1>
+            bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql)
+        {
+            if (!sql) return false;
+            ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
+            QueryQueues::iterator itr = m_queryQueues.find(queryThread);
+            if (itr == m_queryQueues.end()) return false;
+            m_threadBody->Delay(new SqlQuery(sql, new _SqlResultHolder1<Class, ParamType1>(object, method, param1), itr->second));
+            return true;
+        }
+
+        template<class Class>
+            bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...)
+        {
+            if(!format) return false;
+
+            va_list ap;
+            char szQuery [MAX_QUERY_LEN];
+            va_start(ap, format);
+            int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+            va_end(ap);
+
+            if(res==-1)
+            {
+                sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+                return false;
+            }
+            
+            return AsyncQuery(object, method, szQuery);
+        }
+
+        template<class Class, typename ParamType1>
+            bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...)
+        {
+            if(!format) return false;
+
+            va_list ap;
+            char szQuery [MAX_QUERY_LEN];
+            va_start(ap, format);
+            int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+            va_end(ap);
+
+            if(res==-1)
+            {
+                sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+                return false;
+            }
+            
+            return AsyncQuery(object, method, param1, szQuery);
+        }
+
         virtual bool Execute(const char *sql) = 0;
         virtual bool PExecute(const char *format,...) = 0;
         virtual bool DirectExecute(const char* sql) = 0;
@@ -80,6 +144,10 @@
         virtual void ThreadStart();
         // must be called before finish thread run (one time for thread using one from existed Database objects)
         virtual void ThreadEnd();
+
+        // sets the result queue of the current thread, be careful what thread you call this from
+        void SetResultQueue(SqlResultQueue * queue);
+
     private:
         // 0 - do not log, 1 - log sql commands        
         uint32 m_logSQL;
Index: src/shared/Database/DatabaseMysql.cpp
===================================================================
--- src/shared/Database/DatabaseMysql.cpp	(revision 4123)
+++ src/shared/Database/DatabaseMysql.cpp	(working copy)
@@ -425,4 +425,4 @@
     delete m_delayThread;                                   //This also deletes m_threadBody
     m_delayThread = NULL;
     m_threadBody = NULL;
-}
\ No newline at end of file
+}
Index: src/shared/Database/SqlOperations.cpp
===================================================================
--- src/shared/Database/SqlOperations.cpp	(revision 4123)
+++ src/shared/Database/SqlOperations.cpp	(working copy)
@@ -37,3 +37,40 @@
     }
     db->DirectExecute("COMMIT");
 }
+
+void SqlQuery::Execute(Database *db)
+{
+    if(!m_holder || !m_queue) return;
+    m_holder->SetResult(db->Query(m_sql));
+    m_queue->add(m_holder);
+    m_holder = NULL;
+}
+
+SqlResultHolder::~SqlResultHolder()
+{
+    delete m_result;
+}
+
+
+void SqlResultQueue::Update()
+{
+    while(!empty())
+    {
+        SqlResultHolder * holder = next();
+        holder->CallBack();
+    }
+}
+
+void SqlTransaction::Execute(Database *db, size_t nr)
+{
+    if(m_queue.size() < nr) return;
+    db->DirectExecute("START TRANSACTION");
+    for(size_t i = 0; i < nr; i++)
+    {
+        char *sql = (char*)m_queue.front();
+        m_queue.pop();
+        db->DirectExecute(sql);
+        free(sql);
+    }
+    db->DirectExecute("COMMIT");
+}
\ No newline at end of file
Index: src/shared/Database/SqlOperations.h
===================================================================
--- src/shared/Database/SqlOperations.h	(revision 4123)
+++ src/shared/Database/SqlOperations.h	(working copy)
@@ -21,6 +21,7 @@
 
 #include "zthread/LockedQueue.h"
 #include "zthread/FastMutex.h"
+#include "zthread/Thread.h"
 #include <queue>
 
 /// ---- BASE ---
@@ -30,6 +31,7 @@
 class SqlOperation
 {
     public:
+        virtual void OnRemove() { delete this; }
         virtual void Execute(Database *db) = 0;
         virtual ~SqlOperation() {}
 };
@@ -54,5 +56,83 @@
         SqlTransaction() {}
         void DelayExecute(const char *sql) { m_queue.push(strdup(sql)); }
         void Execute(Database *db);
+        void Execute(Database *db, size_t nr);
 };
+
+class SqlTransHolder : public SqlOperation
+{
+    private:
+        SqlTransaction *m_trans;
+        size_t m_nr;
+    public:
+        SqlTransHolder(SqlTransaction *trans, size_t opNr) : m_trans(trans), m_nr(opNr) {}
+        void Execute(Database *db) { m_trans->Execute(db, m_nr); }
+};
+
+// ---- ASYNC QUERIES ----
+
+class SqlQuery;
+class QueryResult;
+class SqlResultHolder;
+class SqlResultQueue;
+
+class SqlResultQueue : public ZThread::LockedQueue<SqlResultHolder*, ZThread::FastMutex>
+{
+    public:
+        SqlResultQueue() : ZThread::LockedQueue<SqlResultHolder*, ZThread::FastMutex>() {}
+        void Update();
+};
+
+class SqlResultHolder
+{
+    private:
+        QueryResult *m_result;
+    public:
+        SqlResultHolder() : m_result(NULL) {}
+        void SetResult(QueryResult *result) { m_result = result; }
+        QueryResult * GetResult() { return m_result; }
+        virtual ~SqlResultHolder();
+        virtual void CallBack() = 0;
+};
+
+template<class Class>
+class _SqlResultHolder : public SqlResultHolder
+{
+    private:
+        typedef void (Class::*Method)(QueryResult*);
+        Class *m_object;
+        Method m_method;
+    public:
+        _SqlResultHolder(Class *object, Method method)
+            : m_object(object), m_method(method), SqlResultHolder() {}
+        void CallBack() { (m_object->*m_method)(GetResult()); }
+};
+
+template<class Class, typename ParamType1>
+class _SqlResultHolder1 : public SqlResultHolder
+{
+    private:
+        typedef void (Class::*Method)(QueryResult*, ParamType1);
+        Class *m_object;
+        Method m_method;
+        ParamType1 m_param1;
+    public:
+        _SqlResultHolder1(Class *object, Method method, ParamType1 param1)
+            : m_object(object), m_method(method), m_param1(param1), SqlResultHolder() {}
+        void CallBack() { (m_object->*m_method)(GetResult(), m_param1); }
+};
+
+class SqlQuery : public SqlOperation
+{
+    private:
+        const char *m_sql;
+        SqlResultHolder * m_holder;
+        SqlResultQueue * m_queue;
+    public:
+        SqlQuery(const char *sql, SqlResultHolder * holder, SqlResultQueue * queue)
+            : m_sql(strdup(sql)), m_holder(holder), m_queue(queue) {}
+        ~SqlQuery() { if(m_holder) delete m_holder; free((void*)m_sql); }
+        void Execute(Database *db);
+};
+
 #endif                                                      //__SQLOPERATIONS_H