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