m2Farm2025

ClientManagerPlayer.cpp

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