Advertisement
Guest User

Untitled

a guest
Nov 6th, 2020
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 48.02 KB | None | 0 0
  1.  
  2. #include "stdafx.h"
  3.  
  4. #include "ClientManager.h"
  5.  
  6. #include "Main.h"
  7. #include "QID.h"
  8. #include "ItemAwardManager.h"
  9. #include "HB.h"
  10. #include "Cache.h"
  11. #ifdef __SKILL_COLOR_SYSTEM__
  12.     #include "../../common/length.h"
  13. #endif
  14. #include "../../common/service.h"
  15.  
  16. extern bool g_bHotBackup;
  17.  
  18. extern std::string g_stLocale;
  19. extern int g_test_server;
  20. extern int g_log;
  21.  
  22. //
  23. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  24. // !!!!!!!!!!! IMPORTANT !!!!!!!!!!!!
  25. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  26. //
  27. // Check all SELECT syntax on item table before change this function!!!
  28. //
  29. bool CreateItemTableFromRes(MYSQL_RES * res, std::vector<TPlayerItem> * pVec, DWORD dwPID)
  30. {
  31.     if (!res)
  32.     {
  33.         pVec->clear();
  34.         return true;
  35.     }
  36.  
  37.     int rows;
  38.  
  39.     if ((rows = mysql_num_rows(res)) <= 0)  // 데이터 없음
  40.     {
  41.         pVec->clear();
  42.         return true;
  43.     }
  44.  
  45.     pVec->resize(rows);
  46.  
  47.     for (int i = 0; i < rows; ++i)
  48.     {
  49.         MYSQL_ROW row = mysql_fetch_row(res);
  50.         TPlayerItem & item = pVec->at(i);
  51.  
  52.         int cur = 0;
  53.  
  54.         // Check all SELECT syntax on item table before change this function!!!
  55.         // Check all SELECT syntax on item table before change this function!!!
  56.         // Check all SELECT syntax on item table before change this function!!!
  57.         str_to_number(item.id, row[cur++]);
  58.         str_to_number(item.window, row[cur++]);
  59.         str_to_number(item.pos, row[cur++]);
  60.         str_to_number(item.count, row[cur++]);
  61.         str_to_number(item.vnum, row[cur++]);
  62.         str_to_number(item.alSockets[0], row[cur++]);
  63.         str_to_number(item.alSockets[1], row[cur++]);
  64.         str_to_number(item.alSockets[2], row[cur++]);
  65.  
  66.         for (int j = 0; j < ITEM_ATTRIBUTE_MAX_NUM; j++)
  67.         {
  68.             str_to_number(item.aAttr[j].bType, row[cur++]);
  69.             str_to_number(item.aAttr[j].sValue, row[cur++]);
  70.         }
  71.  
  72.         item.owner      = dwPID;
  73.     }
  74.  
  75.     return true;
  76. }
  77.  
  78. #ifdef __SKILL_COLOR_SYSTEM__
  79. bool CreateSkillColorTableFromRes(MYSQL_RES * res, DWORD * dwSkillColor)
  80. {
  81.     if (mysql_num_rows(res) == 0)
  82.         return false;
  83.  
  84.     MYSQL_ROW row = mysql_fetch_row(res);
  85.  
  86.     for (int x = 0; x < ESkillColorLength::MAX_SKILL_COUNT + ESkillColorLength::MAX_BUFF_COUNT; ++x)
  87.     {
  88.         for (int i = 0; i < ESkillColorLength::MAX_EFFECT_COUNT; ++i)
  89.         {
  90.             *(dwSkillColor++) = atoi(row[i + (x*ESkillColorLength::MAX_EFFECT_COUNT)]);
  91.         }
  92.     }
  93.  
  94.     return true;
  95. }
  96. #endif
  97.  
  98. size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * pkTab)
  99. {
  100.     size_t queryLen;
  101.  
  102.     queryLen = snprintf(pszQuery, querySize,
  103.             "UPDATE player%s SET "
  104.             "job = %d, "
  105.             "voice = %d, "
  106.             "dir = %d, "
  107.             "x = %d, "
  108.             "y = %d, "
  109.             "z = %d, "
  110.             "map_index = %d, "
  111.             "exit_x = %ld, "
  112.             "exit_y = %ld, "
  113.             "exit_map_index = %ld, "
  114.             "hp = %d, "
  115.             "mp = %d, "
  116.             "stamina = %d, "
  117.             "random_hp = %d, "
  118.             "random_sp = %d, "
  119.             "playtime = %d, "
  120.             "level = %d, "
  121.             "level_step = %d, "
  122.             "st = %d, "
  123.             "ht = %d, "
  124.             "dx = %d, "
  125.             "iq = %d, "
  126.             "gold = %d, "
  127.             "exp = %u, "
  128.             "stat_point = %d, "
  129.             "skill_point = %d, "
  130.             "sub_skill_point = %d, "
  131.             "stat_reset_count = %d, "
  132.             "ip = '%s', "
  133.             "part_main = %d, "
  134.             "part_hair = %d, "
  135.             "last_play = NOW(), "
  136.             "skill_group = %d, "
  137.             "alignment = %ld, "
  138. #ifdef ENABLE_TITLE_SYSTEM
  139.             "prestige = %ld, "
  140. #endif 
  141.             "horse_level = %d, "
  142.             "horse_riding = %d, "
  143.             "horse_hp = %d, "
  144.             "horse_hp_droptime = %u, "
  145.             "horse_stamina = %d, "
  146.             "horse_skill_point = %d, "
  147. #ifdef ENABLE_FISH_EVENT
  148.             "fish_use_count = %d, "
  149. #endif
  150.             ,
  151.         GetTablePostfix(),
  152.         pkTab->job,
  153.         pkTab->voice,
  154.         pkTab->dir,
  155.         pkTab->x,
  156.         pkTab->y,
  157.         pkTab->z,
  158.         pkTab->lMapIndex,
  159.         pkTab->lExitX,
  160.         pkTab->lExitY,
  161.         pkTab->lExitMapIndex,
  162.         pkTab->hp,
  163.         pkTab->sp,
  164.         pkTab->stamina,
  165.         pkTab->sRandomHP,
  166.         pkTab->sRandomSP,
  167.         pkTab->playtime,
  168.         pkTab->level,
  169.         pkTab->level_step,
  170.         pkTab->st,
  171.         pkTab->ht,
  172.         pkTab->dx,
  173.         pkTab->iq,
  174.         pkTab->gold,
  175.         pkTab->exp,
  176.         pkTab->stat_point,
  177.         pkTab->skill_point,
  178.         pkTab->sub_skill_point,
  179.         pkTab->stat_reset_count,
  180.         pkTab->ip,
  181.         pkTab->parts[PART_MAIN],
  182.         pkTab->parts[PART_HAIR],
  183.         pkTab->skill_group,
  184.         pkTab->lAlignment,
  185. #ifdef ENABLE_TITLE_SYSTEM
  186.         pkTab->lPrestige,
  187. #endif
  188.         pkTab->horse.bLevel,
  189.         pkTab->horse.bRiding,
  190.         pkTab->horse.sHealth,
  191.         pkTab->horse.dwHorseHealthDropTime,
  192.         pkTab->horse.sStamina,
  193.         pkTab->horse_skill_point,
  194. #ifdef ENABLE_FISH_EVENT
  195.         pkTab->fishEventUseCount,
  196. #endif
  197. #ifdef __TITLE_SYSTEM
  198.     for (int i = 0; i< TITLE_COLOR_MAX_NUM; ++i)
  199.         queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "title_color%d = '%u', ", i, pkTab->title.bColours[i]);
  200. #endif
  201.     );
  202.     // Binary 로 바꾸기 위한 임시 공간
  203.     static char text[8192 + 1];
  204.  
  205.     CDBManager::instance().EscapeString(text, pkTab->skills, sizeof(pkTab->skills));
  206.     queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "skill_level = '%s', ", text);
  207.     CDBManager::instance().EscapeString(text, pkTab->quickslot, sizeof(pkTab->quickslot));
  208.     queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "quickslot = '%s' ", text);
  209.     CDBManager::instance().EscapeString(text, pkTab->title.szName, strlen(pkTab->title.szName));
  210.     queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, "title = '%s' ", text);
  211.     for (int i = 0; i< TITLE_COLOR_MAX_NUM; ++i)
  212.         queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, ",title_color%d = '%u' ", i, pkTab->title.bColours[i]);
  213. #ifdef ENABLE_FISH_EVENT
  214.     CDBManager::instance().EscapeString(text, pkTab->fishSlots, sizeof(pkTab->fishSlots));
  215.     queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, ",fish_slots = '%s' ", text);
  216. #endif
  217.  
  218.     queryLen += snprintf(pszQuery + queryLen, querySize - queryLen, " WHERE id=%d", pkTab->id);
  219.     return queryLen;
  220. }
  221.  
  222. CPlayerTableCache * CClientManager::GetPlayerCache(DWORD id)
  223. {
  224.     TPlayerTableCacheMap::iterator it = m_map_playerCache.find(id);
  225.  
  226.     if (it == m_map_playerCache.end())
  227.         return NULL;
  228.  
  229.     TPlayerTable* pTable = it->second->Get(false);
  230.     pTable->logoff_interval = GetCurrentTime() - it->second->GetLastUpdateTime();
  231.     return it->second;
  232. }
  233.  
  234. void CClientManager::PutPlayerCache(TPlayerTable * pNew)
  235. {
  236.     CPlayerTableCache * c;
  237.  
  238.     c = GetPlayerCache(pNew->id);
  239.  
  240.     if (!c)
  241.     {
  242.         c = new CPlayerTableCache;
  243.         m_map_playerCache.insert(TPlayerTableCacheMap::value_type(pNew->id, c));
  244.     }
  245.  
  246.     if (g_bHotBackup)
  247.         PlayerHB::instance().Put(pNew->id);
  248.  
  249.     c->Put(pNew);
  250. }
  251.  
  252. #ifdef __SKILL_COLOR_SYSTEM__
  253. void CClientManager::QUERY_SKILL_COLOR_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoadPacket * packet)
  254. {
  255.     CSKillColorCache * c;
  256.     TSkillColor * p;
  257.     if (c = GetSkillColorCache(packet->player_id))
  258.     {
  259.         p = c->Get();
  260.         peer->EncodeHeader(HEADER_DG_SKILL_COLOR_LOAD, dwHandle, sizeof(p->dwSkillColor));
  261.         peer->Encode(p->dwSkillColor, sizeof(p->dwSkillColor));
  262.     }
  263.     else
  264.     {
  265.         char szQuery[QUERY_MAX_LEN];
  266.         snprintf(szQuery, sizeof(szQuery), "SELECT "
  267.             "s1_col1, s1_col2, s1_col3, s1_col4, s1_col5, "
  268.             "s2_col1, s2_col2, s2_col3, s2_col4, s2_col5, "
  269.             "s3_col1, s3_col2, s3_col3, s3_col4, s3_col5, "
  270.             "s4_col1, s4_col2, s4_col3, s4_col4, s4_col5, "
  271.             "s5_col1, s5_col2, s5_col3, s5_col4, s5_col5, "
  272.             "s6_col1, s6_col2, s6_col3, s6_col4, s6_col5, " // end of skills
  273.             "s7_col1, s7_col2, s7_col3, s7_col4, s7_col5, " // begin of buffs
  274.             "s8_col1, s8_col2, s8_col3, s8_col4, s8_col5, "
  275.             "s9_col1, s9_col2, s9_col3, s9_col4, s9_col5, "
  276.             "s10_col1, s10_col2, s10_col3, s10_col4, s10_col5 "
  277.             "s11_col1, s11_col2, s11_col3, s11_col4, s11_col5 "
  278.             "FROM skill_color%s WHERE player_id=%d",
  279.             GetTablePostfix(), packet->player_id);
  280.         CDBManager::instance().ReturnQuery(szQuery, QID_SKILL_COLOR, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));
  281.     }
  282. }
  283. #endif
  284.  
  285. /*
  286.  * PLAYER LOAD
  287.  */
  288. void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoadPacket * packet)
  289. {
  290.     CPlayerTableCache * c;
  291.     TPlayerTable * pTab;
  292.  
  293.     //
  294.     // 한 계정에 속한 모든 캐릭터들 캐쉬처리
  295.     //
  296.     CLoginData * pLoginData = GetLoginDataByAID(packet->account_id);
  297.  
  298.     if (pLoginData)
  299.     {
  300.         for (int n = 0; n < PLAYER_PER_ACCOUNT; ++n)
  301.             if (pLoginData->GetAccountRef().players[n].dwID != 0)
  302.                 DeleteLogoutPlayer(pLoginData->GetAccountRef().players[n].dwID);
  303.     }
  304.  
  305.     //----------------------------------------------------------------
  306.     // 1. 유저정보가 DBCache 에 존재 : DBCache에서
  307.     // 2. 유저정보가 DBCache 에 없음 : DB에서
  308.     // ---------------------------------------------------------------
  309.  
  310.     //----------------------------------
  311.     // 1. 유저정보가 DBCache 에 존재 : DBCache에서
  312.     //----------------------------------
  313.     if ((c = GetPlayerCache(packet->player_id)))
  314.     {
  315.         CLoginData * pkLD = GetLoginDataByAID(packet->account_id);
  316.  
  317.         if (!pkLD || pkLD->IsPlay())
  318.         {
  319.             sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0);
  320.             peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, dwHandle, 0);
  321.             return;
  322.         }
  323.  
  324.         pTab = c->Get();
  325.  
  326.         pkLD->SetPlay(true);
  327.         SendLoginToBilling(pkLD, true);
  328.         thecore_memcpy(pTab->aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(pTab->aiPremiumTimes));
  329.  
  330.         peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, dwHandle, sizeof(TPlayerTable));
  331.         peer->Encode(pTab, sizeof(TPlayerTable));
  332.  
  333.         if (packet->player_id != pkLD->GetLastPlayerID())
  334.         {
  335.             TPacketNeedLoginLogInfo logInfo;
  336.             logInfo.dwPlayerID = packet->player_id;
  337.  
  338.             pkLD->SetLastPlayerID( packet->player_id );
  339.  
  340.             peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, dwHandle, sizeof(TPacketNeedLoginLogInfo) );
  341.             peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) );
  342.         }
  343.  
  344.         char szQuery[1024] = { 0, };
  345.  
  346.         TItemCacheSet * pSet = GetItemCacheSet(pTab->id);
  347.  
  348.         sys_log(0, "[PLAYER_LOAD] ID %s pid %d gold %d ", pTab->name, pTab->id, pTab->gold);
  349.  
  350.         //--------------------------------------------
  351.         // 아이템 & AFFECT & QUEST 로딩 :
  352.         //--------------------------------------------
  353.         // 1) 아이템이 DBCache 에 존재 : DBCache 에서 가져옴
  354.         // 2) 아이템이 DBCache 에 없음 : DB 에서 가져옴
  355.  
  356.         /////////////////////////////////////////////
  357.         // 1) 아이템이 DBCache 에 존재 : DBCache 에서 가져옴
  358.         /////////////////////////////////////////////
  359.         if (pSet)
  360.         {
  361.             static std::vector<TPlayerItem> s_items;
  362.             s_items.resize(pSet->size());
  363.  
  364.             DWORD dwCount = 0;
  365.             TItemCacheSet::iterator it = pSet->begin();
  366.  
  367.             while (it != pSet->end())
  368.             {
  369.                 CItemCache * c = *it++;
  370.                 TPlayerItem * p = c->Get();
  371.  
  372.                 if (p->vnum) // vnum이 없으면 삭제된 아이템이다.
  373.                     thecore_memcpy(&s_items[dwCount++], p, sizeof(TPlayerItem));
  374.             }
  375.  
  376.             if (g_test_server)
  377.                 sys_log(0, "ITEM_CACHE: HIT! %s count: %u", pTab->name, dwCount);
  378.  
  379.             peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount);
  380.             peer->EncodeDWORD(dwCount);
  381.  
  382.             if (dwCount)
  383.                 peer->Encode(&s_items[0], sizeof(TPlayerItem) * dwCount);
  384.  
  385.             // Quest
  386.             snprintf(szQuery, sizeof(szQuery),
  387.                     "SELECT dwPID,szName,szState,lValue FROM quest%s WHERE dwPID=%d AND lValue<>0",
  388.                     GetTablePostfix(), pTab->id);
  389.  
  390.             CDBManager::instance().ReturnQuery(szQuery, QID_QUEST, peer->GetHandle(), new ClientHandleInfo(dwHandle,0,packet->account_id));
  391.  
  392.             // Affect
  393.             snprintf(szQuery, sizeof(szQuery),
  394.                     "SELECT dwPID,bType,bApplyOn,lApplyValue,dwFlag,lDuration,lSPCost FROM affect%s WHERE dwPID=%d",
  395.                     GetTablePostfix(), pTab->id);
  396.             // @fixme402 ClientHandleInfo+pTab->id
  397.             CDBManager::instance().ReturnQuery(szQuery, QID_AFFECT, peer->GetHandle(), new ClientHandleInfo(dwHandle, pTab->id));
  398.         }
  399.         /////////////////////////////////////////////
  400.         // 2) 아이템이 DBCache 에 없음 : DB 에서 가져옴
  401.         /////////////////////////////////////////////
  402.         else
  403.         {
  404.             snprintf(szQuery, sizeof(szQuery),
  405.                     "SELECT id,window+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6 "
  406.                     "FROM item%s WHERE owner_id=%d AND (window in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY','SWITCHBOT'))",
  407.  
  408.             GetTablePostfix(), pTab->id);
  409.  
  410.             CDBManager::instance().ReturnQuery(szQuery,
  411.                     QID_ITEM,
  412.                     peer->GetHandle(),
  413.                     new ClientHandleInfo(dwHandle, pTab->id));
  414.             snprintf(szQuery, sizeof(szQuery),
  415.                     "SELECT dwPID, szName, szState, lValue FROM quest%s WHERE dwPID=%d",
  416.                     GetTablePostfix(), pTab->id);
  417.  
  418.             CDBManager::instance().ReturnQuery(szQuery,
  419.                     QID_QUEST,
  420.                     peer->GetHandle(),
  421.                     new ClientHandleInfo(dwHandle, pTab->id));
  422.             snprintf(szQuery, sizeof(szQuery),
  423.                     "SELECT dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost FROM affect%s WHERE dwPID=%d",
  424.                     GetTablePostfix(), pTab->id);
  425.  
  426.             CDBManager::instance().ReturnQuery(szQuery,
  427.                     QID_AFFECT,
  428.                     peer->GetHandle(),
  429.                     new ClientHandleInfo(dwHandle, pTab->id));
  430.         }
  431.         //ljw
  432.         //return;
  433.     }
  434.     //----------------------------------
  435.     // 2. 유저정보가 DBCache 에 없음 : DB에서
  436.     //----------------------------------
  437.     else
  438.     {
  439.         sys_log(0, "[PLAYER_LOAD] Load from PlayerDB pid[%d]", packet->player_id);
  440.  
  441.         char queryStr[QUERY_MAX_LEN];
  442.  
  443.         //--------------------------------------------------------------
  444.         // 캐릭터 정보 얻어오기 : 무조건 DB에서
  445.  
  446.         snprintf(queryStr, sizeof(queryStr),
  447.                 "SELECT "
  448.                 "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,"
  449.                 "gold,level,level_step,st,ht,dx,iq,exp,"
  450.                 "stat_point,skill_point,sub_skill_point,stat_reset_count,part_base,part_hair,"
  451.                 "skill_level,quickslot,skill_group,alignment,prestige,horse_level,horse_riding,horse_hp,horse_hp_droptime,horse_stamina,"
  452.                 "UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(last_play),horse_skill_point"
  453.                 ",title, title_color0, title_color1, title_color2, title_color3 "
  454.  
  455.                 ",fish_use_count, fish_slots "
  456.  
  457.  
  458.                 "FROM player%s WHERE id=%d",
  459.                 GetTablePostfix(), packet->player_id,
  460. ////BughyT Fix :D
  461.                 stColourTables.str().c_str());
  462. ////End BughyT Fix :D
  463.  
  464.         ClientHandleInfo * pkInfo = new ClientHandleInfo(dwHandle, packet->player_id);
  465.         pkInfo->account_id = packet->account_id;
  466.         CDBManager::instance().ReturnQuery(queryStr, QID_PLAYER, peer->GetHandle(), pkInfo);
  467.  
  468.         //--------------------------------------------------------------
  469.         // 아이템 가져오기
  470.         //--------------------------------------------------------------
  471.         snprintf(queryStr, sizeof(queryStr),
  472.                 "SELECT id,window+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6 "
  473.                 "FROM item%s WHERE owner_id=%d AND (window in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY','SWITCHBOT'))",
  474.  
  475.         GetTablePostfix(), packet->player_id);
  476.         CDBManager::instance().ReturnQuery(queryStr, QID_ITEM, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));
  477.  
  478.         //--------------------------------------------------------------
  479.         // QUEST 가져오기
  480.         //--------------------------------------------------------------
  481.         snprintf(queryStr, sizeof(queryStr),
  482.                 "SELECT dwPID,szName,szState,lValue FROM quest%s WHERE dwPID=%d",
  483.                 GetTablePostfix(), packet->player_id);
  484.         CDBManager::instance().ReturnQuery(queryStr, QID_QUEST, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id,packet->account_id));
  485.         //독일 선물 기능에서 item_award테이블에서 login 정보를 얻기위해 account id도 넘겨준다
  486.         //--------------------------------------------------------------
  487.         // AFFECT 가져오기
  488.         //--------------------------------------------------------------
  489.         snprintf(queryStr, sizeof(queryStr),
  490.                 "SELECT dwPID,bType,bApplyOn,lApplyValue,dwFlag,lDuration,lSPCost FROM affect%s WHERE dwPID=%d",
  491.                 GetTablePostfix(), packet->player_id);
  492.         CDBManager::instance().ReturnQuery(queryStr, QID_AFFECT, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));
  493.     }
  494.  
  495.  
  496. }
  497. void CClientManager::ItemAward(CPeer * peer,char* login)
  498. {
  499.     char login_t[LOGIN_MAX_LEN + 1] = "";
  500.     strlcpy(login_t,login,LOGIN_MAX_LEN + 1);
  501.     std::set<TItemAward *> * pSet = ItemAwardManager::instance().GetByLogin(login_t);
  502.     if(pSet == NULL)
  503.         return;
  504.     __typeof(pSet->begin()) it = pSet->begin(); //taken_time이 NULL인것들 읽어옴
  505.     while(it != pSet->end() )
  506.     {
  507.         TItemAward * pItemAward = *(it++);
  508.         char* whyStr = pItemAward->szWhy;   //why 콜룸 읽기
  509.         char cmdStr[100] = "";  //why콜룸에서 읽은 값을 임시 문자열에 복사해둠
  510.         strcpy(cmdStr,whyStr);  //명령어 얻는 과정에서 토큰쓰면 원본도 토큰화 되기 때문
  511.         char command[20] = "";
  512.         // @fixme203 directly GetCommand instead of strcpy
  513.         GetCommand(cmdStr, command);            // command 얻기
  514.         if( !(strcmp(command,"GIFT") )) // command 가 GIFT이면
  515.         {
  516.             TPacketItemAwardInfromer giftData;
  517.             strcpy(giftData.login, pItemAward->szLogin);    //로그인 아이디 복사
  518.             strcpy(giftData.command, command);                  //명령어 복사
  519.             giftData.vnum = pItemAward->dwVnum;             //아이템 vnum도 복사
  520.             ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer));
  521.         }
  522.     }
  523. }
  524. char* CClientManager::GetCommand(char* str, char* command) // @fixme203
  525. {
  526.     char* tok;
  527.  
  528.     if( str[0] == '[' )
  529.     {
  530.         tok = strtok(str,"]");
  531.         strcat(command,&tok[1]);
  532.     }
  533.  
  534.     return command;
  535. }
  536.  
  537. bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
  538. {
  539.     if (mysql_num_rows(res) == 0)   // 데이터 없음
  540.         return false;
  541.  
  542.     memset(pkTab, 0, sizeof(TPlayerTable));
  543.  
  544.     MYSQL_ROW row = mysql_fetch_row(res);
  545.  
  546.     int col = 0;
  547.     str_to_number(pkTab->id, row[col++]);
  548.     strlcpy(pkTab->name, row[col++], sizeof(pkTab->name));
  549.     str_to_number(pkTab->job, row[col++]);
  550.     str_to_number(pkTab->voice, row[col++]);
  551.     str_to_number(pkTab->dir, row[col++]);
  552.     str_to_number(pkTab->x, row[col++]);
  553.     str_to_number(pkTab->y, row[col++]);
  554.     str_to_number(pkTab->z, row[col++]);
  555.     str_to_number(pkTab->lMapIndex, row[col++]);
  556.     str_to_number(pkTab->lExitX, row[col++]);
  557.     str_to_number(pkTab->lExitY, row[col++]);
  558.     str_to_number(pkTab->lExitMapIndex,  row[col++]);
  559.     str_to_number(pkTab->hp, row[col++]);
  560.     str_to_number(pkTab->sp, row[col++]);
  561.     str_to_number(pkTab->stamina, row[col++]);
  562.     str_to_number(pkTab->sRandomHP, row[col++]);
  563.     str_to_number(pkTab->sRandomSP, row[col++]);
  564.     str_to_number(pkTab->playtime, row[col++]);
  565.     str_to_number(pkTab->gold, row[col++]);
  566.     str_to_number(pkTab->level, row[col++]);
  567.     str_to_number(pkTab->level_step, row[col++]);
  568.     str_to_number(pkTab->st, row[col++]);
  569.     str_to_number(pkTab->ht, row[col++]);
  570.     str_to_number(pkTab->dx, row[col++]);
  571.     str_to_number(pkTab->iq, row[col++]);
  572.     str_to_number(pkTab->exp, row[col++]);
  573.     str_to_number(pkTab->stat_point, row[col++]);
  574.     str_to_number(pkTab->skill_point, row[col++]);
  575.     str_to_number(pkTab->sub_skill_point, row[col++]);
  576.     str_to_number(pkTab->stat_reset_count, row[col++]);
  577.     str_to_number(pkTab->part_base, row[col++]);
  578.     str_to_number(pkTab->parts[PART_HAIR], row[col++]);
  579.  
  580.     if (row[col])
  581.         thecore_memcpy(pkTab->skills, row[col], sizeof(pkTab->skills));
  582.     else
  583.         memset(&pkTab->skills, 0, sizeof(pkTab->skills));
  584.  
  585.     col++;
  586.  
  587.     if (row[col])
  588.         thecore_memcpy(pkTab->quickslot, row[col], sizeof(pkTab->quickslot));
  589.     else
  590.         memset(pkTab->quickslot, 0, sizeof(pkTab->quickslot));
  591.  
  592.     col++;
  593.  
  594.     str_to_number(pkTab->skill_group, row[col++]);
  595.     str_to_number(pkTab->lAlignment, row[col++]);
  596. #ifdef ENABLE_TITLE_SYSTEM         
  597.     str_to_number(pkTab->lPrestige, row[col++]);
  598. #endif
  599.  
  600.     col++;
  601.  
  602.     str_to_number(pkTab->horse.bLevel, row[col++]);
  603.     str_to_number(pkTab->horse.bRiding, row[col++]);
  604.     str_to_number(pkTab->horse.sHealth, row[col++]);
  605.     str_to_number(pkTab->horse.dwHorseHealthDropTime, row[col++]);
  606.     str_to_number(pkTab->horse.sStamina, row[col++]);
  607. #ifdef __TITLE_SYSTEM
  608.     if (row[col])
  609.         strcpy(pkTab->title.szName, row[col]);
  610.     else
  611.         memset(pkTab->title.szName, '\0', sizeof(pkTab->title));
  612.  
  613.     col++;
  614.    
  615.     for (int i = 0; i<TITLE_COLOR_MAX_NUM; ++i)
  616.     {
  617.         str_to_number(pkTab->title.bColours[i], row[col]);
  618.         col++;
  619.     }
  620. #endif
  621.     str_to_number(pkTab->logoff_interval, row[col++]);
  622.     str_to_number(pkTab->horse_skill_point, row[col++]);
  623.  
  624. #ifdef ENABLE_FISH_EVENT
  625.     str_to_number(pkTab->fishEventUseCount, row[col++]);
  626.    
  627.     if (row[col])
  628.         thecore_memcpy(pkTab->fishSlots, row[col], sizeof(pkTab->fishSlots));
  629.     else
  630.         memset(pkTab->fishSlots, 0, sizeof(pkTab->fishSlots));
  631.  
  632.     col++;
  633. #endif
  634.     // reset sub_skill_point
  635.     {
  636.         pkTab->skills[123].bLevel = 0; // SKILL_CREATE
  637.  
  638.         if (pkTab->level > 9)
  639.         {
  640.             int max_point = pkTab->level - 9;
  641.  
  642.             int skill_point =
  643.                 MIN(20, pkTab->skills[121].bLevel) +    // SKILL_LEADERSHIP         통솔력
  644.                 MIN(20, pkTab->skills[124].bLevel) +    // SKILL_MINING             채광
  645.                 MIN(10, pkTab->skills[131].bLevel) +    // SKILL_HORSE_SUMMON       말소환
  646.                 MIN(20, pkTab->skills[141].bLevel) +    // SKILL_ADD_HP             HP보강
  647.                 MIN(20, pkTab->skills[142].bLevel);     // SKILL_RESIST_PENETRATE   관통저항
  648.  
  649.             pkTab->sub_skill_point = max_point - skill_point;
  650.         }
  651.         else
  652.             pkTab->sub_skill_point = 0;
  653.     }
  654.  
  655.     return true;
  656. }
  657.  
  658. void CClientManager::RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD dwQID)
  659. {
  660.     CQueryInfo * qi = (CQueryInfo *) pMsg->pvUserData;
  661.     std::unique_ptr<ClientHandleInfo> info((ClientHandleInfo *) qi->pvData);
  662.  
  663.     MYSQL_RES * pSQLResult = pMsg->Get()->pSQLResult;
  664.     if (!pSQLResult)
  665.     {
  666.         sys_err("null MYSQL_RES QID %u", dwQID);
  667.         return;
  668.     }
  669.  
  670.     switch (dwQID)
  671.     {
  672.         case QID_PLAYER:
  673.             sys_log(0, "QID_PLAYER %u %u", info->dwHandle, info->player_id);
  674.             RESULT_PLAYER_LOAD(peer, pSQLResult, info.get());
  675.  
  676.             break;
  677. #ifdef __SKILL_COLOR_SYSTEM__
  678.         case QID_SKILL_COLOR:
  679.             sys_log(0, "QID_SKILL_COLOR %u %u", info->dwHandle, info->player_id);
  680.             RESULT_SKILL_COLOR_LOAD(peer, pSQLResult, info->dwHandle);
  681.             break;
  682. #endif
  683.         case QID_ITEM:
  684.             sys_log(0, "QID_ITEM %u", info->dwHandle);
  685.             RESULT_ITEM_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
  686.             break;
  687.  
  688.         case QID_QUEST:
  689.             {
  690.                 sys_log(0, "QID_QUEST %u", info->dwHandle);
  691.                 RESULT_QUEST_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
  692.                 //aid얻기
  693.                 ClientHandleInfo*  temp1 = info.get();
  694.                 if (temp1 == NULL)
  695.                     break;
  696.  
  697.                 CLoginData* pLoginData1 = GetLoginDataByAID(temp1->account_id); //
  698.                 //독일 선물 기능
  699.                 if( pLoginData1->GetAccountRef().login == NULL)
  700.                     break;
  701.                 if( pLoginData1 == NULL )
  702.                     break;
  703.                 sys_log(0,"info of pLoginData1 before call ItemAwardfunction %d",pLoginData1);
  704.                 ItemAward(peer,pLoginData1->GetAccountRef().login);
  705.             }
  706.             break;
  707.  
  708.         case QID_AFFECT:
  709.             sys_log(0, "QID_AFFECT %u", info->dwHandle);
  710.             // @fixme402 RESULT_AFFECT_LOAD+info->player_id
  711.             RESULT_AFFECT_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
  712.             break;
  713.             /*
  714.                case QID_PLAYER_ITEM_QUEST_AFFECT:
  715.                sys_log(0, "QID_PLAYER_ITEM_QUEST_AFFECT %u", info->dwHandle);
  716.                RESULT_PLAYER_LOAD(peer, pSQLResult, info->dwHandle);
  717.  
  718.                if (!pMsg->Next())
  719.                {
  720.                sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: ITEM FAILED");
  721.                return;
  722.                }
  723.  
  724.                case QID_ITEM_QUEST_AFFECT:
  725.                sys_log(0, "QID_ITEM_QUEST_AFFECT %u", info->dwHandle);
  726.                RESULT_ITEM_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
  727.  
  728.                if (!pMsg->Next())
  729.                {
  730.                sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: QUEST FAILED");
  731.                return;
  732.                }
  733.  
  734.                case QID_QUEST_AFFECT:
  735.                sys_log(0, "QID_QUEST_AFFECT %u", info->dwHandle);
  736.                RESULT_QUEST_LOAD(peer, pSQLResult, info->dwHandle);
  737.  
  738.                if (!pMsg->Next())
  739.                sys_err("RESULT_COMPOSITE_PLAYER: QID_PLAYER_ITEM_QUEST_AFFECT: AFFECT FAILED");
  740.                else
  741.                RESULT_AFFECT_LOAD(peer, pSQLResult, info->dwHandle);
  742.  
  743.                break;
  744.                */
  745.     }
  746.  
  747. }
  748.  
  749. void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHandleInfo * pkInfo)
  750. {
  751.     TPlayerTable tab;
  752.  
  753.     if (!CreatePlayerTableFromRes(pRes, &tab))
  754.     {
  755.         peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0);
  756.         return;
  757.     }
  758.  
  759.     CLoginData * pkLD = GetLoginDataByAID(pkInfo->account_id);
  760.  
  761.     if (!pkLD || pkLD->IsPlay())
  762.     {
  763.         sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0);
  764.         peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0);
  765.         return;
  766.     }
  767.  
  768.     pkLD->SetPlay(true);
  769.     SendLoginToBilling(pkLD, true);
  770.     thecore_memcpy(tab.aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(tab.aiPremiumTimes));
  771.  
  772.     peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, pkInfo->dwHandle, sizeof(TPlayerTable));
  773.     peer->Encode(&tab, sizeof(TPlayerTable));
  774.  
  775.     if (tab.id != pkLD->GetLastPlayerID())
  776.     {
  777.         TPacketNeedLoginLogInfo logInfo;
  778.         logInfo.dwPlayerID = tab.id;
  779.  
  780.         pkLD->SetLastPlayerID( tab.id );
  781.  
  782.         peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, pkInfo->dwHandle, sizeof(TPacketNeedLoginLogInfo) );
  783.         peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) );
  784.     }
  785. }
  786.  
  787. void CClientManager::RESULT_ITEM_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwPID)
  788. {
  789.     static std::vector<TPlayerItem> s_items;
  790.     //DB에서 아이템 정보를 읽어온다.
  791.     CreateItemTableFromRes(pRes, &s_items, dwPID);
  792.     DWORD dwCount = s_items.size();
  793.  
  794.     peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount);
  795.     peer->EncodeDWORD(dwCount);
  796.  
  797.     //CacheSet을 만든다
  798.     CreateItemCacheSet(dwPID);
  799.  
  800.     // ITEM_LOAD_LOG_ATTACH_PID
  801.     sys_log(0, "ITEM_LOAD: count %u pid %u", dwCount, dwPID);
  802.     // END_OF_ITEM_LOAD_LOG_ATTACH_PID
  803.  
  804.     if (dwCount)
  805.     {
  806.         peer->Encode(&s_items[0], sizeof(TPlayerItem) * dwCount);
  807.  
  808.         for (DWORD i = 0; i < dwCount; ++i)
  809.             PutItemCache(&s_items[i], true); // 로드한 것은 따로 저장할 필요 없으므로, 인자 bSkipQuery에 true를 넣는다.
  810.     }
  811. }
  812.  
  813.  
  814. #ifdef __SKILL_COLOR_SYSTEM__
  815. void CClientManager::RESULT_SKILL_COLOR_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle)
  816. {
  817.     DWORD dwSkillColor[ESkillColorLength::MAX_SKILL_COUNT + ESkillColorLength::MAX_BUFF_COUNT][ESkillColorLength::MAX_EFFECT_COUNT];
  818.     memset(dwSkillColor, 0, sizeof(dwSkillColor));
  819.  
  820.     CreateSkillColorTableFromRes(pRes, *dwSkillColor);
  821.     sys_log(0, "SKILL_COLOR_LOAD %i, %i, %i, %i,", dwSkillColor[0][0], dwSkillColor[1][1], dwSkillColor[2][2], dwSkillColor[3][3]);
  822.     peer->EncodeHeader(HEADER_DG_SKILL_COLOR_LOAD, dwHandle, sizeof(dwSkillColor));
  823.     peer->Encode(&dwSkillColor, sizeof(dwSkillColor));
  824. }
  825. #endif
  826. // @fixme402 (RESULT_AFFECT_LOAD +dwRealPID)
  827. void CClientManager::RESULT_AFFECT_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwRealPID)
  828. {
  829.     int iNumRows;
  830.  
  831.     if ((iNumRows = mysql_num_rows(pRes)) == 0) // 데이터 없음
  832.     {
  833.         // @fixme402 begin
  834.         static DWORD dwPID;
  835.         static DWORD dwCount = 0; //1;
  836.         static TPacketAffectElement paeTable = {0};
  837.  
  838.         dwPID = dwRealPID;
  839.         sys_log(0, "AFFECT_LOAD: count %u PID %u RealPID %u", dwCount, dwPID, dwRealPID);
  840.  
  841.         peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount);
  842.         peer->Encode(&dwPID, sizeof(DWORD));
  843.         peer->Encode(&dwCount, sizeof(DWORD));
  844.         peer->Encode(&paeTable, sizeof(TPacketAffectElement) * dwCount);
  845.         // @fixme402 end
  846.         return;
  847.     }
  848.  
  849.     static std::vector<TPacketAffectElement> s_elements;
  850.     s_elements.resize(iNumRows);
  851.  
  852.     DWORD dwPID = 0;
  853.  
  854.     MYSQL_ROW row;
  855.  
  856.     for (int i = 0; i < iNumRows; ++i)
  857.     {
  858.         TPacketAffectElement & r = s_elements[i];
  859.         row = mysql_fetch_row(pRes);
  860.  
  861.         if (dwPID == 0)
  862.             str_to_number(dwPID, row[0]);
  863.  
  864.         str_to_number(r.dwType, row[1]);
  865.         str_to_number(r.bApplyOn, row[2]);
  866.         str_to_number(r.lApplyValue, row[3]);
  867.         str_to_number(r.dwFlag, row[4]);
  868.         str_to_number(r.lDuration, row[5]);
  869.         str_to_number(r.lSPCost, row[6]);
  870.     }
  871.  
  872.     sys_log(0, "AFFECT_LOAD: count %d PID %u", s_elements.size(), dwPID);
  873.  
  874.     DWORD dwCount = s_elements.size();
  875.  
  876.     peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount);
  877.     peer->Encode(&dwPID, sizeof(DWORD));
  878.     peer->Encode(&dwCount, sizeof(DWORD));
  879.     peer->Encode(&s_elements[0], sizeof(TPacketAffectElement) * dwCount);
  880. }
  881.  
  882. void CClientManager::RESULT_QUEST_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD pid)
  883. {
  884.     int iNumRows;
  885.  
  886.     if ((iNumRows = mysql_num_rows(pRes)) == 0)
  887.     {
  888.         DWORD dwCount = 0;
  889.         peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD));
  890.         peer->Encode(&dwCount, sizeof(DWORD));
  891.         return;
  892.     }
  893.  
  894.     static std::vector<TQuestTable> s_table;
  895.     s_table.resize(iNumRows);
  896.  
  897.     MYSQL_ROW row;
  898.  
  899.     for (int i = 0; i < iNumRows; ++i)
  900.     {
  901.         TQuestTable & r = s_table[i];
  902.  
  903.         row = mysql_fetch_row(pRes);
  904.  
  905.         str_to_number(r.dwPID, row[0]);
  906.         strlcpy(r.szName, row[1], sizeof(r.szName));
  907.         strlcpy(r.szState, row[2], sizeof(r.szState));
  908.         str_to_number(r.lValue, row[3]);
  909.     }
  910.  
  911.     sys_log(0, "QUEST_LOAD: count %d PID %u", s_table.size(), s_table[0].dwPID);
  912.  
  913.     DWORD dwCount = s_table.size();
  914.  
  915.     peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD) + sizeof(TQuestTable) * dwCount);
  916.     peer->Encode(&dwCount, sizeof(DWORD));
  917.     peer->Encode(&s_table[0], sizeof(TQuestTable) * dwCount);
  918. }
  919.  
  920. /*
  921.  * PLAYER SAVE
  922.  */
  923. void CClientManager::QUERY_PLAYER_SAVE(CPeer * peer, DWORD dwHandle, TPlayerTable * pkTab)
  924. {
  925.     if (g_test_server)
  926.         sys_log(0, "PLAYER_SAVE: %s", pkTab->name);
  927.  
  928.     PutPlayerCache(pkTab);
  929. }
  930.  
  931. typedef std::map<DWORD, time_t> time_by_id_map_t;
  932. static time_by_id_map_t s_createTimeByAccountID;
  933.  
  934. /*
  935.  * PLAYER CREATE
  936.  */
  937. void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerCreatePacket* packet)
  938. {
  939.     char    queryStr[QUERY_MAX_LEN];
  940.     int     queryLen;
  941.     int     player_id;
  942.  
  943.     // 한 계정에 X초 내로 캐릭터 생성을 할 수 없다.
  944.     time_by_id_map_t::iterator it = s_createTimeByAccountID.find(packet->account_id);
  945.  
  946.     if (it != s_createTimeByAccountID.end())
  947.     {
  948.         time_t curtime = time(0);
  949.  
  950.         if (curtime - it->second < 30)
  951.         {
  952.             peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
  953.             return;
  954.         }
  955.     }
  956.  
  957.     queryLen = snprintf(queryStr, sizeof(queryStr),
  958.             "SELECT pid%u FROM player_index%s WHERE id=%d", packet->account_index + 1, GetTablePostfix(), packet->account_id);
  959.  
  960.     std::unique_ptr<SQLMsg> pMsg0(CDBManager::instance().DirectQuery(queryStr));
  961.  
  962.     if (pMsg0->Get()->uiNumRows != 0)
  963.     {
  964.         if (!pMsg0->Get()->pSQLResult)
  965.         {
  966.             peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
  967.             return;
  968.         }
  969.  
  970.         MYSQL_ROW row = mysql_fetch_row(pMsg0->Get()->pSQLResult);
  971.  
  972.         DWORD dwPID = 0; str_to_number(dwPID, row[0]);
  973.         if (row[0] && dwPID > 0)
  974.         {
  975.             peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
  976.             sys_log(0, "ALREADY EXIST AccountChrIdx %d ID %d", packet->account_index, dwPID);
  977.             return;
  978.         }
  979.     }
  980.     else
  981.     {
  982.         peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
  983.         return;
  984.     }
  985.  
  986.     if (g_stLocale == "sjis")
  987.         snprintf(queryStr, sizeof(queryStr),
  988.             "SELECT COUNT(*) as count FROM player%s WHERE name='%s' collate sjis_japanese_ci",
  989.             GetTablePostfix(), packet->player_table.name);
  990.     else
  991.     snprintf(queryStr, sizeof(queryStr),
  992.             "SELECT COUNT(*) as count FROM player%s WHERE name='%s'", GetTablePostfix(), packet->player_table.name);
  993.  
  994.     std::unique_ptr<SQLMsg> pMsg1(CDBManager::instance().DirectQuery(queryStr));
  995.  
  996.     if (pMsg1->Get()->uiNumRows)
  997.     {
  998.         if (!pMsg1->Get()->pSQLResult)
  999.         {
  1000.             peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
  1001.             return;
  1002.         }
  1003.  
  1004.         MYSQL_ROW row = mysql_fetch_row(pMsg1->Get()->pSQLResult);
  1005.  
  1006.         if (*row[0] != '0')
  1007.         {
  1008.             sys_log(0, "ALREADY EXIST name %s, row[0] %s query %s", packet->player_table.name, row[0], queryStr);
  1009.             peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
  1010.             return;
  1011.         }
  1012.     }
  1013.     else
  1014.     {
  1015.         peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
  1016.         return;
  1017.     }
  1018.  
  1019.     queryLen = snprintf(queryStr, sizeof(queryStr),
  1020.             "INSERT INTO player%s "
  1021.             "(id, account_id, name, level, st, ht, dx, iq, "
  1022.             "job, voice, dir, x, y, z, "
  1023.             "hp, mp, random_hp, random_sp, stat_point, stamina, part_base, "
  1024.             "part_main, part_hair, gold, "
  1025.             "playtime, skill_level, "
  1026. #ifdef ENABLE_FISH_EVENT
  1027.             "fish_slots, "
  1028. #endif
  1029.             "quickslot) "
  1030.             "VALUES(0, %u, '%s', %d, %d, %d, %d, %d, "
  1031.             "%d, %d, %d, %d, %d, %d, %d, "
  1032.             "%d, %d, %d, %d, %d, %d, %d, 0, %d, 0, ",
  1033.             GetTablePostfix(),
  1034.             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,
  1035.             packet->player_table.job, packet->player_table.voice, packet->player_table.dir, packet->player_table.x, packet->player_table.y, packet->player_table.z,
  1036.             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);
  1037.  
  1038.     sys_log(0, "PlayerCreate accountid %d name %s level %d gold %d, st %d ht %d job %d",
  1039.             packet->account_id,
  1040.             packet->player_table.name,
  1041.             packet->player_table.level,
  1042.             packet->player_table.gold,
  1043.             packet->player_table.st,
  1044.             packet->player_table.ht,
  1045.             packet->player_table.job);
  1046.  
  1047.     static char text[4096 + 1];
  1048.  
  1049.     CDBManager::instance().EscapeString(text, packet->player_table.skills, sizeof(packet->player_table.skills));
  1050.     queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s', ", text);
  1051.     if (g_test_server)
  1052.         sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);
  1053.  
  1054. #ifdef ENABLE_FISH_EVENT
  1055.     CDBManager::instance().EscapeString(text, packet->player_table.quickslot, sizeof(packet->player_table.quickslot));
  1056.     queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s', ", text);
  1057.  
  1058.     CDBManager::instance().EscapeString(text, packet->player_table.fishSlots, sizeof(packet->player_table.fishSlots));
  1059.     queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s')", text);
  1060. #else
  1061.     CDBManager::instance().EscapeString(text, packet->player_table.quickslot, sizeof(packet->player_table.quickslot));
  1062.     queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s')", text);
  1063. #endif
  1064.  
  1065.     std::unique_ptr<SQLMsg> pMsg2(CDBManager::instance().DirectQuery(queryStr));
  1066.     if (g_test_server)
  1067.         sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);
  1068.  
  1069.     if (pMsg2->Get()->uiAffectedRows <= 0)
  1070.     {
  1071.         peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
  1072.         sys_log(0, "ALREADY EXIST3 query: %s AffectedRows %lu", queryStr, pMsg2->Get()->uiAffectedRows);
  1073.         return;
  1074.     }
  1075.  
  1076.     player_id = pMsg2->Get()->uiInsertID;
  1077.  
  1078.     snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%d=%d WHERE id=%d",
  1079.             GetTablePostfix(), packet->account_index + 1, player_id, packet->account_id);
  1080.     std::unique_ptr<SQLMsg> pMsg3(CDBManager::instance().DirectQuery(queryStr));
  1081.  
  1082.     if (pMsg3->Get()->uiAffectedRows <= 0)
  1083.     {
  1084.         sys_err("QUERY_ERROR: %s", queryStr);
  1085.  
  1086.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), player_id);
  1087.         CDBManager::instance().DirectQuery(queryStr);
  1088.  
  1089.         peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
  1090.         return;
  1091.     }
  1092.  
  1093.     TPacketDGCreateSuccess pack;
  1094.     memset(&pack, 0, sizeof(pack));
  1095.  
  1096.     pack.bAccountCharacterIndex = packet->account_index;
  1097.  
  1098.     pack.player.dwID            = player_id;
  1099.     strlcpy(pack.player.szName, packet->player_table.name, sizeof(pack.player.szName));
  1100.     pack.player.byJob           = packet->player_table.job;
  1101.     pack.player.byLevel         = 1;
  1102.     pack.player.dwPlayMinutes   = 0;
  1103.     pack.player.byST            = packet->player_table.st;
  1104.     pack.player.byHT            = packet->player_table.ht;
  1105.     pack.player.byDX            = packet->player_table.dx;
  1106.     pack.player.byIQ            = packet->player_table.iq;
  1107.     pack.player.wMainPart       = packet->player_table.part_base;
  1108.     pack.player.x           = packet->player_table.x;
  1109.     pack.player.y           = packet->player_table.y;
  1110.  
  1111.     peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_SUCCESS, dwHandle, sizeof(TPacketDGCreateSuccess));
  1112.     peer->Encode(&pack, sizeof(TPacketDGCreateSuccess));
  1113.  
  1114.     sys_log(0, "7 name %s job %d", pack.player.szName, pack.player.byJob);
  1115.  
  1116.     s_createTimeByAccountID[packet->account_id] = time(0);
  1117. }
  1118.  
  1119. /*
  1120.  * PLAYER DELETE
  1121.  */
  1122. void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerDeletePacket* packet)
  1123. {
  1124.     if (!packet->login[0] || !packet->player_id || packet->account_index >= PLAYER_PER_ACCOUNT)
  1125.         return;
  1126.  
  1127.     CLoginData * ld = GetLoginDataByLogin(packet->login);
  1128.  
  1129.     if (!ld)
  1130.     {
  1131.         peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
  1132.         peer->EncodeBYTE(packet->account_index);
  1133.         return;
  1134.     }
  1135.  
  1136.     TAccountTable & r = ld->GetAccountRef();
  1137.  
  1138.     // block for japan
  1139.     if (g_stLocale != "sjis")
  1140.     {
  1141.         if (!IsChinaEventServer())
  1142.         {
  1143.             if (strlen(r.social_id) < 7 || strncmp(packet->private_code, r.social_id + strlen(r.social_id) - 7, 7))
  1144.             {
  1145.                 sys_log(0, "PLAYER_DELETE FAILED len(%d)", strlen(r.social_id));
  1146.                 peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
  1147.                 peer->EncodeBYTE(packet->account_index);
  1148.                 return;
  1149.             }
  1150.  
  1151.             CPlayerTableCache * pkPlayerCache = GetPlayerCache(packet->player_id);
  1152.             if (pkPlayerCache)
  1153.             {
  1154.                 TPlayerTable * pTab = pkPlayerCache->Get();
  1155.  
  1156.                 if (pTab->level >= m_iPlayerDeleteLevelLimit)
  1157.                 {
  1158.                     sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimit);
  1159.                     peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
  1160.                     peer->EncodeBYTE(packet->account_index);
  1161.                     return;
  1162.                 }
  1163.  
  1164.                 if (pTab->level < m_iPlayerDeleteLevelLimitLower)
  1165.                 {
  1166.                     sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimitLower);
  1167.                     peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1);
  1168.                     peer->EncodeBYTE(packet->account_index);
  1169.                     return;
  1170.                 }
  1171.             }
  1172.         }
  1173.     }
  1174.  
  1175.     char szQuery[128];
  1176.     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",
  1177.             GetTablePostfix(), GetTablePostfix(), packet->account_index + 1, packet->player_id, packet->account_index + 1);
  1178.  
  1179.     ClientHandleInfo * pi = new ClientHandleInfo(dwHandle, packet->player_id);
  1180.     pi->account_index = packet->account_index;
  1181.  
  1182.     sys_log(0, "PLAYER_DELETE TRY: %s %d pid%d", packet->login, packet->player_id, packet->account_index + 1);
  1183.     CDBManager::instance().ReturnQuery(szQuery, QID_PLAYER_DELETE, peer->GetHandle(), pi);
  1184. }
  1185.  
  1186. //
  1187. // @version 05/06/10 Bang2ni - 플레이어 삭제시 가격정보 리스트 삭제 추가.
  1188. //
  1189. void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
  1190. {
  1191.     CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
  1192.     ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;
  1193.  
  1194.     if (msg->Get() && msg->Get()->uiNumRows)
  1195.     {
  1196.         MYSQL_ROW row = mysql_fetch_row(msg->Get()->pSQLResult);
  1197.  
  1198.         DWORD dwPID = 0;
  1199.         str_to_number(dwPID, row[0]);
  1200.  
  1201.         int deletedLevelLimit = 0;
  1202.         str_to_number(deletedLevelLimit, row[1]);
  1203.  
  1204.         char szName[64];
  1205.         strlcpy(szName, row[2], sizeof(szName));
  1206.  
  1207.         if (deletedLevelLimit >= m_iPlayerDeleteLevelLimit && !IsChinaEventServer())
  1208.         {
  1209.             sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimit);
  1210.             peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
  1211.             peer->EncodeBYTE(pi->account_index);
  1212.             return;
  1213.         }
  1214.  
  1215.         if (deletedLevelLimit < m_iPlayerDeleteLevelLimitLower)
  1216.         {
  1217.             sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimitLower);
  1218.             peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
  1219.             peer->EncodeBYTE(pi->account_index);
  1220.             return;
  1221.         }
  1222.  
  1223.         char queryStr[QUERY_MAX_LEN];
  1224.  
  1225.         snprintf(queryStr, sizeof(queryStr), "INSERT INTO player_deleted%s SELECT * FROM player%s WHERE id=%d",
  1226.                 GetTablePostfix(), GetTablePostfix(), pi->player_id);
  1227.         std::unique_ptr<SQLMsg> pIns(CDBManager::instance().DirectQuery(queryStr));
  1228.  
  1229.         if (pIns->Get()->uiAffectedRows == 0 || pIns->Get()->uiAffectedRows == (uint32_t)-1)
  1230.         {
  1231.             sys_log(0, "PLAYER_DELETE FAILED %u CANNOT INSERT TO player_deleted%s", dwPID, GetTablePostfix());
  1232.  
  1233.             peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
  1234.             peer->EncodeBYTE(pi->account_index);
  1235.             return;
  1236.         }
  1237.  
  1238.         // 삭제 성공
  1239.         sys_log(0, "PLAYER_DELETE SUCCESS %u", dwPID);
  1240.  
  1241.         char account_index_string[16];
  1242.  
  1243.         snprintf(account_index_string, sizeof(account_index_string), "player_id%d", m_iPlayerIDStart + pi->account_index);
  1244.  
  1245.         // 플레이어 테이블을 캐쉬에서 삭제한다.
  1246.         CPlayerTableCache * pkPlayerCache = GetPlayerCache(pi->player_id);
  1247.  
  1248.         if (pkPlayerCache)
  1249.         {
  1250.             m_map_playerCache.erase(pi->player_id);
  1251.             delete pkPlayerCache;
  1252.         }
  1253.  
  1254.         // 아이템들을 캐쉬에서 삭제한다.
  1255.         TItemCacheSet * pSet = GetItemCacheSet(pi->player_id);
  1256.  
  1257.         if (pSet)
  1258.         {
  1259.             TItemCacheSet::iterator it = pSet->begin();
  1260.  
  1261.             while (it != pSet->end())
  1262.             {
  1263.                 CItemCache * pkItemCache = *it++;
  1264.                 DeleteItemCache(pkItemCache->Get()->id);
  1265.             }
  1266.  
  1267.             pSet->clear();
  1268.             delete pSet;
  1269.  
  1270.             m_map_pkItemCacheSetPtr.erase(pi->player_id);
  1271.         }
  1272.  
  1273.         snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%u=0 WHERE pid%u=%d",
  1274.                 GetTablePostfix(),
  1275.                 pi->account_index + 1,
  1276.                 pi->account_index + 1,
  1277.                 pi->player_id);
  1278.  
  1279.         std::unique_ptr<SQLMsg> pMsg(CDBManager::instance().DirectQuery(queryStr));
  1280.  
  1281.         if (pMsg->Get()->uiAffectedRows == 0 || pMsg->Get()->uiAffectedRows == (uint32_t)-1)
  1282.         {
  1283.             sys_log(0, "PLAYER_DELETE FAIL WHEN UPDATE account table");
  1284.             peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
  1285.             peer->EncodeBYTE(pi->account_index);
  1286.             return;
  1287.         }
  1288.  
  1289.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), pi->player_id);
  1290.         delete CDBManager::instance().DirectQuery(queryStr);
  1291.  
  1292.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM item%s WHERE owner_id=%d AND (window in ('INVENTORY','EQUIPMENT','DRAGON_SOUL_INVENTORY','BELT_INVENTORY','SWITCHBOT'",
  1293.  
  1294.         GetTablePostfix(), pi->player_id);
  1295.  
  1296.         delete CDBManager::instance().DirectQuery(queryStr);
  1297.  
  1298.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM quest%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
  1299.         CDBManager::instance().AsyncQuery(queryStr);
  1300.  
  1301.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM affect%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
  1302.         CDBManager::instance().AsyncQuery(queryStr);
  1303.  
  1304.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM guild_member%s WHERE pid=%d", GetTablePostfix(), pi->player_id);
  1305.         CDBManager::instance().AsyncQuery(queryStr);
  1306.  
  1307.         // MYSHOP_PRICE_LIST
  1308.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM myshop_pricelist%s WHERE owner_id=%d", GetTablePostfix(), pi->player_id);
  1309.         CDBManager::instance().AsyncQuery(queryStr);
  1310.         // END_OF_MYSHOP_PRICE_LIST
  1311.  
  1312.         snprintf(queryStr, sizeof(queryStr), "DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'", GetTablePostfix(), szName, szName);
  1313.         CDBManager::instance().AsyncQuery(queryStr);
  1314.  
  1315.         peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_SUCCESS, pi->dwHandle, 1);
  1316.         peer->EncodeBYTE(pi->account_index);
  1317.     }
  1318.     else
  1319.     {
  1320.         // 삭제 실패
  1321.         sys_log(0, "PLAYER_DELETE FAIL NO ROW");
  1322.         peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
  1323.         peer->EncodeBYTE(pi->account_index);
  1324.     }
  1325. }
  1326.  
  1327. void CClientManager::QUERY_ADD_AFFECT(CPeer * peer, TPacketGDAddAffect * p)
  1328. {
  1329.     char queryStr[QUERY_MAX_LEN];
  1330.     /*
  1331.        snprintf(queryStr, sizeof(queryStr),
  1332.        "INSERT INTO affect%s (dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost) "
  1333.        "VALUES(%u, %u, %u, %d, %u, %d, %d) "
  1334.        "ON DUPLICATE KEY UPDATE lApplyValue=%d, dwFlag=%u, lDuration=%d, lSPCost=%d",
  1335.        GetTablePostfix(),
  1336.        p->dwPID,
  1337.        p->elem.dwType,
  1338.        p->elem.bApplyOn,
  1339.        p->elem.lApplyValue,
  1340.        p->elem.dwFlag,
  1341.        p->elem.lDuration,
  1342.        p->elem.lSPCost,
  1343.        p->elem.lApplyValue,
  1344.        p->elem.dwFlag,
  1345.        p->elem.lDuration,
  1346.        p->elem.lSPCost);
  1347.        */
  1348.     snprintf(queryStr, sizeof(queryStr),
  1349.             "REPLACE INTO affect%s (dwPID, bType, bApplyOn, lApplyValue, dwFlag, lDuration, lSPCost) "
  1350.             "VALUES(%u, %u, %u, %ld, %u, %ld, %ld)",
  1351.             GetTablePostfix(),
  1352.             p->dwPID,
  1353.             p->elem.dwType,
  1354.             p->elem.bApplyOn,
  1355.             p->elem.lApplyValue,
  1356.             p->elem.dwFlag,
  1357.             p->elem.lDuration,
  1358.             p->elem.lSPCost);
  1359.  
  1360.     CDBManager::instance().AsyncQuery(queryStr);
  1361. }
  1362.  
  1363. void CClientManager::QUERY_REMOVE_AFFECT(CPeer * peer, TPacketGDRemoveAffect * p)
  1364. {
  1365.     char queryStr[QUERY_MAX_LEN];
  1366.  
  1367.     snprintf(queryStr, sizeof(queryStr),
  1368.             "DELETE FROM affect%s WHERE dwPID=%u AND bType=%u AND bApplyOn=%u",
  1369.             GetTablePostfix(), p->dwPID, p->dwType, p->bApplyOn);
  1370.  
  1371.     CDBManager::instance().AsyncQuery(queryStr);
  1372. }
  1373.  
  1374.  
  1375. void CClientManager::QUERY_HIGHSCORE_REGISTER(CPeer* peer, TPacketGDHighscore * data)
  1376. {
  1377.     char szQuery[128];
  1378.     snprintf(szQuery, sizeof(szQuery), "SELECT value FROM highscore%s WHERE board='%s' AND pid = %u", GetTablePostfix(), data->szBoard, data->dwPID);
  1379.  
  1380.     sys_log(0, "HEADER_GD_HIGHSCORE_REGISTER: PID %u", data->dwPID);
  1381.  
  1382.     ClientHandleInfo * pi = new ClientHandleInfo(0);
  1383.     strlcpy(pi->login, data->szBoard, sizeof(pi->login));
  1384.     pi->account_id = (DWORD)data->lValue;
  1385.     pi->player_id = data->dwPID;
  1386.     pi->account_index = (data->cDir > 0);
  1387.  
  1388.     CDBManager::instance().ReturnQuery(szQuery, QID_HIGHSCORE_REGISTER, peer->GetHandle(), pi);
  1389. }
  1390.  
  1391. void CClientManager::RESULT_HIGHSCORE_REGISTER(CPeer * pkPeer, SQLMsg * msg)
  1392. {
  1393.     CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
  1394.     ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;
  1395.     //DWORD dwHandle = pi->dwHandle;
  1396.  
  1397.     char szBoard[21];
  1398.     strlcpy(szBoard, pi->login, sizeof(szBoard));
  1399.     int value = (int)pi->account_id;
  1400.  
  1401.     SQLResult * res = msg->Get();
  1402.  
  1403.     if (res->uiNumRows == 0)
  1404.     {
  1405.         // 새로운 하이스코어를 삽입
  1406.         char buf[256];
  1407.         snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
  1408.         CDBManager::instance().AsyncQuery(buf);
  1409.     }
  1410.     else
  1411.     {
  1412.         if (!res->pSQLResult)
  1413.         {
  1414.             delete pi;
  1415.             return;
  1416.         }
  1417.  
  1418.         MYSQL_ROW row = mysql_fetch_row(res->pSQLResult);
  1419.         if (row && row[0])
  1420.         {
  1421.             int current_value = 0; str_to_number(current_value, row[0]);
  1422.             if (((pi->account_index)&&(current_value >= value)) || ((!pi->account_index)&&(current_value <= value)))
  1423.             {
  1424.                 value = current_value;
  1425.             }
  1426.             else
  1427.             {
  1428.                 char buf[256];
  1429.                 snprintf(buf, sizeof(buf), "REPLACE INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
  1430.                 CDBManager::instance().AsyncQuery(buf);
  1431.             }
  1432.         }
  1433.         else
  1434.         {
  1435.             char buf[256];
  1436.             snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
  1437.             CDBManager::instance().AsyncQuery(buf);
  1438.         }
  1439.     }
  1440.     // TODO: 이곳에서 하이스코어가 업데이트 되었는지 체크하여 공지를 뿌려야한다.
  1441.     delete pi;
  1442. }
  1443.  
  1444. void CClientManager::InsertLogoutPlayer(DWORD pid)
  1445. {
  1446.     TLogoutPlayerMap::iterator it = m_map_logout.find(pid);
  1447.  
  1448.     // 존재하지 않을경우 추가
  1449.     if (it != m_map_logout.end())
  1450.     {
  1451.         // 존재할경우 시간만 갱신
  1452.         if (g_log)
  1453.             sys_log(0, "LOGOUT: Update player time pid(%d)", pid);
  1454.  
  1455.         it->second->time = time(0);
  1456.         return;
  1457.     }
  1458.  
  1459.     TLogoutPlayer * pLogout = new TLogoutPlayer;
  1460.     pLogout->pid = pid;
  1461.     pLogout->time = time(0);
  1462.     m_map_logout.insert(std::make_pair(pid, pLogout));
  1463.  
  1464.     if (g_log)
  1465.         sys_log(0, "LOGOUT: Insert player pid(%d)", pid);
  1466. }
  1467.  
  1468. void CClientManager::DeleteLogoutPlayer(DWORD pid)
  1469. {
  1470.     TLogoutPlayerMap::iterator it = m_map_logout.find(pid);
  1471.  
  1472.     if (it != m_map_logout.end())
  1473.     {
  1474.         delete it->second;
  1475.         m_map_logout.erase(it);
  1476.     }
  1477. }
  1478.  
  1479. extern int g_iLogoutSeconds;
  1480.  
  1481. void CClientManager::UpdateLogoutPlayer()
  1482. {
  1483.     time_t now = time(0);
  1484.  
  1485.     TLogoutPlayerMap::iterator it = m_map_logout.begin();
  1486.  
  1487.     while (it != m_map_logout.end())
  1488.     {
  1489.         TLogoutPlayer* pLogout = it->second;
  1490.  
  1491.         if (now - g_iLogoutSeconds > pLogout->time)
  1492.         {
  1493.             FlushItemCacheSet(pLogout->pid);
  1494.             FlushPlayerCacheSet(pLogout->pid);
  1495.  
  1496.             delete pLogout;
  1497.             m_map_logout.erase(it++);
  1498.         }
  1499.         else
  1500.             ++it;
  1501.     }
  1502. }
  1503.  
  1504. void CClientManager::FlushPlayerCacheSet(DWORD pid)
  1505. {
  1506.     TPlayerTableCacheMap::iterator it = m_map_playerCache.find(pid);
  1507.  
  1508.     if (it != m_map_playerCache.end())
  1509.     {
  1510.         CPlayerTableCache * c = it->second;
  1511.         m_map_playerCache.erase(it);
  1512.  
  1513.         c->Flush();
  1514.         delete c;
  1515.     }
  1516. }
  1517.  
  1518.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement