Advertisement
Guest User

clientmanagerplayer.cpp

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