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