MrP0wers

Untitled

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