Jump to content

Restart the core and lose skills


Recommended Posts

Hi developers

I have added many systems to my source, so I can't find the reason for this problem.
Every time the core is restarted, skills are always lost, although I have joined before.

Here are some pictures:

Not joined

 

spacer.png

add

spacer.png

Increase skill points

spacer.png

Restart core

spacer.png

 

If you have any way, please let me know, I will thank you very much

Edited by Metin2 Dev International
Core X - External 2 Internal
Link to comment
Share on other sites

28 minutes ago, Abel(Tiger) said:

Post ClientManagerPlayer.cpp from the db. In most cases, your problem stems from this file.

thank you I check my ClientManagerPlayer.cpp

Quote

#include "stdafx.h"

#include "ClientManager.h"

#include "Main.h"
#include "QID.h"
#include "ItemAwardManager.h"
#include "HB.h"
#include "Cache.h"

extern bool g_bHotBackup;

extern std::string g_stLocale;
extern int g_test_server;
extern int g_log;

//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!! IMPORTANT !!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// Check all SELECT syntax on item table before change this function!!!
//
bool CreateItemTableFromRes(MYSQL_RES * res, std::vector<TPlayerItem> * pVec, DWORD dwPID)
{
    if (!res)
    {
        pVec->clear();
        return true;
    }

    int rows;

    if ((rows = mysql_num_rows(res)) <= 0)
    {
        pVec->clear();
        return true;
    }

    pVec->resize(rows);

    for (int i = 0; i < rows; ++i)
    {
        MYSQL_ROW row = mysql_fetch_row(res);
        TPlayerItem & item = pVec->at(i);

        int cur = 0;

        // Check all SELECT syntax on item table before change this function!!!
        // Check all SELECT syntax on item table before change this function!!!
        // Check all SELECT syntax on item table before change this function!!!
        str_to_number(item.id, row[cur++]);
        str_to_number(item.window, row[cur++]);
        str_to_number(item.pos, row[cur++]);
        str_to_number(item.count, row[cur++]);
        str_to_number(item.vnum, row[cur++]);
        str_to_number(item.alSockets[0], row[cur++]);
        str_to_number(item.alSockets[1], row[cur++]);
        str_to_number(item.alSockets[2], row[cur++]);

        for (int j = 0; j < ITEM_ATTRIBUTE_MAX_NUM; j++)
        {
            str_to_number(item.aAttr[j].bType, row[cur++]);
            str_to_number(item.aAttr[j].sValue, row[cur++]);
        }
#ifdef ENABLE_SOULBIND_SYSTEM
        str_to_number(item.sealbind, row[cur++]);
#endif

        item.owner        = dwPID;
    }

    return true;
}

size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * pkTab)
{
    size_t queryLen;

    queryLen = snprintf(pszQuery, querySize,
            "UPDATE player%s SET "
            "job = %d, "
            "voice = %d, "
            "dir = %d, "
            "x = %d, "
            "y = %d, "
            "z = %d, "
            "map_index = %d, "
            "exit_x = %ld, "
            "exit_y = %ld, "
            "exit_map_index = %ld, "
            "hp = %d, "
            "mp = %d, "
            "stamina = %d, "
            "random_hp = %d, "
            "random_sp = %d, "
            "playtime = %d, "
            "level = %d, "
            "level_step = %d, "
            "st = %d, "
            "ht = %d, "
            "dx = %d, "
            "iq = %d, "
            "gold = %d, "
            "exp = %u, "
            "stat_point = %d, "
            "skill_point = %d, "
            "sub_skill_point = %d, "
            "stat_reset_count = %d, "
            "ip = '%s', "
            "part_main = %d, "
            "part_hair = %d, "
#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
            "pick_up_mode = %d, "
            "rarity_mode = %d, "
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
            "shop_flag = %llu, "
#endif
            #ifdef ENABLE_ACCE_COSTUME_SYSTEM
            "part_acce = %d, "
            #endif
            "last_play = NOW(), "
            "skill_group = %d, "
            "alignment = %ld, "
            "horse_level = %d, "
            "horse_riding = %d, "
            "horse_hp = %d, "
            "horse_hp_droptime = %u, "
            "horse_stamina = %d, "
            "horse_skill_point = %d, "
            ,
        GetTablePostfix(),
        pkTab->job,
        pkTab->voice,
        pkTab->dir,
        pkTab->x,
        pkTab->y,
        pkTab->z,
        pkTab->lMapIndex,
        pkTab->lExitX,
        pkTab->lExitY,
        pkTab->lExitMapIndex,
        pkTab->hp,
        pkTab->sp,
        pkTab->stamina,
        pkTab->sRandomHP,
        pkTab->sRandomSP,
        pkTab->playtime,
        pkTab->level,
        pkTab->level_step,
        pkTab->st,
        pkTab->ht,
        pkTab->dx,
        pkTab->iq,
        pkTab->gold,
        pkTab->exp,
        pkTab->stat_point,
        pkTab->skill_point,
        pkTab->sub_skill_point,
        pkTab->stat_reset_count,
        pkTab->ip,
        pkTab->parts[PART_MAIN],
        pkTab->parts[PART_HAIR],
#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
        pkTab->dwPickUPMode,
        pkTab->dwRarityMode,
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
        pkTab->shopFlag,
#endif
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
        pkTab->parts[PART_ACCE],
#endif
        pkTab->skill_group,
        pkTab->lAlignment,
        pkTab->horse.bLevel,
        pkTab->horse.bRiding,
        pkTab->horse.sHealth,
        pkTab->horse.dwHorseHealthDropTime,
        pkTab->horse.sStamina,
        pkTab->horse_skill_point);


    static char text[8192 + 1];

    CDBManager::instance().EscapeString(text, pkTab->skills, sizeof(pkTab->skills));
    queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "skill_level = '%s', ", text);

    CDBManager::instance().EscapeString(text, pkTab->quickslot, sizeof(pkTab->quickslot));
    queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "quickslot = '%s' ", text);

    queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, " WHERE id=%d", pkTab->id);
    return queryLen;
}

CPlayerTableCache * CClientManager::GetPlayerCache(DWORD id)
{
    TPlayerTableCacheMap::iterator it = m_map_playerCache.find(id);

    if (it == m_map_playerCache.end())
        return NULL;

    TPlayerTable* pTable = it->second->Get(false);
    pTable->logoff_interval = GetCurrentTime() - it->second->GetLastUpdateTime();
    return it->second;
}

void CClientManager::PutPlayerCache(TPlayerTable * pNew)
{
    CPlayerTableCache * c;

    c = GetPlayerCache(pNew->id);

    if (!c)
    {
        c = new CPlayerTableCache;
        m_map_playerCache.emplace(pNew->id, c);
    }

    if (g_bHotBackup)
        PlayerHB::instance().Put(pNew->id);

    c->Put(pNew);
}

/*
 * PLAYER LOAD
 */
void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoadPacket * packet)
{
    CPlayerTableCache * c;
    TPlayerTable * pTab;

    //

    //
    CLoginData * pLoginData = GetLoginDataByAID(packet->account_id);

    if (pLoginData)
    {
        for (int n = 0; n < PLAYER_PER_ACCOUNT; ++n)
            if (pLoginData->GetAccountRef().players[n].dwID != 0)
                DeleteLogoutPlayer(pLoginData->GetAccountRef().players[n].dwID);
    }

    //----------------------------------------------------------------


    // ---------------------------------------------------------------

    //----------------------------------

    //----------------------------------
    if ((c = GetPlayerCache(packet->player_id)))
    {
        CLoginData * pkLD = GetLoginDataByAID(packet->account_id);

        if (!pkLD || pkLD->IsPlay())
        {
            sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0);
            peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, dwHandle, 0);
            return;
        }

        pTab = c->Get();

        pkLD->SetPlay(true);
        SendLoginToBilling(pkLD, true);
        thecore_memcpy(pTab->aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(pTab->aiPremiumTimes));

        peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, dwHandle, sizeof(TPlayerTable));
        peer->Encode(pTab, sizeof(TPlayerTable));

        if (packet->player_id != pkLD->GetLastPlayerID())
        {
            TPacketNeedLoginLogInfo logInfo;
            logInfo.dwPlayerID = packet->player_id;

            pkLD->SetLastPlayerID( packet->player_id );

            peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, dwHandle, sizeof(TPacketNeedLoginLogInfo) );
            peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) );
        }

        char szQuery[1024] = { 0, };

        TItemCacheSet * pSet = GetItemCacheSet(pTab->id);

        sys_log(0, "[PLAYER_LOAD] ID %s pid %d gold %d ", pTab->name, pTab->id, pTab->gold);

        //--------------------------------------------

        //--------------------------------------------

        /////////////////////////////////////////////

        /////////////////////////////////////////////
        if (pSet)
        {
            static std::vector<TPlayerItem> s_items;
            s_items.resize(pSet->size());

            DWORD dwCount = 0;
            TItemCacheSet::iterator it = pSet->begin();

            while (it != pSet->end())
            {
                CItemCache * c = *it++;
                TPlayerItem * p = c->Get();

                if (p->vnum)
                    thecore_memcpy(&s_items[dwCount++], p, sizeof(TPlayerItem));
            }

            if (g_test_server)
                sys_log(0, "ITEM_CACHE: HIT! %s count: %u", pTab->name, dwCount);

            peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount);
            peer->EncodeDWORD(dwCount);

            if (dwCount)
                peer->Encode(&s_items[0], sizeof(TPlayerItem) * dwCount);

            // Quest
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID,szName,szState,lValue FROM quest%s WHERE dwPID=%d AND lValue<>0",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery, QID_QUEST, peer->GetHandle(), new ClientHandleInfo(dwHandle,0,packet->account_id));

            // Affect
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID,bType,bApplyOn,lApplyValue,dwFlag,lDuration,lSPCost FROM affect%s WHERE dwPID=%d",
                    GetTablePostfix(), pTab->id);
            // @fixme402 ClientHandleInfo+pTab->id
            CDBManager::instance().ReturnQuery(szQuery, QID_AFFECT, peer->GetHandle(), new ClientHandleInfo(dwHandle, pTab->id));
        }
        /////////////////////////////////////////////

        /////////////////////////////////////////////
        else
        {
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT id,`window`+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6 "
#ifdef ENABLE_SOULBIND_SYSTEM
                    ",sealbind "
#endif
                    "FROM item%s WHERE owner_id=%d AND (`window` in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY'"
#ifdef ENABLE_SWITCHBOT_WORLDARD
                    ",'SWITCHBOT'"
#endif
#ifdef FAST_EQUIP_WORLDARD
                    ",'CHANGE_EQUIP'"
#endif
                    "))",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery,
                    QID_ITEM,
                    peer->GetHandle(),
                    new ClientHandleInfo(dwHandle, pTab->id));
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID, szName, szState, lValue FROM quest%s WHERE dwPID=%d",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery,
                    QID_QUEST,
                    peer->GetHandle(),
                    new ClientHandleInfo(dwHandle, pTab->id));
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost FROM affect%s WHERE dwPID=%d",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery,
                    QID_AFFECT,
                    peer->GetHandle(),
                    new ClientHandleInfo(dwHandle, pTab->id));
        }
        //ljw
        //return;
    }
    //----------------------------------

    //----------------------------------
    else
    {
        sys_log(0, "[PLAYER_LOAD] Load from PlayerDB pid[%d]", packet->player_id);

        char queryStr[QUERY_MAX_LEN];

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT "
                "id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,playtime,"
                "gold,level,level_step,st,ht,dx,iq,exp,"
                "stat_point,skill_point,sub_skill_point,stat_reset_count,part_base,part_hair,"
#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
                "pick_up_mode,"
                "rarity_mode,"
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
                                                "shop_flag,"
#endif
                #ifdef ENABLE_ACCE_COSTUME_SYSTEM
                "part_acce, "
                #endif
                "skill_level,quickslot,skill_group,alignment,mobile,horse_level,horse_riding,horse_hp,horse_hp_droptime,horse_stamina,"
                "UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(last_play),horse_skill_point FROM player%s WHERE id=%d",
                GetTablePostfix(), packet->player_id);

        ClientHandleInfo * pkInfo = new ClientHandleInfo(dwHandle, packet->player_id);
        pkInfo->account_id = packet->account_id;
        CDBManager::instance().ReturnQuery(queryStr, QID_PLAYER, peer->GetHandle(), pkInfo);

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT id,`window`+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6 "
#ifdef ENABLE_SOULBIND_SYSTEM
                ",sealbind "
#endif
                "FROM item%s WHERE owner_id=%d AND (`window` in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY'"
#ifdef ENABLE_SWITCHBOT_WORLDARD
                ",'SWITCHBOT'"
#endif
#ifdef FAST_EQUIP_WORLDARD
                ",'CHANGE_EQUIP'"
#endif
                "))",
                GetTablePostfix(), packet->player_id);
        CDBManager::instance().ReturnQuery(queryStr, QID_ITEM, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT dwPID,szName,szState,lValue FROM quest%s WHERE dwPID=%d",
                GetTablePostfix(), packet->player_id);
        CDBManager::instance().ReturnQuery(queryStr, QID_QUEST, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id,packet->account_id));

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT dwPID,bType,bApplyOn,lApplyValue,dwFlag,lDuration,lSPCost FROM affect%s WHERE dwPID=%d",
                GetTablePostfix(), packet->player_id);
        CDBManager::instance().ReturnQuery(queryStr, QID_AFFECT, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));
    }
}


void CClientManager::ItemAward(CPeer * peer,char* login)
{
    char login_t[LOGIN_MAX_LEN + 1] = "";
    strlcpy(login_t,login,LOGIN_MAX_LEN + 1);
    std::set<TItemAward *> * pSet = ItemAwardManager::instance().GetByLogin(login_t);
    if(pSet == NULL)
        return;
    typeof(pSet->begin()) it = pSet->begin();
    while(it != pSet->end() )
    {
        TItemAward * pItemAward = *(it++);
        char* whyStr = pItemAward->szWhy;
        char cmdStr[100] = "";
        strcpy(cmdStr,whyStr);
        char command[20] = "";
        // @fixme203 directly GetCommand instead of strcpy
        GetCommand(cmdStr, command);
        if( !(strcmp(command,"GIFT") ))
        {
            TPacketItemAwardInfromer giftData;
            strcpy(giftData.login, pItemAward->szLogin);
            strcpy(giftData.command, command);
            giftData.vnum = pItemAward->dwVnum;
            ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer));
        }
    }
}
char* CClientManager::GetCommand(char* str, char* command) // @fixme203
{
    char* tok;

    if( str[0] == '[' )
    {
        tok = strtok(str,"]");
        strcat(command,&tok[1]);
    }

    return command;
}

bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
{
    if (mysql_num_rows(res) == 0)
        return false;

    memset(pkTab, 0, sizeof(TPlayerTable));

    MYSQL_ROW row = mysql_fetch_row(res);

    int    col = 0;

    // "id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,playtime,"
    // "gold,level,level_step,st,ht,dx,iq,exp,"
    // "stat_point,skill_point,sub_skill_point,stat_reset_count,part_base,part_hair,"
    // "skill_level,quickslot,skill_group,alignment,mobile,horse_level,horse_riding,horse_hp,horse_stamina FROM player%s WHERE id=%d",
    str_to_number(pkTab->id, row[col++]);
    strlcpy(pkTab->name, row[col++], sizeof(pkTab->name));
    str_to_number(pkTab->job, row[col++]);
    str_to_number(pkTab->voice, row[col++]);
    str_to_number(pkTab->dir, row[col++]);
    str_to_number(pkTab->x, row[col++]);
    str_to_number(pkTab->y, row[col++]);
    str_to_number(pkTab->z, row[col++]);
    str_to_number(pkTab->lMapIndex, row[col++]);
    str_to_number(pkTab->lExitX, row[col++]);
    str_to_number(pkTab->lExitY, row[col++]);
    str_to_number(pkTab->lExitMapIndex,  row[col++]);
    str_to_number(pkTab->hp, row[col++]);
    str_to_number(pkTab->sp, row[col++]);
    str_to_number(pkTab->stamina, row[col++]);
    str_to_number(pkTab->sRandomHP, row[col++]);
    str_to_number(pkTab->sRandomSP, row[col++]);
    str_to_number(pkTab->playtime, row[col++]);
    str_to_number(pkTab->gold, row[col++]);
    str_to_number(pkTab->level, row[col++]);
    str_to_number(pkTab->level_step, row[col++]);
    str_to_number(pkTab->st, row[col++]);
    str_to_number(pkTab->ht, row[col++]);
    str_to_number(pkTab->dx, row[col++]);
    str_to_number(pkTab->iq, row[col++]);
    str_to_number(pkTab->exp, row[col++]);
    str_to_number(pkTab->stat_point, row[col++]);
    str_to_number(pkTab->skill_point, row[col++]);
    str_to_number(pkTab->sub_skill_point, row[col++]);
    str_to_number(pkTab->stat_reset_count, row[col++]);
    str_to_number(pkTab->part_base, row[col++]);
    str_to_number(pkTab->parts[PART_HAIR], row[col++]);
#ifdef ENABLE_OFFLINESHOP_SYSTEM
    str_to_number(pkTab->shopFlag, row[col++]);
#endif
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
    str_to_number(pkTab->parts[PART_ACCE], row[col++]);
#endif

    if (row[col])
        thecore_memcpy(pkTab->skills, row[col], sizeof(pkTab->skills));
    else
        memset(&pkTab->skills, 0, sizeof(pkTab->skills));

    col++;

    if (row[col])
        thecore_memcpy(pkTab->quickslot, row[col], sizeof(pkTab->quickslot));
    else
        memset(pkTab->quickslot, 0, sizeof(pkTab->quickslot));

    col++;

    str_to_number(pkTab->skill_group, row[col++]);
    str_to_number(pkTab->lAlignment, row[col++]);

    if (row[col])
    {
        strlcpy(pkTab->szMobile, row[col], sizeof(pkTab->szMobile));
    }

    col++;

    str_to_number(pkTab->horse.bLevel, row[col++]);
    str_to_number(pkTab->horse.bRiding, row[col++]);
    str_to_number(pkTab->horse.sHealth, row[col++]);
    str_to_number(pkTab->horse.dwHorseHealthDropTime, row[col++]);
    str_to_number(pkTab->horse.sStamina, row[col++]);
    str_to_number(pkTab->logoff_interval, row[col++]);
    str_to_number(pkTab->horse_skill_point, row[col++]);

    // reset sub_skill_point
    {
        pkTab->skills[123].bLevel = 0; // SKILL_CREATE

        if (pkTab->level > 9)
        {
            int max_point = pkTab->level - 9;

            int skill_point =
                MIN(20, pkTab->skills[121].bLevel) +
                MIN(20, pkTab->skills[124].bLevel) +
                MIN(10, pkTab->skills[131].bLevel) +
                MIN(20, pkTab->skills[141].bLevel) +
                MIN(20, pkTab->skills[142].bLevel);

            pkTab->sub_skill_point = max_point - skill_point;
        }
        else
            pkTab->sub_skill_point = 0;
    }

    return true;
}

void CClientManager::RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD dwQID)
{
    CQueryInfo * qi = (CQueryInfo *) pMsg->pvUserData;
    std::unique_ptr<ClientHandleInfo> info((ClientHandleInfo *) qi->pvData);

    MYSQL_RES * pSQLResult = pMsg->Get()->pSQLResult;
    if (!pSQLResult)
    {
        sys_err("null MYSQL_RES QID %u", dwQID);
        return;
    }

    switch (dwQID)
    {
        case QID_PLAYER:
            sys_log(0, "QID_PLAYER %u %u", info->dwHandle, info->player_id);
            RESULT_PLAYER_LOAD(peer, pSQLResult, info.get());

            break;

        case QID_ITEM:
            sys_log(0, "QID_ITEM %u", info->dwHandle);
            RESULT_ITEM_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
            break;

        case QID_QUEST:
            {
                sys_log(0, "QID_QUEST %u", info->dwHandle);
                RESULT_QUEST_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);

                ClientHandleInfo*  temp1 = info.get();
                if (temp1 == NULL)
                    break;

                CLoginData* pLoginData1 = GetLoginDataByAID(temp1->account_id);    //

                if( pLoginData1->GetAccountRef().login == NULL)
                    break;
                if( pLoginData1 == NULL )
                    break;
                sys_log(0,"info of pLoginData1 before call ItemAwardfunction %d",pLoginData1);
                ItemAward(peer,pLoginData1->GetAccountRef().login);
            }
            break;

        case QID_AFFECT:
            sys_log(0, "QID_AFFECT %u", info->dwHandle);
            // @fixme402 RESULT_AFFECT_LOAD+info->player_id
            RESULT_AFFECT_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
            break;
            /*
               case QID_PLAYER_ITEM_QUEST_AFFECT:
               sys_log(0, "QID_PLAYER_ITEM_QUEST_AFFECT %u", info->dwHandle);
               RESULT_PLAYER_LOAD(peer, pSQLResult, info->dwHandle);

               if (!pMsg->Next())
               {
               sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: ITEM FAILED");
               return;
               }

               case QID_ITEM_QUEST_AFFECT:
               sys_log(0, "QID_ITEM_QUEST_AFFECT %u", info->dwHandle);
               RESULT_ITEM_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);

               if (!pMsg->Next())
               {
               sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: QUEST FAILED");
               return;
               }

               case QID_QUEST_AFFECT:
               sys_log(0, "QID_QUEST_AFFECT %u", info->dwHandle);
               RESULT_QUEST_LOAD(peer, pSQLResult, info->dwHandle);

               if (!pMsg->Next())
               sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: AFFECT FAILED");
               else
               RESULT_AFFECT_LOAD(peer, pSQLResult, info->dwHandle);

               break;
               */
    }

}

void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHandleInfo * pkInfo)
{
    TPlayerTable tab;

    if (!CreatePlayerTableFromRes(pRes, &tab))
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0);
        return;
    }

    CLoginData * pkLD = GetLoginDataByAID(pkInfo->account_id);

    if (!pkLD || pkLD->IsPlay())
    {
        sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0);
        peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0);
        return;
    }

    pkLD->SetPlay(true);
    SendLoginToBilling(pkLD, true);
    thecore_memcpy(tab.aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(tab.aiPremiumTimes));

    peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, pkInfo->dwHandle, sizeof(TPlayerTable));
    peer->Encode(&tab, sizeof(TPlayerTable));

    if (tab.id != pkLD->GetLastPlayerID())
    {
        TPacketNeedLoginLogInfo logInfo;
        logInfo.dwPlayerID = tab.id;

        pkLD->SetLastPlayerID( tab.id );

        peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, pkInfo->dwHandle, sizeof(TPacketNeedLoginLogInfo) );
        peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) );
    }
}

void CClientManager::RESULT_ITEM_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwPID)
{
    static std::vector<TPlayerItem> s_items;

    CreateItemTableFromRes(pRes, &s_items, dwPID);
    DWORD dwCount = s_items.size();

    peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount);
    peer->EncodeDWORD(dwCount);


    CreateItemCacheSet(dwPID);

    // ITEM_LOAD_LOG_ATTACH_PID
    sys_log(0, "ITEM_LOAD: count %u pid %u", dwCount, dwPID);
    // END_OF_ITEM_LOAD_LOG_ATTACH_PID

    if (dwCount)
    {
        peer->Encode(&s_items[0], sizeof(TPlayerItem) * dwCount);

        for (DWORD i = 0; i < dwCount; ++i)
            PutItemCache(&s_items[i], true);
    }
}

// @fixme402 (RESULT_AFFECT_LOAD +dwRealPID)
void CClientManager::RESULT_AFFECT_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwRealPID)
{
    int iNumRows;

    if ((iNumRows = mysql_num_rows(pRes)) == 0)
    {
        // @fixme402 begin
        static DWORD dwPID;
        static DWORD dwCount = 0; //1;
        static TPacketAffectElement paeTable = {0};

        dwPID = dwRealPID;
        sys_log(0, "AFFECT_LOAD: count %u PID %u RealPID %u", dwCount, dwPID, dwRealPID);

        peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount);
        peer->Encode(&dwPID, sizeof(DWORD));
        peer->Encode(&dwCount, sizeof(DWORD));
        peer->Encode(&paeTable, sizeof(TPacketAffectElement) * dwCount);
        // @fixme402 end
        return;
    }

    static std::vector<TPacketAffectElement> s_elements;
    s_elements.resize(iNumRows);

    DWORD dwPID = 0;

    MYSQL_ROW row;

    for (int i = 0; i < iNumRows; ++i)
    {
        TPacketAffectElement & r = s_elements[i];
        row = mysql_fetch_row(pRes);

        if (dwPID == 0)
            str_to_number(dwPID, row[0]);

        str_to_number(r.dwType, row[1]);
        str_to_number(r.bApplyOn, row[2]);
        str_to_number(r.lApplyValue, row[3]);
        str_to_number(r.dwFlag, row[4]);
        str_to_number(r.lDuration, row[5]);
        str_to_number(r.lSPCost, row[6]);
    }

    sys_log(0, "AFFECT_LOAD: count %d PID %u", s_elements.size(), dwPID);

    DWORD dwCount = s_elements.size();

    peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount);
    peer->Encode(&dwPID, sizeof(DWORD));
    peer->Encode(&dwCount, sizeof(DWORD));
    peer->Encode(&s_elements[0], sizeof(TPacketAffectElement) * dwCount);
}

void CClientManager::RESULT_QUEST_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD pid)
{
    int iNumRows;

    if ((iNumRows = mysql_num_rows(pRes)) == 0)
    {
        DWORD dwCount = 0;
        peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD));
        peer->Encode(&dwCount, sizeof(DWORD));
        return;
    }

    static std::vector<TQuestTable> s_table;
    s_table.resize(iNumRows);

    MYSQL_ROW row;

    for (int i = 0; i < iNumRows; ++i)
    {
        TQuestTable & r = s_table[i];

        row = mysql_fetch_row(pRes);

        str_to_number(r.dwPID, row[0]);
        strlcpy(r.szName, row[1], sizeof(r.szName));
        strlcpy(r.szState, row[2], sizeof(r.szState));
        str_to_number(r.lValue, row[3]);
    }

    sys_log(0, "QUEST_LOAD: count %d PID %u", s_table.size(), s_table[0].dwPID);

    DWORD dwCount = s_table.size();

    peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD) + sizeof(TQuestTable) * dwCount);
    peer->Encode(&dwCount, sizeof(DWORD));
    peer->Encode(&s_table[0], sizeof(TQuestTable) * dwCount);
}

/*
 * PLAYER SAVE
 */
void CClientManager::QUERY_PLAYER_SAVE(CPeer * peer, DWORD dwHandle, TPlayerTable * pkTab)
{
    if (g_test_server)
        sys_log(0, "PLAYER_SAVE: %s", pkTab->name);

    PutPlayerCache(pkTab);
}

typedef std::map<DWORD, time_t> time_by_id_map_t;
static time_by_id_map_t s_createTimeByAccountID;

/*
 * PLAYER CREATE
 */
void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerCreatePacket* packet)
{
    char    queryStr[QUERY_MAX_LEN];
    int        queryLen;
    int        player_id;


    time_by_id_map_t::iterator it = s_createTimeByAccountID.find(packet->account_id);

    if (it != s_createTimeByAccountID.end())
    {
        time_t curtime = time(0);

        if (curtime - it->second < 30)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
            return;
        }
    }

    queryLen = snprintf(queryStr, sizeof(queryStr),
            "SELECT pid%u FROM player_index%s WHERE id=%d", packet->account_index + 1, GetTablePostfix(), packet->account_id);

    auto pMsg0(CDBManager::instance().DirectQuery(queryStr));
    if (pMsg0->Get()->uiNumRows != 0)
    {
        if (!pMsg0->Get()->pSQLResult)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
            return;
        }

        MYSQL_ROW row = mysql_fetch_row(pMsg0->Get()->pSQLResult);

        DWORD dwPID = 0; str_to_number(dwPID, row[0]);
        if (row[0] && dwPID > 0)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
            sys_log(0, "ALREADY EXIST AccountChrIdx %d ID %d", packet->account_index, dwPID);
            return;
        }
    }
    else
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
        return;
    }

    if (g_stLocale == "sjis")
        snprintf(queryStr, sizeof(queryStr),
            "SELECT COUNT(*) as count FROM player%s WHERE name='%s' collate sjis_japanese_ci",
            GetTablePostfix(), packet->player_table.name);
    else
    snprintf(queryStr, sizeof(queryStr),
            "SELECT COUNT(*) as count FROM player%s WHERE name='%s'", GetTablePostfix(), packet->player_table.name);

    auto pMsg1(CDBManager::instance().DirectQuery(queryStr));
    if (pMsg1->Get()->uiNumRows)
    {
        if (!pMsg1->Get()->pSQLResult)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
            return;
        }

        MYSQL_ROW row = mysql_fetch_row(pMsg1->Get()->pSQLResult);

        if (*row[0] != '0')
        {
            sys_log(0, "ALREADY EXIST name %s, row[0] %s query %s", packet->player_table.name, row[0], queryStr);
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
            return;
        }
    }
    else
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
        return;
    }

    queryLen = snprintf(queryStr, sizeof(queryStr),
            "INSERT INTO player%s "
            "(id, account_id, name, level, st, ht, dx, iq, "
            "job, voice, dir, x, y, z, "
            "hp, mp, random_hp, random_sp, stat_point, stamina, part_base, part_main, part_hair,"
            #ifdef ENABLE_ACCE_COSTUME_SYSTEM
            "part_acce, "
            #endif
            " gold, playtime, "
            "skill_level, quickslot) "
            "VALUES(0, %u, '%s', %d, %d, %d, %d, %d, "
            "%d, %d, %d, %d, %d, %d, %d, "
            "%d, %d, %d, %d, %d, %d, %d, 0, "
            #ifdef ENABLE_ACCE_COSTUME_SYSTEM
            "0, "
            #endif
            "%d, 0, ",
            GetTablePostfix(),
            packet->account_id, packet->player_table.name, packet->player_table.level, packet->player_table.st, packet->player_table.ht, packet->player_table.dx, packet->player_table.iq,
            packet->player_table.job, packet->player_table.voice, packet->player_table.dir, packet->player_table.x, packet->player_table.y, packet->player_table.z,
            packet->player_table.hp, packet->player_table.sp, packet->player_table.sRandomHP, packet->player_table.sRandomSP, packet->player_table.stat_point, packet->player_table.stamina, packet->player_table.part_base, packet->player_table.part_base, packet->player_table.gold);

    sys_log(0, "PlayerCreate accountid %d name %s level %d gold %d, st %d ht %d job %d",
            packet->account_id,
            packet->player_table.name,
            packet->player_table.level,
            packet->player_table.gold,
            packet->player_table.st,
            packet->player_table.ht,
            packet->player_table.job);

    static char text[4096 + 1];

    CDBManager::instance().EscapeString(text, packet->player_table.skills, sizeof(packet->player_table.skills));
    queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s', ", text);
    if (g_test_server)
        sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);

    CDBManager::instance().EscapeString(text, packet->player_table.quickslot, sizeof(packet->player_table.quickslot));
    queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s')", text);

    auto pMsg2(CDBManager::instance().DirectQuery(queryStr));
    if (g_test_server)
        sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);

    if (pMsg2->Get()->uiAffectedRows <= 0)
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
        sys_log(0, "ALREADY EXIST3 query: %s AffectedRows %lu", queryStr, pMsg2->Get()->uiAffectedRows);
        return;
    }

    player_id = pMsg2->Get()->uiInsertID;

    snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%d=%d WHERE id=%d",
            GetTablePostfix(), packet->account_index + 1, player_id, packet->account_id);

    auto pMsg3(CDBManager::instance().DirectQuery(queryStr));
    if (pMsg3->Get()->uiAffectedRows <= 0)
    {
        sys_err("QUERY_ERROR: %s", queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), player_id);
        CDBManager::instance().DirectQuery(queryStr);

        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
        return;
    }

    TPacketDGCreateSuccess pack;
    memset(&pack, 0, sizeof(pack));

    pack.bAccountCharacterIndex = packet->account_index;

    pack.player.dwID            = player_id;
    strlcpy(pack.player.szName, packet->player_table.name, sizeof(pack.player.szName));
    pack.player.byJob            = packet->player_table.job;
    pack.player.byLevel            = 1;
    pack.player.dwPlayMinutes    = 0;
    pack.player.byST            = packet->player_table.st;
    pack.player.byHT            = packet->player_table.ht;
    pack.player.byDX             = packet->player_table.dx;
    pack.player.byIQ            = packet->player_table.iq;
    pack.player.wMainPart        = packet->player_table.part_base;
    pack.player.x            = packet->player_table.x;
    pack.player.y            = packet->player_table.y;

    peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_SUCCESS, dwHandle, sizeof(TPacketDGCreateSuccess));
    peer->Encode(&pack, sizeof(TPacketDGCreateSuccess));

    sys_log(0, "7 name %s job %d", pack.player.szName, pack.player.byJob);

    s_createTimeByAccountID[packet->account_id] = time(0);
}

/*
 * PLAYER DELETE
 */
void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerDeletePacket* packet)
{
    if (!packet->login[0] || !packet->player_id || packet->account_index >= PLAYER_PER_ACCOUNT)
        return;

    CLoginData * ld = GetLoginDataByLogin(packet->login);

    if (!ld)
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
        peer->EncodeBYTE(packet->account_index);
        return;
    }

    TAccountTable & r = ld->GetAccountRef();

    // block for japan
    if (g_stLocale != "sjis")
    {
        if (!IsChinaEventServer())
        {
            if (strlen(r.social_id) < 7 || strncmp(packet->private_code, r.social_id + strlen(r.social_id) - 7, 7))
            {
                sys_log(0, "PLAYER_DELETE FAILED len(%d)", strlen(r.social_id));
                peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
                peer->EncodeBYTE(packet->account_index);
                return;
            }

            CPlayerTableCache * pkPlayerCache = GetPlayerCache(packet->player_id);
            if (pkPlayerCache)
            {
                TPlayerTable * pTab = pkPlayerCache->Get();

                if (pTab->level >= m_iPlayerDeleteLevelLimit)
                {
                    sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimit);
                    peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
                    peer->EncodeBYTE(packet->account_index);
                    return;
                }

                if (pTab->level < m_iPlayerDeleteLevelLimitLower)
                {
                    sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimitLower);
                    peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
                    peer->EncodeBYTE(packet->account_index);
                    return;
                }
            }
        }
    }

    char szQuery[128];
    snprintf(szQuery, sizeof(szQuery), "SELECT p.id, p.level, p.name FROM player_index%s AS i, player%s AS p WHERE pid%u=%u AND pid%u=p.id",
            GetTablePostfix(), GetTablePostfix(), packet->account_index + 1, packet->player_id, packet->account_index + 1);

    ClientHandleInfo * pi = new ClientHandleInfo(dwHandle, packet->player_id);
    pi->account_index = packet->account_index;

    sys_log(0, "PLAYER_DELETE TRY: %s %d pid%d", packet->login, packet->player_id, packet->account_index + 1);
    CDBManager::instance().ReturnQuery(szQuery, QID_PLAYER_DELETE, peer->GetHandle(), pi);
}

//

//
void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
{
    CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
    ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;

    if (msg->Get() && msg->Get()->uiNumRows)
    {
        MYSQL_ROW row = mysql_fetch_row(msg->Get()->pSQLResult);

        DWORD dwPID = 0;
        str_to_number(dwPID, row[0]);

        int deletedLevelLimit = 0;
        str_to_number(deletedLevelLimit, row[1]);

        char szName[64];
        strlcpy(szName, row[2], sizeof(szName));

        if (deletedLevelLimit >= m_iPlayerDeleteLevelLimit && !IsChinaEventServer())
        {
            sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimit);
            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }

        if (deletedLevelLimit < m_iPlayerDeleteLevelLimitLower)
        {
            sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimitLower);
            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }

        char queryStr[QUERY_MAX_LEN];

        snprintf(queryStr, sizeof(queryStr), "INSERT INTO player%s_deleted SELECT * FROM player%s WHERE id=%d",
                GetTablePostfix(), GetTablePostfix(), pi->player_id);
        auto pIns(CDBManager::instance().DirectQuery(queryStr));

        if (pIns->Get()->uiAffectedRows == 0 || pIns->Get()->uiAffectedRows == (uint32_t)-1)
        {
            sys_log(0, "PLAYER_DELETE FAILED %u CANNOT INSERT TO player%s_deleted", dwPID, GetTablePostfix());

            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }


        sys_log(0, "PLAYER_DELETE SUCCESS %u", dwPID);

        char account_index_string[16];

        snprintf(account_index_string, sizeof(account_index_string), "player_id%d", m_iPlayerIDStart + pi->account_index);


        CPlayerTableCache * pkPlayerCache = GetPlayerCache(pi->player_id);

        if (pkPlayerCache)
        {
            m_map_playerCache.erase(pi->player_id);
            delete pkPlayerCache;
        }


        TItemCacheSet * pSet = GetItemCacheSet(pi->player_id);

        if (pSet)
        {
            TItemCacheSet::iterator it = pSet->begin();

            while (it != pSet->end())
            {
                CItemCache * pkItemCache = *it++;
                DeleteItemCache(pkItemCache->Get()->id);
            }

            pSet->clear();
            delete pSet;

            m_map_pkItemCacheSetPtr.erase(pi->player_id);
        }

        snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%u=0 WHERE pid%u=%d",
                GetTablePostfix(),
                pi->account_index + 1,
                pi->account_index + 1,
                pi->player_id);

        auto pMsg(CDBManager::instance().DirectQuery(queryStr));
        if (pMsg->Get()->uiAffectedRows == 0 || pMsg->Get()->uiAffectedRows == (uint32_t)-1)
        {
            sys_log(0, "PLAYER_DELETE FAIL WHEN UPDATE account table");
            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().DirectQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM item%s WHERE owner_id=%d AND (`window` in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY'"
#ifdef ENABLE_SWITCHBOT_WORLDARD
        ",'SWITCHBOT'"
#endif
#ifdef FAST_EQUIP_WORLDARD
        ",'CHANGE_EQUIP'"
#endif
        "))", GetTablePostfix(), pi->player_id);
        CDBManager::instance().DirectQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM quest%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM affect%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM guild_member%s WHERE pid=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);

        // MYSHOP_PRICE_LIST
        snprintf(queryStr, sizeof(queryStr), "DELETE FROM myshop_pricelist%s WHERE owner_id=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);
        // END_OF_MYSHOP_PRICE_LIST

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'", GetTablePostfix(), szName, szName);
        CDBManager::instance().AsyncQuery(queryStr);

        peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_SUCCESS, pi->dwHandle, 1);
        peer->EncodeBYTE(pi->account_index);
    }
    else
    {

        sys_log(0, "PLAYER_DELETE FAIL NO ROW");
        peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
        peer->EncodeBYTE(pi->account_index);
    }
}

void CClientManager::QUERY_ADD_AFFECT(CPeer * peer, TPacketGDAddAffect * p)
{
    char queryStr[QUERY_MAX_LEN];
    /*
       snprintf(queryStr, sizeof(queryStr),
       "INSERT INTO affect%s (dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost) "
       "VALUES(%u, %u, %u, %d, %u, %d, %d) "
       "ON DUPLICATE KEY UPDATE lApplyValue=%d, dwFlag=%u, lDuration=%d, lSPCost=%d",
       GetTablePostfix(),
       p->dwPID,
       p->elem.dwType,
       p->elem.bApplyOn,
       p->elem.lApplyValue,
       p->elem.dwFlag,
       p->elem.lDuration,
       p->elem.lSPCost,
       p->elem.lApplyValue,
       p->elem.dwFlag,
       p->elem.lDuration,
       p->elem.lSPCost);
       */
    snprintf(queryStr, sizeof(queryStr),
            "REPLACE INTO affect%s (dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost) "
            "VALUES(%u, %u, %u, %ld, %u, %ld, %ld)",
            GetTablePostfix(),
            p->dwPID,
            p->elem.dwType,
            p->elem.bApplyOn,
            p->elem.lApplyValue,
            p->elem.dwFlag,
            p->elem.lDuration,
            p->elem.lSPCost);

    CDBManager::instance().AsyncQuery(queryStr);
}

void CClientManager::QUERY_REMOVE_AFFECT(CPeer * peer, TPacketGDRemoveAffect * p)
{
    char queryStr[QUERY_MAX_LEN];

    snprintf(queryStr, sizeof(queryStr),
            "DELETE FROM affect%s WHERE dwPID=%u AND bType=%u AND bApplyOn=%u",
            GetTablePostfix(), p->dwPID, p->dwType, p->bApplyOn);

    CDBManager::instance().AsyncQuery(queryStr);
}


void CClientManager::QUERY_HIGHSCORE_REGISTER(CPeer* peer, TPacketGDHighscore * data)
{
    char szQuery[128];
    snprintf(szQuery, sizeof(szQuery), "SELECT value FROM highscore%s WHERE board='%s' AND pid = %u", GetTablePostfix(), data->szBoard, data->dwPID);

    sys_log(0, "HEADER_GD_HIGHSCORE_REGISTER: PID %u", data->dwPID);

    ClientHandleInfo * pi = new ClientHandleInfo(0);
    strlcpy(pi->login, data->szBoard, sizeof(pi->login));
    pi->account_id = (DWORD)data->lValue;
    pi->player_id = data->dwPID;
    pi->account_index = (data->cDir > 0);

    CDBManager::instance().ReturnQuery(szQuery, QID_HIGHSCORE_REGISTER, peer->GetHandle(), pi);
}

void CClientManager::RESULT_HIGHSCORE_REGISTER(CPeer * pkPeer, SQLMsg * msg)
{
    CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
    ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;
    //DWORD dwHandle = pi->dwHandle;

    char szBoard[21];
    strlcpy(szBoard, pi->login, sizeof(szBoard));
    int value = (int)pi->account_id;

    SQLResult * res = msg->Get();

    if (res->uiNumRows == 0)
    {

        char buf[256];
        snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
        CDBManager::instance().AsyncQuery(buf);
    }
    else
    {
        if (!res->pSQLResult)
        {
            delete pi;
            return;
        }

        MYSQL_ROW row = mysql_fetch_row(res->pSQLResult);
        if (row && row[0])
        {
            int current_value = 0; str_to_number(current_value, row[0]);
            if (((pi->account_index)&&(current_value >= value)) || ((!pi->account_index)&&(current_value <= value)))
            {
                value = current_value;
            }
            else
            {
                char buf[256];
                snprintf(buf, sizeof(buf), "REPLACE INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
                CDBManager::instance().AsyncQuery(buf);
            }
        }
        else
        {
            char buf[256];
            snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
            CDBManager::instance().AsyncQuery(buf);
        }
    }

    delete pi;
}

void CClientManager::InsertLogoutPlayer(DWORD pid)
{
    TLogoutPlayerMap::iterator it = m_map_logout.find(pid);


    if (it != m_map_logout.end())
    {

        if (g_log)
            sys_log(0, "LOGOUT: Update player time pid(%d)", pid);

        it->second->time = time(0);
        return;
    }

    TLogoutPlayer * pLogout = new TLogoutPlayer;
    pLogout->pid = pid;
    pLogout->time = time(0);
    m_map_logout.emplace(pid, pLogout);

    if (g_log)
        sys_log(0, "LOGOUT: Insert player pid(%d)", pid);
}

void CClientManager::DeleteLogoutPlayer(DWORD pid)
{
    TLogoutPlayerMap::iterator it = m_map_logout.find(pid);

    if (it != m_map_logout.end())
    {
        delete it->second;
        m_map_logout.erase(it);
    }
}

extern int g_iLogoutSeconds;

void CClientManager::UpdateLogoutPlayer()
{
    time_t now = time(0);

    TLogoutPlayerMap::iterator it = m_map_logout.begin();

    while (it != m_map_logout.end())
    {
        TLogoutPlayer* pLogout = it->second;

        if (now - g_iLogoutSeconds > pLogout->time)
        {
            FlushItemCacheSet(pLogout->pid);
            FlushPlayerCacheSet(pLogout->pid);

            delete pLogout;
            m_map_logout.erase(it++);
        }
        else
            ++it;
    }
}

void CClientManager::FlushPlayerCacheSet(DWORD pid)
{
    TPlayerTableCacheMap::iterator it = m_map_playerCache.find(pid);

    if (it != m_map_playerCache.end())
    {
        CPlayerTableCache * c = it->second;
        m_map_playerCache.erase(it);

        c->Flush();
        delete c;
    }
}


 

 

Link to comment
Share on other sites

  • Honorable Member

Check in player table if it's correctly storing both the skill levels and skill_group

xGFmly8.png

0328 means skill grade P (0x03), skill level 40 (0x28)

Every skill id takes 6 bytes (0328 0000 0000)

Edited by Metin2 Dev International
Core X - External 2 Internal
  • Love 2
Link to comment
Share on other sites

stupid question but do you run your server local from visual studio?
if yes, i had the same issues after i took my skills from npc/quest and slighty after restartet the server my skills are gone + the qf where set that i got the skills.

i did solved it by just waiting some time between getting skills and restarting it.

its not happening on freebsd, just using killall -1 db game auth instead of killall -9 db game auth.

  • Metin2 Dev 1
Link to comment
Share on other sites

The problem is solved. ClientManagerPlayer.cpp is missing some data

thank you @ Mitachi He helped me solve this annoying problem, which took about 2 minutes!

Quote

#include "stdafx.h"

#include "ClientManager.h"

#include "Main.h"
#include "QID.h"
#include "ItemAwardManager.h"
#include "HB.h"
#include "Cache.h"

extern bool g_bHotBackup;

extern std::string g_stLocale;
extern int g_test_server;
extern int g_log;

//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!! IMPORTANT !!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// Check all SELECT syntax on item table before change this function!!!
//
bool CreateItemTableFromRes(MYSQL_RES * res, std::vector<TPlayerItem> * pVec, DWORD dwPID)
{
    if (!res)
    {
        pVec->clear();
        return true;
    }

    int rows;

    if ((rows = mysql_num_rows(res)) <= 0)
    {
        pVec->clear();
        return true;
    }

    pVec->resize(rows);

    for (int i = 0; i < rows; ++i)
    {
        MYSQL_ROW row = mysql_fetch_row(res);
        TPlayerItem & item = pVec->at(i);

        int cur = 0;

        // Check all SELECT syntax on item table before change this function!!!
        // Check all SELECT syntax on item table before change this function!!!
        // Check all SELECT syntax on item table before change this function!!!
        str_to_number(item.id, row[cur++]);
        str_to_number(item.window, row[cur++]);
        str_to_number(item.pos, row[cur++]);
        str_to_number(item.count, row[cur++]);
        str_to_number(item.vnum, row[cur++]);
        str_to_number(item.alSockets[0], row[cur++]);
        str_to_number(item.alSockets[1], row[cur++]);
        str_to_number(item.alSockets[2], row[cur++]);

        for (int j = 0; j < ITEM_ATTRIBUTE_MAX_NUM; j++)
        {
            str_to_number(item.aAttr[j].bType, row[cur++]);
            str_to_number(item.aAttr[j].sValue, row[cur++]);
        }
#ifdef ENABLE_SOULBIND_SYSTEM
        str_to_number(item.sealbind, row[cur++]);
#endif

        item.owner        = dwPID;
    }

    return true;
}

size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * pkTab)
{
    size_t queryLen;

    queryLen = snprintf(pszQuery, querySize,
            "UPDATE player%s SET "
            "job = %d, "
            "voice = %d, "
            "dir = %d, "
            "x = %d, "
            "y = %d, "
            "z = %d, "
            "map_index = %d, "
            "exit_x = %ld, "
            "exit_y = %ld, "
            "exit_map_index = %ld, "
            "hp = %d, "
            "mp = %d, "
            "stamina = %d, "
            "random_hp = %d, "
            "random_sp = %d, "
            "playtime = %d, "
            "level = %d, "
            "level_step = %d, "
            "st = %d, "
            "ht = %d, "
            "dx = %d, "
            "iq = %d, "
            "gold = %d, "
            "exp = %u, "
            "stat_point = %d, "
            "skill_point = %d, "
            "sub_skill_point = %d, "
            "stat_reset_count = %d, "
            "ip = '%s', "
            "part_main = %d, "
            "part_hair = %d, "
#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
            "pick_up_mode = %d, "
            "rarity_mode = %d, "
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
            "shop_flag = %llu, "
#endif
            #ifdef ENABLE_ACCE_COSTUME_SYSTEM
            "part_acce = %d, "
            #endif
            "last_play = NOW(), "
            "skill_group = %d, "
            "alignment = %ld, "
            "horse_level = %d, "
            "horse_riding = %d, "
            "horse_hp = %d, "
            "horse_hp_droptime = %u, "
            "horse_stamina = %d, "
            "horse_skill_point = %d, "
            ,
        GetTablePostfix(),
        pkTab->job,
        pkTab->voice,
        pkTab->dir,
        pkTab->x,
        pkTab->y,
        pkTab->z,
        pkTab->lMapIndex,
        pkTab->lExitX,
        pkTab->lExitY,
        pkTab->lExitMapIndex,
        pkTab->hp,
        pkTab->sp,
        pkTab->stamina,
        pkTab->sRandomHP,
        pkTab->sRandomSP,
        pkTab->playtime,
        pkTab->level,
        pkTab->level_step,
        pkTab->st,
        pkTab->ht,
        pkTab->dx,
        pkTab->iq,
        pkTab->gold,
        pkTab->exp,
        pkTab->stat_point,
        pkTab->skill_point,
        pkTab->sub_skill_point,
        pkTab->stat_reset_count,
        pkTab->ip,
        pkTab->parts[PART_MAIN],
        pkTab->parts[PART_HAIR],
#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
        pkTab->dwPickUPMode,
        pkTab->dwRarityMode,
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
        pkTab->shopFlag,
#endif
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
        pkTab->parts[PART_ACCE],
#endif
        pkTab->skill_group,
        pkTab->lAlignment,
        pkTab->horse.bLevel,
        pkTab->horse.bRiding,
        pkTab->horse.sHealth,
        pkTab->horse.dwHorseHealthDropTime,
        pkTab->horse.sStamina,
        pkTab->horse_skill_point);


    static char text[8192 + 1];

    CDBManager::instance().EscapeString(text, pkTab->skills, sizeof(pkTab->skills));
    queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "skill_level = '%s', ", text);

    CDBManager::instance().EscapeString(text, pkTab->quickslot, sizeof(pkTab->quickslot));
    queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "quickslot = '%s' ", text);

    queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, " WHERE id=%d", pkTab->id);
    return queryLen;
}

CPlayerTableCache * CClientManager::GetPlayerCache(DWORD id)
{
    TPlayerTableCacheMap::iterator it = m_map_playerCache.find(id);

    if (it == m_map_playerCache.end())
        return NULL;

    TPlayerTable* pTable = it->second->Get(false);
    pTable->logoff_interval = GetCurrentTime() - it->second->GetLastUpdateTime();
    return it->second;
}

void CClientManager::PutPlayerCache(TPlayerTable * pNew)
{
    CPlayerTableCache * c;

    c = GetPlayerCache(pNew->id);

    if (!c)
    {
        c = new CPlayerTableCache;
        m_map_playerCache.emplace(pNew->id, c);
    }

    if (g_bHotBackup)
        PlayerHB::instance().Put(pNew->id);

    c->Put(pNew);
}

/*
 * PLAYER LOAD
 */
void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoadPacket * packet)
{
    CPlayerTableCache * c;
    TPlayerTable * pTab;

    //

    //
    CLoginData * pLoginData = GetLoginDataByAID(packet->account_id);

    if (pLoginData)
    {
        for (int n = 0; n < PLAYER_PER_ACCOUNT; ++n)
            if (pLoginData->GetAccountRef().players[n].dwID != 0)
                DeleteLogoutPlayer(pLoginData->GetAccountRef().players[n].dwID);
    }

    //----------------------------------------------------------------


    // ---------------------------------------------------------------

    //----------------------------------

    //----------------------------------
    if ((c = GetPlayerCache(packet->player_id)))
    {
        CLoginData * pkLD = GetLoginDataByAID(packet->account_id);

        if (!pkLD || pkLD->IsPlay())
        {
            sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0);
            peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, dwHandle, 0);
            return;
        }

        pTab = c->Get();

        pkLD->SetPlay(true);
        SendLoginToBilling(pkLD, true);
        thecore_memcpy(pTab->aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(pTab->aiPremiumTimes));

        peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, dwHandle, sizeof(TPlayerTable));
        peer->Encode(pTab, sizeof(TPlayerTable));

        if (packet->player_id != pkLD->GetLastPlayerID())
        {
            TPacketNeedLoginLogInfo logInfo;
            logInfo.dwPlayerID = packet->player_id;

            pkLD->SetLastPlayerID( packet->player_id );

            peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, dwHandle, sizeof(TPacketNeedLoginLogInfo) );
            peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) );
        }

        char szQuery[1024] = { 0, };

        TItemCacheSet * pSet = GetItemCacheSet(pTab->id);

        sys_log(0, "[PLAYER_LOAD] ID %s pid %d gold %d ", pTab->name, pTab->id, pTab->gold);

        //--------------------------------------------

        //--------------------------------------------

        /////////////////////////////////////////////

        /////////////////////////////////////////////
        if (pSet)
        {
            static std::vector<TPlayerItem> s_items;
            s_items.resize(pSet->size());

            DWORD dwCount = 0;
            TItemCacheSet::iterator it = pSet->begin();

            while (it != pSet->end())
            {
                CItemCache * c = *it++;
                TPlayerItem * p = c->Get();

                if (p->vnum)
                    thecore_memcpy(&s_items[dwCount++], p, sizeof(TPlayerItem));
            }

            if (g_test_server)
                sys_log(0, "ITEM_CACHE: HIT! %s count: %u", pTab->name, dwCount);

            peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount);
            peer->EncodeDWORD(dwCount);

            if (dwCount)
                peer->Encode(&s_items[0], sizeof(TPlayerItem) * dwCount);

            // Quest
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID,szName,szState,lValue FROM quest%s WHERE dwPID=%d AND lValue<>0",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery, QID_QUEST, peer->GetHandle(), new ClientHandleInfo(dwHandle,0,packet->account_id));

            // Affect
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID,bType,bApplyOn,lApplyValue,dwFlag,lDuration,lSPCost FROM affect%s WHERE dwPID=%d",
                    GetTablePostfix(), pTab->id);
            // @fixme402 ClientHandleInfo+pTab->id
            CDBManager::instance().ReturnQuery(szQuery, QID_AFFECT, peer->GetHandle(), new ClientHandleInfo(dwHandle, pTab->id));
        }
        /////////////////////////////////////////////

        /////////////////////////////////////////////
        else
        {
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT id,`window`+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6 "
#ifdef ENABLE_SOULBIND_SYSTEM
                    ",sealbind "
#endif
                    "FROM item%s WHERE owner_id=%d AND (`window` in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY'"
#ifdef ENABLE_SWITCHBOT_WORLDARD
                    ",'SWITCHBOT'"
#endif
#ifdef FAST_EQUIP_WORLDARD
                    ",'CHANGE_EQUIP'"
#endif
                    "))",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery,
                    QID_ITEM,
                    peer->GetHandle(),
                    new ClientHandleInfo(dwHandle, pTab->id));
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID, szName, szState, lValue FROM quest%s WHERE dwPID=%d",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery,
                    QID_QUEST,
                    peer->GetHandle(),
                    new ClientHandleInfo(dwHandle, pTab->id));
            snprintf(szQuery, sizeof(szQuery),
                    "SELECT dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost FROM affect%s WHERE dwPID=%d",
                    GetTablePostfix(), pTab->id);

            CDBManager::instance().ReturnQuery(szQuery,
                    QID_AFFECT,
                    peer->GetHandle(),
                    new ClientHandleInfo(dwHandle, pTab->id));
        }
        //ljw
        //return;
    }
    //----------------------------------

    //----------------------------------
    else
    {
        sys_log(0, "[PLAYER_LOAD] Load from PlayerDB pid[%d]", packet->player_id);

        char queryStr[QUERY_MAX_LEN];

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT "
                "id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,playtime,"
                "gold,level,level_step,st,ht,dx,iq,exp,"
                "stat_point,skill_point,sub_skill_point,stat_reset_count,part_base,part_hair,"
#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
                "pick_up_mode,"
                "rarity_mode,"
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
                                                "shop_flag,"
#endif
                #ifdef ENABLE_ACCE_COSTUME_SYSTEM
                "part_acce, "
                #endif
                "skill_level,quickslot,skill_group,alignment,mobile,horse_level,horse_riding,horse_hp,horse_hp_droptime,horse_stamina,"
                "UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(last_play),horse_skill_point FROM player%s WHERE id=%d",
                GetTablePostfix(), packet->player_id);

        ClientHandleInfo * pkInfo = new ClientHandleInfo(dwHandle, packet->player_id);
        pkInfo->account_id = packet->account_id;
        CDBManager::instance().ReturnQuery(queryStr, QID_PLAYER, peer->GetHandle(), pkInfo);

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT id,`window`+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6 "
#ifdef ENABLE_SOULBIND_SYSTEM
                ",sealbind "
#endif
                "FROM item%s WHERE owner_id=%d AND (`window` in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY'"
#ifdef ENABLE_SWITCHBOT_WORLDARD
                ",'SWITCHBOT'"
#endif
#ifdef FAST_EQUIP_WORLDARD
                ",'CHANGE_EQUIP'"
#endif
                "))",
                GetTablePostfix(), packet->player_id);
        CDBManager::instance().ReturnQuery(queryStr, QID_ITEM, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT dwPID,szName,szState,lValue FROM quest%s WHERE dwPID=%d",
                GetTablePostfix(), packet->player_id);
        CDBManager::instance().ReturnQuery(queryStr, QID_QUEST, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id,packet->account_id));

        //--------------------------------------------------------------

        //--------------------------------------------------------------
        snprintf(queryStr, sizeof(queryStr),
                "SELECT dwPID,bType,bApplyOn,lApplyValue,dwFlag,lDuration,lSPCost FROM affect%s WHERE dwPID=%d",
                GetTablePostfix(), packet->player_id);
        CDBManager::instance().ReturnQuery(queryStr, QID_AFFECT, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));
    }
}


void CClientManager::ItemAward(CPeer * peer,char* login)
{
    char login_t[LOGIN_MAX_LEN + 1] = "";
    strlcpy(login_t,login,LOGIN_MAX_LEN + 1);
    std::set<TItemAward *> * pSet = ItemAwardManager::instance().GetByLogin(login_t);
    if(pSet == NULL)
        return;
    typeof(pSet->begin()) it = pSet->begin();
    while(it != pSet->end() )
    {
        TItemAward * pItemAward = *(it++);
        char* whyStr = pItemAward->szWhy;
        char cmdStr[100] = "";
        strcpy(cmdStr,whyStr);
        char command[20] = "";
        // @fixme203 directly GetCommand instead of strcpy
        GetCommand(cmdStr, command);
        if( !(strcmp(command,"GIFT") ))
        {
            TPacketItemAwardInfromer giftData;
            strcpy(giftData.login, pItemAward->szLogin);
            strcpy(giftData.command, command);
            giftData.vnum = pItemAward->dwVnum;
            ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer));
        }
    }
}
char* CClientManager::GetCommand(char* str, char* command) // @fixme203
{
    char* tok;

    if( str[0] == '[' )
    {
        tok = strtok(str,"]");
        strcat(command,&tok[1]);
    }

    return command;
}

bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
{
    if (mysql_num_rows(res) == 0)
        return false;

    memset(pkTab, 0, sizeof(TPlayerTable));

    MYSQL_ROW row = mysql_fetch_row(res);

    int    col = 0;

    // "id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,playtime,"
    // "gold,level,level_step,st,ht,dx,iq,exp,"
    // "stat_point,skill_point,sub_skill_point,stat_reset_count,part_base,part_hair,"
    // "skill_level,quickslot,skill_group,alignment,mobile,horse_level,horse_riding,horse_hp,horse_stamina FROM player%s WHERE id=%d",
    str_to_number(pkTab->id, row[col++]);
    strlcpy(pkTab->name, row[col++], sizeof(pkTab->name));
    str_to_number(pkTab->job, row[col++]);
    str_to_number(pkTab->voice, row[col++]);
    str_to_number(pkTab->dir, row[col++]);
    str_to_number(pkTab->x, row[col++]);
    str_to_number(pkTab->y, row[col++]);
    str_to_number(pkTab->z, row[col++]);
    str_to_number(pkTab->lMapIndex, row[col++]);
    str_to_number(pkTab->lExitX, row[col++]);
    str_to_number(pkTab->lExitY, row[col++]);
    str_to_number(pkTab->lExitMapIndex,  row[col++]);
    str_to_number(pkTab->hp, row[col++]);
    str_to_number(pkTab->sp, row[col++]);
    str_to_number(pkTab->stamina, row[col++]);
    str_to_number(pkTab->sRandomHP, row[col++]);
    str_to_number(pkTab->sRandomSP, row[col++]);
    str_to_number(pkTab->playtime, row[col++]);
    str_to_number(pkTab->gold, row[col++]);
    str_to_number(pkTab->level, row[col++]);
    str_to_number(pkTab->level_step, row[col++]);
    str_to_number(pkTab->st, row[col++]);
    str_to_number(pkTab->ht, row[col++]);
    str_to_number(pkTab->dx, row[col++]);
    str_to_number(pkTab->iq, row[col++]);
    str_to_number(pkTab->exp, row[col++]);
    str_to_number(pkTab->stat_point, row[col++]);
    str_to_number(pkTab->skill_point, row[col++]);
    str_to_number(pkTab->sub_skill_point, row[col++]);
    str_to_number(pkTab->stat_reset_count, row[col++]);
    str_to_number(pkTab->part_base, row[col++]);
    str_to_number(pkTab->parts[PART_HAIR], row[col++]);

#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
    str_to_number(pkTab->dwPickUPMode, row[col++]);
    str_to_number(pkTab->dwRarityMode, row[col++]);
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
    str_to_number(pkTab->shopFlag, row[col++]);
#endif
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
    str_to_number(pkTab->parts[PART_ACCE], row[col++]);
#endif

    if (row[col])
        thecore_memcpy(pkTab->skills, row[col], sizeof(pkTab->skills));
    else
        memset(&pkTab->skills, 0, sizeof(pkTab->skills));

    col++;

    if (row[col])
        thecore_memcpy(pkTab->quickslot, row[col], sizeof(pkTab->quickslot));
    else
        memset(pkTab->quickslot, 0, sizeof(pkTab->quickslot));

    col++;

    str_to_number(pkTab->skill_group, row[col++]);
    str_to_number(pkTab->lAlignment, row[col++]);

    if (row[col])
    {
        strlcpy(pkTab->szMobile, row[col], sizeof(pkTab->szMobile));
    }

    col++;

    str_to_number(pkTab->horse.bLevel, row[col++]);
    str_to_number(pkTab->horse.bRiding, row[col++]);
    str_to_number(pkTab->horse.sHealth, row[col++]);
    str_to_number(pkTab->horse.dwHorseHealthDropTime, row[col++]);
    str_to_number(pkTab->horse.sStamina, row[col++]);
    str_to_number(pkTab->logoff_interval, row[col++]);
    str_to_number(pkTab->horse_skill_point, row[col++]);

    // reset sub_skill_point
    {
        pkTab->skills[123].bLevel = 0; // SKILL_CREATE

        if (pkTab->level > 9)
        {
            int max_point = pkTab->level - 9;

            int skill_point =
                MIN(20, pkTab->skills[121].bLevel) +
                MIN(20, pkTab->skills[124].bLevel) +
                MIN(10, pkTab->skills[131].bLevel) +
                MIN(20, pkTab->skills[141].bLevel) +
                MIN(20, pkTab->skills[142].bLevel);

            pkTab->sub_skill_point = max_point - skill_point;
        }
        else
            pkTab->sub_skill_point = 0;
    }

    return true;
}

void CClientManager::RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD dwQID)
{
    CQueryInfo * qi = (CQueryInfo *) pMsg->pvUserData;
    std::unique_ptr<ClientHandleInfo> info((ClientHandleInfo *) qi->pvData);

    MYSQL_RES * pSQLResult = pMsg->Get()->pSQLResult;
    if (!pSQLResult)
    {
        sys_err("null MYSQL_RES QID %u", dwQID);
        return;
    }

    switch (dwQID)
    {
        case QID_PLAYER:
            sys_log(0, "QID_PLAYER %u %u", info->dwHandle, info->player_id);
            RESULT_PLAYER_LOAD(peer, pSQLResult, info.get());

            break;

        case QID_ITEM:
            sys_log(0, "QID_ITEM %u", info->dwHandle);
            RESULT_ITEM_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
            break;

        case QID_QUEST:
            {
                sys_log(0, "QID_QUEST %u", info->dwHandle);
                RESULT_QUEST_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);

                ClientHandleInfo*  temp1 = info.get();
                if (temp1 == NULL)
                    break;

                CLoginData* pLoginData1 = GetLoginDataByAID(temp1->account_id);    //

                if( pLoginData1->GetAccountRef().login == NULL)
                    break;
                if( pLoginData1 == NULL )
                    break;
                sys_log(0,"info of pLoginData1 before call ItemAwardfunction %d",pLoginData1);
                ItemAward(peer,pLoginData1->GetAccountRef().login);
            }
            break;

        case QID_AFFECT:
            sys_log(0, "QID_AFFECT %u", info->dwHandle);
            // @fixme402 RESULT_AFFECT_LOAD+info->player_id
            RESULT_AFFECT_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
            break;
            /*
               case QID_PLAYER_ITEM_QUEST_AFFECT:
               sys_log(0, "QID_PLAYER_ITEM_QUEST_AFFECT %u", info->dwHandle);
               RESULT_PLAYER_LOAD(peer, pSQLResult, info->dwHandle);

               if (!pMsg->Next())
               {
               sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: ITEM FAILED");
               return;
               }

               case QID_ITEM_QUEST_AFFECT:
               sys_log(0, "QID_ITEM_QUEST_AFFECT %u", info->dwHandle);
               RESULT_ITEM_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);

               if (!pMsg->Next())
               {
               sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: QUEST FAILED");
               return;
               }

               case QID_QUEST_AFFECT:
               sys_log(0, "QID_QUEST_AFFECT %u", info->dwHandle);
               RESULT_QUEST_LOAD(peer, pSQLResult, info->dwHandle);

               if (!pMsg->Next())
               sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: AFFECT FAILED");
               else
               RESULT_AFFECT_LOAD(peer, pSQLResult, info->dwHandle);

               break;
               */
    }

}

void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHandleInfo * pkInfo)
{
    TPlayerTable tab;

    if (!CreatePlayerTableFromRes(pRes, &tab))
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0);
        return;
    }

    CLoginData * pkLD = GetLoginDataByAID(pkInfo->account_id);

    if (!pkLD || pkLD->IsPlay())
    {
        sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0);
        peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0);
        return;
    }

    pkLD->SetPlay(true);
    SendLoginToBilling(pkLD, true);
    thecore_memcpy(tab.aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(tab.aiPremiumTimes));

    peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, pkInfo->dwHandle, sizeof(TPlayerTable));
    peer->Encode(&tab, sizeof(TPlayerTable));

    if (tab.id != pkLD->GetLastPlayerID())
    {
        TPacketNeedLoginLogInfo logInfo;
        logInfo.dwPlayerID = tab.id;

        pkLD->SetLastPlayerID( tab.id );

        peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, pkInfo->dwHandle, sizeof(TPacketNeedLoginLogInfo) );
        peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) );
    }
}

void CClientManager::RESULT_ITEM_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwPID)
{
    static std::vector<TPlayerItem> s_items;

    CreateItemTableFromRes(pRes, &s_items, dwPID);
    DWORD dwCount = s_items.size();

    peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount);
    peer->EncodeDWORD(dwCount);


    CreateItemCacheSet(dwPID);

    // ITEM_LOAD_LOG_ATTACH_PID
    sys_log(0, "ITEM_LOAD: count %u pid %u", dwCount, dwPID);
    // END_OF_ITEM_LOAD_LOG_ATTACH_PID

    if (dwCount)
    {
        peer->Encode(&s_items[0], sizeof(TPlayerItem) * dwCount);

        for (DWORD i = 0; i < dwCount; ++i)
            PutItemCache(&s_items[i], true);
    }
}

// @fixme402 (RESULT_AFFECT_LOAD +dwRealPID)
void CClientManager::RESULT_AFFECT_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwRealPID)
{
    int iNumRows;

    if ((iNumRows = mysql_num_rows(pRes)) == 0)
    {
        // @fixme402 begin
        static DWORD dwPID;
        static DWORD dwCount = 0; //1;
        static TPacketAffectElement paeTable = {0};

        dwPID = dwRealPID;
        sys_log(0, "AFFECT_LOAD: count %u PID %u RealPID %u", dwCount, dwPID, dwRealPID);

        peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount);
        peer->Encode(&dwPID, sizeof(DWORD));
        peer->Encode(&dwCount, sizeof(DWORD));
        peer->Encode(&paeTable, sizeof(TPacketAffectElement) * dwCount);
        // @fixme402 end
        return;
    }

    static std::vector<TPacketAffectElement> s_elements;
    s_elements.resize(iNumRows);

    DWORD dwPID = 0;

    MYSQL_ROW row;

    for (int i = 0; i < iNumRows; ++i)
    {
        TPacketAffectElement & r = s_elements[i];
        row = mysql_fetch_row(pRes);

        if (dwPID == 0)
            str_to_number(dwPID, row[0]);

        str_to_number(r.dwType, row[1]);
        str_to_number(r.bApplyOn, row[2]);
        str_to_number(r.lApplyValue, row[3]);
        str_to_number(r.dwFlag, row[4]);
        str_to_number(r.lDuration, row[5]);
        str_to_number(r.lSPCost, row[6]);
    }

    sys_log(0, "AFFECT_LOAD: count %d PID %u", s_elements.size(), dwPID);

    DWORD dwCount = s_elements.size();

    peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount);
    peer->Encode(&dwPID, sizeof(DWORD));
    peer->Encode(&dwCount, sizeof(DWORD));
    peer->Encode(&s_elements[0], sizeof(TPacketAffectElement) * dwCount);
}

void CClientManager::RESULT_QUEST_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD pid)
{
    int iNumRows;

    if ((iNumRows = mysql_num_rows(pRes)) == 0)
    {
        DWORD dwCount = 0;
        peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD));
        peer->Encode(&dwCount, sizeof(DWORD));
        return;
    }

    static std::vector<TQuestTable> s_table;
    s_table.resize(iNumRows);

    MYSQL_ROW row;

    for (int i = 0; i < iNumRows; ++i)
    {
        TQuestTable & r = s_table[i];

        row = mysql_fetch_row(pRes);

        str_to_number(r.dwPID, row[0]);
        strlcpy(r.szName, row[1], sizeof(r.szName));
        strlcpy(r.szState, row[2], sizeof(r.szState));
        str_to_number(r.lValue, row[3]);
    }

    sys_log(0, "QUEST_LOAD: count %d PID %u", s_table.size(), s_table[0].dwPID);

    DWORD dwCount = s_table.size();

    peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD) + sizeof(TQuestTable) * dwCount);
    peer->Encode(&dwCount, sizeof(DWORD));
    peer->Encode(&s_table[0], sizeof(TQuestTable) * dwCount);
}

/*
 * PLAYER SAVE
 */
void CClientManager::QUERY_PLAYER_SAVE(CPeer * peer, DWORD dwHandle, TPlayerTable * pkTab)
{
    if (g_test_server)
        sys_log(0, "PLAYER_SAVE: %s", pkTab->name);

    PutPlayerCache(pkTab);
}

typedef std::map<DWORD, time_t> time_by_id_map_t;
static time_by_id_map_t s_createTimeByAccountID;

/*
 * PLAYER CREATE
 */
void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerCreatePacket* packet)
{
    char    queryStr[QUERY_MAX_LEN];
    int        queryLen;
    int        player_id;


    time_by_id_map_t::iterator it = s_createTimeByAccountID.find(packet->account_id);

    if (it != s_createTimeByAccountID.end())
    {
        time_t curtime = time(0);

        if (curtime - it->second < 30)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
            return;
        }
    }

    queryLen = snprintf(queryStr, sizeof(queryStr),
            "SELECT pid%u FROM player_index%s WHERE id=%d", packet->account_index + 1, GetTablePostfix(), packet->account_id);

    auto pMsg0(CDBManager::instance().DirectQuery(queryStr));
    if (pMsg0->Get()->uiNumRows != 0)
    {
        if (!pMsg0->Get()->pSQLResult)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
            return;
        }

        MYSQL_ROW row = mysql_fetch_row(pMsg0->Get()->pSQLResult);

        DWORD dwPID = 0; str_to_number(dwPID, row[0]);
        if (row[0] && dwPID > 0)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
            sys_log(0, "ALREADY EXIST AccountChrIdx %d ID %d", packet->account_index, dwPID);
            return;
        }
    }
    else
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
        return;
    }

    if (g_stLocale == "sjis")
        snprintf(queryStr, sizeof(queryStr),
            "SELECT COUNT(*) as count FROM player%s WHERE name='%s' collate sjis_japanese_ci",
            GetTablePostfix(), packet->player_table.name);
    else
    snprintf(queryStr, sizeof(queryStr),
            "SELECT COUNT(*) as count FROM player%s WHERE name='%s'", GetTablePostfix(), packet->player_table.name);

    auto pMsg1(CDBManager::instance().DirectQuery(queryStr));
    if (pMsg1->Get()->uiNumRows)
    {
        if (!pMsg1->Get()->pSQLResult)
        {
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
            return;
        }

        MYSQL_ROW row = mysql_fetch_row(pMsg1->Get()->pSQLResult);

        if (*row[0] != '0')
        {
            sys_log(0, "ALREADY EXIST name %s, row[0] %s query %s", packet->player_table.name, row[0], queryStr);
            peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
            return;
        }
    }
    else
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
        return;
    }

    queryLen = snprintf(queryStr, sizeof(queryStr),
            "INSERT INTO player%s "
            "(id, account_id, name, level, st, ht, dx, iq, "
            "job, voice, dir, x, y, z, "
            "hp, mp, random_hp, random_sp, stat_point, stamina, part_base, part_main, part_hair,"
#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
            "pick_up_mode, "
            "rarity_mode, "
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
            "shop_flag, "
#endif
            #ifdef ENABLE_ACCE_COSTUME_SYSTEM
            "part_acce, "
            #endif
            " gold, playtime, "
            "skill_level, quickslot) "
            "VALUES(0, %u, '%s', %d, %d, %d, %d, %d, "
            "%d, %d, %d, %d, %d, %d, %d, "
            "%d, %d, %d, %d, %d, %d, %d, 0, "

#ifdef ENABLE_AUTOMATIC_PICK_UP_SYSTEM
            "%d, "
            "%d, "
#endif
#ifdef ENABLE_OFFLINESHOP_SYSTEM
            "%llu, "
#endif
            #ifdef ENABLE_ACCE_COSTUME_SYSTEM
            "0, "
            #endif
            "%d, 0, ",
            GetTablePostfix(),
            packet->account_id, packet->player_table.name, packet->player_table.level, packet->player_table.st, packet->player_table.ht, packet->player_table.dx, packet->player_table.iq,
            packet->player_table.job, packet->player_table.voice, packet->player_table.dir, packet->player_table.x, packet->player_table.y, packet->player_table.z,
            packet->player_table.hp, packet->player_table.sp, packet->player_table.sRandomHP, packet->player_table.sRandomSP, packet->player_table.stat_point, packet->player_table.stamina, packet->player_table.part_base, packet->player_table.part_base, packet->player_table.gold);

    sys_log(0, "PlayerCreate accountid %d name %s level %d gold %d, st %d ht %d job %d",
            packet->account_id,
            packet->player_table.name,
            packet->player_table.level,
            packet->player_table.gold,
            packet->player_table.st,
            packet->player_table.ht,
            packet->player_table.job);

    static char text[4096 + 1];

    CDBManager::instance().EscapeString(text, packet->player_table.skills, sizeof(packet->player_table.skills));
    queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s', ", text);
    if (g_test_server)
        sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);

    CDBManager::instance().EscapeString(text, packet->player_table.quickslot, sizeof(packet->player_table.quickslot));
    queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s')", text);

    auto pMsg2(CDBManager::instance().DirectQuery(queryStr));
    if (g_test_server)
        sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);

    if (pMsg2->Get()->uiAffectedRows <= 0)
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
        sys_log(0, "ALREADY EXIST3 query: %s AffectedRows %lu", queryStr, pMsg2->Get()->uiAffectedRows);
        return;
    }

    player_id = pMsg2->Get()->uiInsertID;

    snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%d=%d WHERE id=%d",
            GetTablePostfix(), packet->account_index + 1, player_id, packet->account_id);

    auto pMsg3(CDBManager::instance().DirectQuery(queryStr));
    if (pMsg3->Get()->uiAffectedRows <= 0)
    {
        sys_err("QUERY_ERROR: %s", queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), player_id);
        CDBManager::instance().DirectQuery(queryStr);

        peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
        return;
    }

    TPacketDGCreateSuccess pack;
    memset(&pack, 0, sizeof(pack));

    pack.bAccountCharacterIndex = packet->account_index;

    pack.player.dwID            = player_id;
    strlcpy(pack.player.szName, packet->player_table.name, sizeof(pack.player.szName));
    pack.player.byJob            = packet->player_table.job;
    pack.player.byLevel            = 1;
    pack.player.dwPlayMinutes    = 0;
    pack.player.byST            = packet->player_table.st;
    pack.player.byHT            = packet->player_table.ht;
    pack.player.byDX             = packet->player_table.dx;
    pack.player.byIQ            = packet->player_table.iq;
    pack.player.wMainPart        = packet->player_table.part_base;
    pack.player.x            = packet->player_table.x;
    pack.player.y            = packet->player_table.y;

    peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_SUCCESS, dwHandle, sizeof(TPacketDGCreateSuccess));
    peer->Encode(&pack, sizeof(TPacketDGCreateSuccess));

    sys_log(0, "7 name %s job %d", pack.player.szName, pack.player.byJob);

    s_createTimeByAccountID[packet->account_id] = time(0);
}

/*
 * PLAYER DELETE
 */
void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerDeletePacket* packet)
{
    if (!packet->login[0] || !packet->player_id || packet->account_index >= PLAYER_PER_ACCOUNT)
        return;

    CLoginData * ld = GetLoginDataByLogin(packet->login);

    if (!ld)
    {
        peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
        peer->EncodeBYTE(packet->account_index);
        return;
    }

    TAccountTable & r = ld->GetAccountRef();

    // block for japan
    if (g_stLocale != "sjis")
    {
        if (!IsChinaEventServer())
        {
            if (strlen(r.social_id) < 7 || strncmp(packet->private_code, r.social_id + strlen(r.social_id) - 7, 7))
            {
                sys_log(0, "PLAYER_DELETE FAILED len(%d)", strlen(r.social_id));
                peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
                peer->EncodeBYTE(packet->account_index);
                return;
            }

            CPlayerTableCache * pkPlayerCache = GetPlayerCache(packet->player_id);
            if (pkPlayerCache)
            {
                TPlayerTable * pTab = pkPlayerCache->Get();

                if (pTab->level >= m_iPlayerDeleteLevelLimit)
                {
                    sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimit);
                    peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
                    peer->EncodeBYTE(packet->account_index);
                    return;
                }

                if (pTab->level < m_iPlayerDeleteLevelLimitLower)
                {
                    sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimitLower);
                    peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
                    peer->EncodeBYTE(packet->account_index);
                    return;
                }
            }
        }
    }

    char szQuery[128];
    snprintf(szQuery, sizeof(szQuery), "SELECT p.id, p.level, p.name FROM player_index%s AS i, player%s AS p WHERE pid%u=%u AND pid%u=p.id",
            GetTablePostfix(), GetTablePostfix(), packet->account_index + 1, packet->player_id, packet->account_index + 1);

    ClientHandleInfo * pi = new ClientHandleInfo(dwHandle, packet->player_id);
    pi->account_index = packet->account_index;

    sys_log(0, "PLAYER_DELETE TRY: %s %d pid%d", packet->login, packet->player_id, packet->account_index + 1);
    CDBManager::instance().ReturnQuery(szQuery, QID_PLAYER_DELETE, peer->GetHandle(), pi);
}

//

//
void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
{
    CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
    ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;

    if (msg->Get() && msg->Get()->uiNumRows)
    {
        MYSQL_ROW row = mysql_fetch_row(msg->Get()->pSQLResult);

        DWORD dwPID = 0;
        str_to_number(dwPID, row[0]);

        int deletedLevelLimit = 0;
        str_to_number(deletedLevelLimit, row[1]);

        char szName[64];
        strlcpy(szName, row[2], sizeof(szName));

        if (deletedLevelLimit >= m_iPlayerDeleteLevelLimit && !IsChinaEventServer())
        {
            sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimit);
            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }

        if (deletedLevelLimit < m_iPlayerDeleteLevelLimitLower)
        {
            sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimitLower);
            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }

        char queryStr[QUERY_MAX_LEN];

        snprintf(queryStr, sizeof(queryStr), "INSERT INTO player%s_deleted SELECT * FROM player%s WHERE id=%d",
                GetTablePostfix(), GetTablePostfix(), pi->player_id);
        auto pIns(CDBManager::instance().DirectQuery(queryStr));

        if (pIns->Get()->uiAffectedRows == 0 || pIns->Get()->uiAffectedRows == (uint32_t)-1)
        {
            sys_log(0, "PLAYER_DELETE FAILED %u CANNOT INSERT TO player%s_deleted", dwPID, GetTablePostfix());

            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }


        sys_log(0, "PLAYER_DELETE SUCCESS %u", dwPID);

        char account_index_string[16];

        snprintf(account_index_string, sizeof(account_index_string), "player_id%d", m_iPlayerIDStart + pi->account_index);


        CPlayerTableCache * pkPlayerCache = GetPlayerCache(pi->player_id);

        if (pkPlayerCache)
        {
            m_map_playerCache.erase(pi->player_id);
            delete pkPlayerCache;
        }


        TItemCacheSet * pSet = GetItemCacheSet(pi->player_id);

        if (pSet)
        {
            TItemCacheSet::iterator it = pSet->begin();

            while (it != pSet->end())
            {
                CItemCache * pkItemCache = *it++;
                DeleteItemCache(pkItemCache->Get()->id);
            }

            pSet->clear();
            delete pSet;

            m_map_pkItemCacheSetPtr.erase(pi->player_id);
        }

        snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%u=0 WHERE pid%u=%d",
                GetTablePostfix(),
                pi->account_index + 1,
                pi->account_index + 1,
                pi->player_id);

        auto pMsg(CDBManager::instance().DirectQuery(queryStr));
        if (pMsg->Get()->uiAffectedRows == 0 || pMsg->Get()->uiAffectedRows == (uint32_t)-1)
        {
            sys_log(0, "PLAYER_DELETE FAIL WHEN UPDATE account table");
            peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
            peer->EncodeBYTE(pi->account_index);
            return;
        }

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().DirectQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM item%s WHERE owner_id=%d AND (`window` in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY'"
#ifdef ENABLE_SWITCHBOT_WORLDARD
        ",'SWITCHBOT'"
#endif
#ifdef FAST_EQUIP_WORLDARD
        ",'CHANGE_EQUIP'"
#endif
        "))", GetTablePostfix(), pi->player_id);
        CDBManager::instance().DirectQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM quest%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM affect%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM guild_member%s WHERE pid=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);

        // MYSHOP_PRICE_LIST
        snprintf(queryStr, sizeof(queryStr), "DELETE FROM myshop_pricelist%s WHERE owner_id=%d", GetTablePostfix(), pi->player_id);
        CDBManager::instance().AsyncQuery(queryStr);
        // END_OF_MYSHOP_PRICE_LIST

        snprintf(queryStr, sizeof(queryStr), "DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'", GetTablePostfix(), szName, szName);
        CDBManager::instance().AsyncQuery(queryStr);

        peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_SUCCESS, pi->dwHandle, 1);
        peer->EncodeBYTE(pi->account_index);
    }
    else
    {

        sys_log(0, "PLAYER_DELETE FAIL NO ROW");
        peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
        peer->EncodeBYTE(pi->account_index);
    }
}

void CClientManager::QUERY_ADD_AFFECT(CPeer * peer, TPacketGDAddAffect * p)
{
    char queryStr[QUERY_MAX_LEN];
    /*
       snprintf(queryStr, sizeof(queryStr),
       "INSERT INTO affect%s (dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost) "
       "VALUES(%u, %u, %u, %d, %u, %d, %d) "
       "ON DUPLICATE KEY UPDATE lApplyValue=%d, dwFlag=%u, lDuration=%d, lSPCost=%d",
       GetTablePostfix(),
       p->dwPID,
       p->elem.dwType,
       p->elem.bApplyOn,
       p->elem.lApplyValue,
       p->elem.dwFlag,
       p->elem.lDuration,
       p->elem.lSPCost,
       p->elem.lApplyValue,
       p->elem.dwFlag,
       p->elem.lDuration,
       p->elem.lSPCost);
       */
    snprintf(queryStr, sizeof(queryStr),
            "REPLACE INTO affect%s (dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost) "
            "VALUES(%u, %u, %u, %ld, %u, %ld, %ld)",
            GetTablePostfix(),
            p->dwPID,
            p->elem.dwType,
            p->elem.bApplyOn,
            p->elem.lApplyValue,
            p->elem.dwFlag,
            p->elem.lDuration,
            p->elem.lSPCost);

    CDBManager::instance().AsyncQuery(queryStr);
}

void CClientManager::QUERY_REMOVE_AFFECT(CPeer * peer, TPacketGDRemoveAffect * p)
{
    char queryStr[QUERY_MAX_LEN];

    snprintf(queryStr, sizeof(queryStr),
            "DELETE FROM affect%s WHERE dwPID=%u AND bType=%u AND bApplyOn=%u",
            GetTablePostfix(), p->dwPID, p->dwType, p->bApplyOn);

    CDBManager::instance().AsyncQuery(queryStr);
}


void CClientManager::QUERY_HIGHSCORE_REGISTER(CPeer* peer, TPacketGDHighscore * data)
{
    char szQuery[128];
    snprintf(szQuery, sizeof(szQuery), "SELECT value FROM highscore%s WHERE board='%s' AND pid = %u", GetTablePostfix(), data->szBoard, data->dwPID);

    sys_log(0, "HEADER_GD_HIGHSCORE_REGISTER: PID %u", data->dwPID);

    ClientHandleInfo * pi = new ClientHandleInfo(0);
    strlcpy(pi->login, data->szBoard, sizeof(pi->login));
    pi->account_id = (DWORD)data->lValue;
    pi->player_id = data->dwPID;
    pi->account_index = (data->cDir > 0);

    CDBManager::instance().ReturnQuery(szQuery, QID_HIGHSCORE_REGISTER, peer->GetHandle(), pi);
}

void CClientManager::RESULT_HIGHSCORE_REGISTER(CPeer * pkPeer, SQLMsg * msg)
{
    CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
    ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;
    //DWORD dwHandle = pi->dwHandle;

    char szBoard[21];
    strlcpy(szBoard, pi->login, sizeof(szBoard));
    int value = (int)pi->account_id;

    SQLResult * res = msg->Get();

    if (res->uiNumRows == 0)
    {

        char buf[256];
        snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
        CDBManager::instance().AsyncQuery(buf);
    }
    else
    {
        if (!res->pSQLResult)
        {
            delete pi;
            return;
        }

        MYSQL_ROW row = mysql_fetch_row(res->pSQLResult);
        if (row && row[0])
        {
            int current_value = 0; str_to_number(current_value, row[0]);
            if (((pi->account_index)&&(current_value >= value)) || ((!pi->account_index)&&(current_value <= value)))
            {
                value = current_value;
            }
            else
            {
                char buf[256];
                snprintf(buf, sizeof(buf), "REPLACE INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
                CDBManager::instance().AsyncQuery(buf);
            }
        }
        else
        {
            char buf[256];
            snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
            CDBManager::instance().AsyncQuery(buf);
        }
    }

    delete pi;
}

void CClientManager::InsertLogoutPlayer(DWORD pid)
{
    TLogoutPlayerMap::iterator it = m_map_logout.find(pid);


    if (it != m_map_logout.end())
    {

        if (g_log)
            sys_log(0, "LOGOUT: Update player time pid(%d)", pid);

        it->second->time = time(0);
        return;
    }

    TLogoutPlayer * pLogout = new TLogoutPlayer;
    pLogout->pid = pid;
    pLogout->time = time(0);
    m_map_logout.emplace(pid, pLogout);

    if (g_log)
        sys_log(0, "LOGOUT: Insert player pid(%d)", pid);
}

void CClientManager::DeleteLogoutPlayer(DWORD pid)
{
    TLogoutPlayerMap::iterator it = m_map_logout.find(pid);

    if (it != m_map_logout.end())
    {
        delete it->second;
        m_map_logout.erase(it);
    }
}

extern int g_iLogoutSeconds;

void CClientManager::UpdateLogoutPlayer()
{
    time_t now = time(0);

    TLogoutPlayerMap::iterator it = m_map_logout.begin();

    while (it != m_map_logout.end())
    {
        TLogoutPlayer* pLogout = it->second;

        if (now - g_iLogoutSeconds > pLogout->time)
        {
            FlushItemCacheSet(pLogout->pid);
            FlushPlayerCacheSet(pLogout->pid);

            delete pLogout;
            m_map_logout.erase(it++);
        }
        else
            ++it;
    }
}

void CClientManager::FlushPlayerCacheSet(DWORD pid)
{
    TPlayerTableCacheMap::iterator it = m_map_playerCache.find(pid);

    if (it != m_map_playerCache.end())
    {
        CPlayerTableCache * c = it->second;
        m_map_playerCache.erase(it);

        c->Flush();
        delete c;
    }
}

 

 

Edited by shenhui1986
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.