diff --git a/src/db/ItemAwardManager.cpp b/src/db/ItemAwardManager.cpp index b119699..e9985e7 100644 --- a/src/db/ItemAwardManager.cpp +++ b/src/db/ItemAwardManager.cpp @@ -3,12 +3,83 @@ #include "DBManager.h" #include "ItemAwardManager.h" #include "Peer.h" +#include "libsql/Statement.h" #include "ClientManager.h" - - DWORD g_dwLastCachedItemAwardID = 0; + +namespace +{ + bool FallbackItemAwardLoadQuery() + { + char szQuery[QUERY_MAX_LEN]; + snprintf(szQuery, sizeof(szQuery), + "SELECT id,login,vnum,count,socket0,socket1,socket2,mall,why " + "FROM item_award WHERE taken_time IS NULL and id > %d", + g_dwLastCachedItemAwardID); + CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_AWARD_LOAD, 0, NULL); + return true; + } + + bool FallbackItemAwardTakenQuery(DWORD dwAwardID, DWORD dwItemID) + { + char szQuery[QUERY_MAX_LEN]; + snprintf(szQuery, sizeof(szQuery), + "UPDATE item_award SET taken_time=NOW(),item_id=%u WHERE id=%u AND taken_time IS NULL", + dwItemID, dwAwardID); + CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_AWARD_TAKEN, 0, NULL); + return true; + } + + void ProcessItemAwardRow(DWORD dwID, const char* login, DWORD dwVnum, DWORD dwCount, + DWORD dwSocket0, DWORD dwSocket1, DWORD dwSocket2, bool bMall, const char* why) + { + if (ItemAwardManager::instance().GetMapAward().find(dwID) != ItemAwardManager::instance().GetMapAward().end()) + return; + + TItemAward* kData = new TItemAward; + memset(kData, 0, sizeof(TItemAward)); + + kData->dwID = dwID; + trim_and_lower(login, kData->szLogin, sizeof(kData->szLogin)); + kData->dwVnum = dwVnum; + kData->dwCount = dwCount; + kData->dwSocket0 = dwSocket0; + kData->dwSocket1 = dwSocket1; + kData->dwSocket2 = dwSocket2; + kData->bMall = bMall; + + if (why && *why) + { + strlcpy(kData->szWhy, why, sizeof(kData->szWhy)); + char* whyStr = kData->szWhy; + char cmdStr[100] = ""; + strcpy(cmdStr, whyStr); + char command[20] = ""; + strcpy(command, CClientManager::instance().GetCommand(cmdStr)); + if (!(strcmp(command, "GIFT"))) + { + TPacketItemAwardInfromer giftData; + strcpy(giftData.login, kData->szLogin); + strcpy(giftData.command, command); + giftData.vnum = kData->dwVnum; + CClientManager::instance().ForwardPacket(DG::ITEMAWARD_INFORMER, &giftData, sizeof(TPacketItemAwardInfromer)); + } + } + + ItemAwardManager::instance().GetMapAward().insert(std::make_pair(dwID, kData)); + + printf("ITEM_AWARD load id %u bMall %d \n", kData->dwID, kData->bMall); + sys_log(0, "ITEM_AWARD: load id %lu login %s vnum %lu count %u socket %lu", kData->dwID, kData->szLogin, kData->dwVnum, kData->dwCount, kData->dwSocket0); + std::set& kSet = ItemAwardManager::instance().GetMapkSetAwardByLogin()[kData->szLogin]; + kSet.insert(kData); + + if (dwID > g_dwLastCachedItemAwardID) + g_dwLastCachedItemAwardID = dwID; + } +} + ItemAwardManager::ItemAwardManager() { } @@ -19,9 +90,45 @@ ItemAwardManager::~ItemAwardManager() void ItemAwardManager::RequestLoad() { - char szQuery[QUERY_MAX_LEN]; - snprintf(szQuery, sizeof(szQuery), "SELECT id,login,vnum,count,socket0,socket1,socket2,mall,why FROM item_award WHERE taken_time IS NULL and id > %d", g_dwLastCachedItemAwardID); - CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_AWARD_LOAD, 0, NULL); + static const char* query = + "SELECT id, login, vnum, count, socket0, socket1, socket2, mall, COALESCE(why, '') " + "FROM item_award WHERE taken_time IS NULL AND id > ?"; + + CStmt stmt; + DWORD dwID = 0; + DWORD dwVnum = 0; + DWORD dwCount = 0; + DWORD dwSocket0 = 0; + DWORD dwSocket1 = 0; + DWORD dwSocket2 = 0; + char login[LOGIN_MAX_LEN + 1] = {}; + char why[ITEM_AWARD_WHY_MAX_LEN + 1] = {}; + DWORD dwMall = 0; + + if (!stmt.Prepare(CDBManager::instance().GetDirectSQL(), query) || + !stmt.BindParam(MYSQL_TYPE_LONG, &g_dwLastCachedItemAwardID) || + !stmt.BindResult(MYSQL_TYPE_LONG, &dwID) || + !stmt.BindResult(MYSQL_TYPE_STRING, login, sizeof(login)) || + !stmt.BindResult(MYSQL_TYPE_LONG, &dwVnum) || + !stmt.BindResult(MYSQL_TYPE_LONG, &dwCount) || + !stmt.BindResult(MYSQL_TYPE_LONG, &dwSocket0) || + !stmt.BindResult(MYSQL_TYPE_LONG, &dwSocket1) || + !stmt.BindResult(MYSQL_TYPE_LONG, &dwSocket2) || + !stmt.BindResult(MYSQL_TYPE_LONG, &dwMall) || + !stmt.BindResult(MYSQL_TYPE_STRING, why, sizeof(why)) || + !stmt.Execute()) + { + sys_err("ITEM_AWARD: prepared load failed, falling back to legacy query path"); + FallbackItemAwardLoadQuery(); + return; + } + + while (stmt.Fetch()) + { + ProcessItemAwardRow(dwID, login, dwVnum, dwCount, dwSocket0, dwSocket1, dwSocket2, dwMall != 0, why); + memset(login, 0, sizeof(login)); + memset(why, 0, sizeof(why)); + } } void ItemAwardManager::Load(SQLMsg * pMsg) @@ -35,51 +142,22 @@ void ItemAwardManager::Load(SQLMsg * pMsg) DWORD dwID = 0; str_to_number(dwID, row[col++]); + const char* login = row[col++]; - if (m_map_award.find(dwID) != m_map_award.end()) - continue; + DWORD dwVnum = 0; + DWORD dwCount = 0; + DWORD dwSocket0 = 0; + DWORD dwSocket1 = 0; + DWORD dwSocket2 = 0; + DWORD dwMall = 0; + str_to_number(dwVnum, row[col++]); + str_to_number(dwCount, row[col++]); + str_to_number(dwSocket0, row[col++]); + str_to_number(dwSocket1, row[col++]); + str_to_number(dwSocket2, row[col++]); + str_to_number(dwMall, row[col++]); - TItemAward * kData = new TItemAward; - memset(kData, 0, sizeof(TItemAward)); - - kData->dwID = dwID; - trim_and_lower(row[col++], kData->szLogin, sizeof(kData->szLogin)); - str_to_number(kData->dwVnum, row[col++]); - str_to_number(kData->dwCount, row[col++]); - str_to_number(kData->dwSocket0, row[col++]); - str_to_number(kData->dwSocket1, row[col++]); - str_to_number(kData->dwSocket2, row[col++]); - str_to_number(kData->bMall, row[col++]); - - if (row[col]) - { - strlcpy(kData->szWhy, row[col], sizeof(kData->szWhy)); - //게임 중에 why콜룸에 변동이 생기면 - char* whyStr = kData->szWhy; //why 콜룸 읽기 - char cmdStr[100] = ""; //why콜룸에서 읽은 값을 임시 문자열에 복사해둠 - strcpy(cmdStr,whyStr); //명령어 얻는 과정에서 토큰쓰면 원본도 토큰화 되기 때문 - char command[20] = ""; - strcpy(command,CClientManager::instance().GetCommand(cmdStr)); // command 얻기 - //sys_err("%d, %s",pItemAward->dwID,command); - if( !(strcmp(command,"GIFT") )) // command 가 GIFT이면 - { - TPacketItemAwardInfromer giftData; - strcpy(giftData.login, kData->szLogin); //로그인 아이디 복사 - strcpy(giftData.command, command); //명령어 복사 - giftData.vnum = kData->dwVnum; //아이템 vnum도 복사 - CClientManager::instance().ForwardPacket(DG::ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer)); - } - } - - m_map_award.insert(std::make_pair(dwID, kData)); - - printf("ITEM_AWARD load id %u bMall %d \n", kData->dwID, kData->bMall); - sys_log(0, "ITEM_AWARD: load id %lu login %s vnum %lu count %u socket %lu", kData->dwID, kData->szLogin, kData->dwVnum, kData->dwCount, kData->dwSocket0); - std::set & kSet = m_map_kSetAwardByLogin[kData->szLogin]; - kSet.insert(kData); - - if (dwID > g_dwLastCachedItemAwardID) - g_dwLastCachedItemAwardID = dwID; + ProcessItemAwardRow(dwID, login, dwVnum, dwCount, dwSocket0, dwSocket1, dwSocket2, dwMall != 0, row[col] ? row[col] : ""); } } @@ -109,13 +187,18 @@ void ItemAwardManager::Taken(DWORD dwAwardID, DWORD dwItemID) // // Update taken_time in database to prevent not to give him again. // - char szQuery[QUERY_MAX_LEN]; + static const char* query = + "UPDATE item_award SET taken_time=NOW(), item_id=? WHERE id=? AND taken_time IS NULL"; - snprintf(szQuery, sizeof(szQuery), - "UPDATE item_award SET taken_time=NOW(),item_id=%u WHERE id=%u AND taken_time IS NULL", - dwItemID, dwAwardID); - - CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_AWARD_TAKEN, 0, NULL); + CStmt stmt; + if (!stmt.Prepare(CDBManager::instance().GetDirectSQL(), query) || + !stmt.BindParam(MYSQL_TYPE_LONG, &dwItemID) || + !stmt.BindParam(MYSQL_TYPE_LONG, &dwAwardID) || + !stmt.Execute()) + { + sys_err("ITEM_AWARD: prepared taken update failed, falling back to legacy query path"); + FallbackItemAwardTakenQuery(dwAwardID, dwItemID); + } } std::map& ItemAwardManager::GetMapAward() @@ -126,4 +209,4 @@ std::map& ItemAwardManager::GetMapAward() std::map >& ItemAwardManager::GetMapkSetAwardByLogin() { return m_map_kSetAwardByLogin; -} \ No newline at end of file +}