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