// QuestRemove.cpp : ÄÜ¼Ö ÀÀ¿ë ÇÁ·Î±×·¥¿¡ ´ëÇÑ ÁøÀÔÁ¡À» Á¤ÀÇÇÕ´Ï´Ù. // /* ½ºÅ©¸³Æ® ±¸Á¶ Ŭ·¡½ºÅ¸ÀÔ °èÁ¤±¹ÀûŸÀÔ Ä¿¸Çµå Äù½ºÆ®ID Ŭ·¡½ºÅ¸ÀÔÀº ´ÙÀ½ÀÌ ÀÖ´Ù ALL : ¸ðµç Ŭ·¡½º HUMAN_1ST : ÈÞ¸Õ ±âº» (ÆÄÀÌÅÍ, ·Î±×, ¸ÞÀÌÁö, ¾îÄݶóÀÌÆ®) HUMAN_2ND : ÈÞ¸Õ »óÀ§ (µðÆæ´õ, ¿ö¸®¾î, ¾î½Ø½Å, ¾ÆÃ³, ¼Ò¼­·¯, ÀÎæÅÍ, ÇÁ¸®½ºÆ®, Ŭ·¹¸¯) AKHAN_1ST : ¾ÆÄ­ ±âº» (ÄĹèÅÏÆ®, ¿ÀÇǼ¼ÀÌÅÍ) AKHAN_2ND : ¾ÆÄ­ »óÀ§ (ÅÛÇ÷¯, ¾îÅÂÄ¿, °Å³Ê, ·é¿ÀÇÁ, ¶óÀÌÇÁ¿ÀÇÁ, ½¦µµ¿ì¿ÀÇÁ) FIGHTER : ÈÞ¸Õ Àü»ç ROGUE : ÈÞ¸Õ ·Î±× MAGE : ÈÞ¸Õ ¸ÞÀÌÁö ACOLYTE : ÈÞ¸Õ ¾îÄݶóÀÌÆ® DEFENDER : ÈÞ¸Õ µðÆæ´õ WARRIOR : ÈÞ¸Õ ¿ö¸®¾î ASSASSIN : ÈÞ¸Õ ¾î½Ø½Å ARCHER : ÈÞ¸Õ ¾ÆÃ³ SORCERER : ÈÞ¸Õ ¼Ò¼­·¯ ENCHANTER : ÈÞ¸Õ ÀÎæÅÍ PRIEST : ÈÞ¸Õ ÇÁ¸®½ºÆ® CLERIC : ÈÞ¸Õ Å¬·¹¸¯ COMBATANT : ¾ÆÄ­ ÄĹèÅÏÆ® OFFICIATOR : ¾ÆÄ­ ¿ÀÇǼ¼ÀÌÅÍ TEMPLAR : ¾ÆÄ­ ÅÛÇ÷¯ ATTACKER : ¾ÆÄ­ ¾îÅÂÄ¿ GUNNER : ¾ÆÄ­ °Å³Ê RUNEOFF : ¾ÆÄ­ ·é¿ÀÇÁ LIFEOFF : ¾ÆÄ­ ¶óÀÌÇÁ¿ÀÇÁ SHADOWOFF : ¾ÆÄ­ ½¦µµ¿ì¿ÀÇÁ °èÁ¤±¹ÀûŸÀÔÀº ´ÙÀ½ÀÌ ÀÖ´Ù ALL : ¸ðµç ±¹Àû KA : Ä«¸£Å×¶õÆ® ME : ¸Þ¸£Ä«µð¾Æ AP : ½ÅÀÇ ÇØÀû´Ü Ä¿¸Çµå´Â ´ÙÀ½ÀÌ ÀÖ´Ù REMOVE_ALL : ¼öÇàÁßÀÎ Äù½ºÆ®, ¼öÇà ¿Ï·á Äù½ºÆ® µÑ ´Ù REMOVE_CURRENT : ¼öÇàÁßÀÎ Äù½ºÆ® »èÁ¦ REMOVE_HISTORY : ¼öÇà¿Ï·á Äù½ºÆ® »èÁ¦ Äù½ºÆ®ID ´Â 10Áø¼ö ȤÀº 0x·Î ½ÃÀÛÇÏ´Â 16Áø¼öÀÌ´Ù. ÁÖ¼®Àº C½ºÅ¸ÀÏÀÇ ÁÖ¼® // ¸¸ Áö¿øÇÑ´Ù */ #pragma warning(disable:4800) #include "stdafx.h" #include #include #include #include #include #include #include #include #include #include #include #include // Quest Script Command enum QSCommand { NOTHING, REMOVE_ALL, REMOVE_CURRENT, REMOVE_HISTORY }; struct QuestData { std::bitset m_Class; // µ¿ÀÛÀ» ¼öÇàÇÒ Å¬·¡½º Creature::Nation m_Nation; // µ¿ÀÛÀ» ¼öÇàÇÒ °èÁ¤±¹Àû (MAX_NATION == ±¹Àû¿¡ °ü°è¾øÀÌ ¼öÇà) QSCommand m_Command; // ÇØ´ç Äù½ºÆ®¿¡ ¼öÇàÇÒ µ¿ÀÛ unsigned short m_QuestID; // Äù½ºÆ® ID std::set, boost::fast_pool_allocator > m_DstCharID; // ÀÛ¾÷ÇÒ Ä³¸¯ÅÍID }; struct QuestTarget { unsigned long CID; DBSTATUSENUM CIDStatus; BEGIN_ACCESSOR_MAP(QuestTarget, 1) BEGIN_ACCESSOR(0, true) COLUMN_ENTRY_STATUS(1, CID, CIDStatus) END_ACCESSOR() END_ACCESSOR_MAP() }; class CProcessQuest : public IDBCharQuestProcess { public: bool LoadScript(const char* szScriptName); HRESULT SetTargets(ATL::CSession& dbSession); private: typedef std::list QuestDataList; virtual ConvertResult operator()(RylDBCommand::CCharQuest& charQuest_InOut); QSCommand IsProcessQuest(unsigned long dwCID, unsigned short usQuestID); QuestDataList m_ProcessQuestData; }; void PrintUsage() { printf("usage : QuestRemove.exe DBAddress DBName DBAccount DBPassword QuestRemoveScriptName \n"); } int _tmain(int argc, _TCHAR* argv[]) { if(6 != argc) { PrintUsage(); return -1; } const char* szProcessQuestScript = argv[5]; CProcessQuest processQuest; if(FAILED(processQuest.LoadScript(szProcessQuestScript))) { printf("%s ½ºÅ©¸³Æ® ·Îµå ½ÇÆÐ", szProcessQuestScript); return -1; } CoInitialize(0); HRESULT hr = S_OK; ATL::CDataSource dataSource; ATL::CSession Session; #define LOG_CONVERT0(str) { ERRLOG0(g_Log, (str)); printf(str "\n"); } #define LOG_CONVERT1(str, arg1) { ERRLOG1(g_Log, (str), (arg1)); printf(str "\n", (arg1)); } #define LOG_CONVERT2(str, arg1, arg2) { ERRLOG2(g_Log, (str), (arg1), (arg2)); printf(str "\n", (arg1), (arg2)); } if(FAILED(hr = CRylDBProcess::ConnectDB(dataSource, argv[1], argv[2], argv[3], argv[4]))) { LOG_CONVERT1("Connect DB failed : hr:0x%08X", hr); } else if(FAILED(hr = Session.Open(dataSource))) { LOG_CONVERT1("Open session failed : hr:0x%08X", hr); } else if(FAILED(hr = processQuest.SetTargets(Session))) { LOG_CONVERT1("Target setting failed : hr:0x%08X", hr); } else { CRylDBProcess rylDBProcess(Session); CConsoleCounter consoleCounter(1000); if (!rylDBProcess.CharQuest(processQuest, consoleCounter)) { LOG_CONVERT1("CharQuest process failed : hr:0x%08X", hr); } } INFLOG0(g_Log, "Remove Complete"); Session.Close(); dataSource.Close(); CoUninitialize(); return 0; } bool CProcessQuest::LoadScript(const char* szScriptName) { bool bResult = true; FILE* lpFile = fopen(szScriptName, "rt"); if (0 != lpFile) { const int MAX_BUFFER = 1024; char szBuffer[MAX_BUFFER]; const char* szDelimiter = "\r\n\t: "; int nLine = 0; const char* szComment = "//"; size_t nCommentLen = strlen(szComment); const char* szHexHeader = "0X"; size_t nHexHeaderLen = strlen(szHexHeader); char* szStopPtr = 0; int nBase = 10; while(fgets(szBuffer, MAX_BUFFER - 1, lpFile)) { ++nLine; char* szClass = strtok(szBuffer, szDelimiter); char* szNation = strtok(0, szDelimiter); char* szCommand = strtok(0, szDelimiter); char* szQuestID = strtok(0, szDelimiter); if (0 != szClass && 0 != szNation && 0 != szCommand && 0 != szQuestID && 0 != strncmp(szClass, szComment, nCommentLen)) { strupr(szClass); strupr(szNation); strupr(szCommand); strupr(szQuestID); QuestData questData; questData.m_Class.reset(); // Ŭ·¡½º À̸§ ÆÄ½Ì if (0 == strcmp(szClass, "ALL")) { questData.m_Class.set(); } else if (0 == strcmp(szClass, "HUMAN_1ST")) { questData.m_Class.set(CClass::Fighter); questData.m_Class.set(CClass::Rogue); questData.m_Class.set(CClass::Mage); questData.m_Class.set(CClass::Acolyte); } else if (0 == strcmp(szClass, "HUMAN_2ND")) { questData.m_Class.set(CClass::Defender); questData.m_Class.set(CClass::Warrior); questData.m_Class.set(CClass::Assassin); questData.m_Class.set(CClass::Archer); questData.m_Class.set(CClass::Sorcerer); questData.m_Class.set(CClass::Enchanter); questData.m_Class.set(CClass::Priest); questData.m_Class.set(CClass::Cleric); } else if (0 == strcmp(szClass, "AKHAN_1ST")) { questData.m_Class.set(CClass::Combatant); questData.m_Class.set(CClass::Officiator); } else if (0 == strcmp(szClass, "AKHAN_2ND")) { questData.m_Class.set(CClass::Templar); questData.m_Class.set(CClass::Attacker); questData.m_Class.set(CClass::Gunner); questData.m_Class.set(CClass::RuneOff); questData.m_Class.set(CClass::LifeOff); questData.m_Class.set(CClass::ShadowOff); } else if (0 == strcmp(szClass, "FIGHTER")) { questData.m_Class.set(CClass::Fighter); } else if (0 == strcmp(szClass, "ROGUE")) { questData.m_Class.set(CClass::Rogue); } else if (0 == strcmp(szClass, "MAGE")) { questData.m_Class.set(CClass::Mage); } else if (0 == strcmp(szClass, "ACOLYTE")) { questData.m_Class.set(CClass::Acolyte); } else if (0 == strcmp(szClass, "DEFENDER")) { questData.m_Class.set(CClass::Defender); } else if (0 == strcmp(szClass, "WARRIOR")) { questData.m_Class.set(CClass::Warrior); } else if (0 == strcmp(szClass, "ASSASSIN")) { questData.m_Class.set(CClass::Assassin); } else if (0 == strcmp(szClass, "ARCHER")) { questData.m_Class.set(CClass::Archer); } else if (0 == strcmp(szClass, "SORCERER")) { questData.m_Class.set(CClass::Sorcerer); } else if (0 == strcmp(szClass, "ENCHANTER")) { questData.m_Class.set(CClass::Enchanter); } else if (0 == strcmp(szClass, "PRIEST")) { questData.m_Class.set(CClass::Priest); } else if (0 == strcmp(szClass, "CLERIC")) { questData.m_Class.set(CClass::Cleric); } else if (0 == strcmp(szClass, "COMBATANT")) { questData.m_Class.set(CClass::Combatant); } else if (0 == strcmp(szClass, "OFFICIATOR")) { questData.m_Class.set(CClass::Officiator); } else if (0 == strcmp(szClass, "TEMPLAR")) { questData.m_Class.set(CClass::Templar); } else if (0 == strcmp(szClass, "ATTACKER")) { questData.m_Class.set(CClass::Attacker); } else if (0 == strcmp(szClass, "GUNNER")) { questData.m_Class.set(CClass::Gunner); } else if (0 == strcmp(szClass, "RUNEOFF")) { questData.m_Class.set(CClass::RuneOff); } else if (0 == strcmp(szClass, "LIFEOFF")) { questData.m_Class.set(CClass::LifeOff); } else if (0 == strcmp(szClass, "SHADOWOFF")) { questData.m_Class.set(CClass::ShadowOff); } else { // ÆÄ½Ì ºÒ°¡. printf("Ŭ·¡½º°¡ À߸øµÈ ¶óÀÎÀÌ ÀÖ½À´Ï´Ù : %s:%d", szClass, nLine); bResult = false; break; } // ±¹Àû ÆÄ½Ì if (0 == strcmp(szNation, "ALL")) { questData.m_Nation = Creature::MAX_NATION;} else if (0 == strcmp(szNation, "KA")) { questData.m_Nation = Creature::KARTERANT; } else if (0 == strcmp(szNation, "ME")) { questData.m_Nation = Creature::MERKADIA; } else if (0 == strcmp(szNation, "AP")) { questData.m_Nation = Creature::ALMIGHTY_PIRATE; } else { // ÆÄ½Ì ºÒ°¡ LOG_CONVERT2("±¹ÀûÀÌ À߸øµÈ ¶óÀÎÀÌ ÀÖ½À´Ï´Ù : %s:%d", szNation, nLine); bResult = false; break; } // Ä¿¸Çµå ÆÄ½Ì if (0 == strcmp(szCommand, "REMOVE_ALL")) { questData.m_Command = REMOVE_ALL; } else if (0 == strcmp(szCommand, "REMOVE_CURRENT")) { questData.m_Command = REMOVE_CURRENT; } else if (0 == strcmp(szCommand, "REMOVE_HISTORY")) { questData.m_Command = REMOVE_HISTORY; } else { // ÆÄ½Ì ºÒ°¡ LOG_CONVERT2("Ä¿¸Çµå°¡ À߸øµÈ ¶óÀÎÀÌ ÀÖ½À´Ï´Ù : %s:%d", szCommand, nLine); bResult = false; break; } // Äù½ºÆ®ID ÆÄ½Ì nBase = (0 == strncmp(szQuestID, szHexHeader, nHexHeaderLen)) ? 16 : 10; questData.m_QuestID = static_cast(strtoul(szQuestID, &szStopPtr, nBase)); if (0 != questData.m_QuestID) { m_ProcessQuestData.push_back(questData); } else { LOG_CONVERT2("Äù½ºÆ®ID °¡ À߸øµÈ ¶óÀÎÀÌ ÀÖ½À´Ï´Ù : %s:%d", szQuestID, nLine); bResult = false; break; } } } fclose(lpFile); } else { LOG_CONVERT1("ÆÄÀÏ ¿­±â¿¡ ½ÇÆÐÇß½À´Ï´Ù : %s", szScriptName); bResult = false; } return bResult; } HRESULT CProcessQuest::SetTargets(ATL::CSession& dbSession) { /* Ŭ·¡½º°¡ ALLÀÎ °æ¿ì - WHERE¹®À» ³¯¸°´Ù ±¹°¡°¡ ALLÀÎ °æ¿ì - 2~6¶óÀÎÀ» ³¯¸°´Ù SELECT A.CID FROM CharInfo A JOIN (SELECT Char1 as CID FROM UserInfo WHERE Nation = 1 AND Char1 > 0 UNION ALL SELECT Char2 as CID FROM UserInfo WHERE Nation = 1 AND Char2 > 0 UNION ALL SELECT Char3 as CID FROM UserInfo WHERE Nation = 1 AND Char3 > 0 UNION ALL SELECT Char4 as CID FROM UserInfo WHERE Nation = 1 AND Char4 > 0 UNION ALL SELECT Char5 as CID FROM UserInfo WHERE Nation = 1 AND Char5 > 0 ) B ON A.CID = B.CID WHERE A.Class = 1 */ const int MAX_QUERY_BUFFER = 512; char szQueryBuffer[MAX_QUERY_BUFFER]; size_t nTotalTargetNum = 0; QuestDataList::iterator pos = m_ProcessQuestData.begin(); QuestDataList::iterator end = m_ProcessQuestData.end(); for (; pos != end; ++pos) { QuestData& questData = *pos; std::string targetQuery; targetQuery.reserve(MAX_QUERY_BUFFER * 2); targetQuery.assign("SELECT A.CID FROM CharInfo A "); if (questData.m_Nation != Creature::MAX_NATION) { _snprintf(szQueryBuffer, MAX_QUERY_BUFFER, "JOIN (SELECT Char1 as CID FROM UserInfo WHERE Nation = %d AND Char1 > 0 UNION ALL" "SELECT Char2 as CID FROM UserInfo WHERE Nation = %d AND Char2 > 0 UNION ALL" "SELECT Char3 as CID FROM UserInfo WHERE Nation = %d AND Char3 > 0 UNION ALL" "SELECT Char4 as CID FROM UserInfo WHERE Nation = %d AND Char4 > 0 UNION ALL" "SELECT Char5 as CID FROM UserInfo WHERE Nation = %d AND Char5 > 0 ) B ON A.CID = B.CID", questData.m_Nation, questData.m_Nation, questData.m_Nation, questData.m_Nation, questData.m_Nation); szQueryBuffer[MAX_QUERY_BUFFER - 1] = 0; targetQuery.append(szQueryBuffer); } if (questData.m_Class.any()) { targetQuery.append("WHERE A.Class in ("); for (int nCount = 0; nCount < CClass::MAX_CLASS; ++nCount) { if (questData.m_Class.test(nCount)) { targetQuery.append(itoa(nCount, szQueryBuffer, 10)); targetQuery.append(", "); } } size_t position = targetQuery.find_last_of(","); if (position != std::string::npos) { targetQuery[position] = ')'; } } CCommand, CBulkRowset, CMultipleResults> targetCIDs; HRESULT hr = S_OK; targetCIDs.SetRows(100000); if (FAILED(hr = targetCIDs.Open(dbSession, targetQuery.c_str()))) { LOG_CONVERT2("Ÿ°Ù ¾ò¾î¿À±â ½ÇÆÐ : hr:0x08X / targetQuery:%s", hr, targetQuery.c_str); return hr; } else { while(S_OK == (hr = targetCIDs.MoveNext())) { if (0 != targetCIDs.CID) { questData.m_DstCharID.insert(targetCIDs.CID); targetCIDs.CID = 0; } } RULLOG0(g_Log, targetQuery.c_str()); printf("QuestID:0x%04X - Ÿ°Ù ¾ò¾î¿À±â ¼º°ø(%u¸í)\n", questData.m_QuestID, questData.m_DstCharID.size()); nTotalTargetNum += questData.m_DstCharID.size(); } } printf("ÃÑ Å¸°Ù ¼ö(%u¸í)\n", nTotalTargetNum); return S_OK; } QSCommand CProcessQuest::IsProcessQuest(unsigned long dwCID, unsigned short usQuestID) { QuestDataList::iterator pos = m_ProcessQuestData.begin(); QuestDataList::iterator end = m_ProcessQuestData.end(); for (; pos != end; ++pos) { QuestData& questData = *pos; if (questData.m_QuestID == usQuestID && questData.m_DstCharID.end() != questData.m_DstCharID.find(dwCID)) { // ÇØ´ç Äù½ºÆ®/´ë»óÀÚ°¡ Á¸ÀçÇÑ´Ù. return questData.m_Command; } } return NOTHING; } ConvertResult CProcessQuest::operator()(RylDBCommand::CCharQuest& charQuest_InOut) { unsigned long dwCID = charQuest_InOut.GetCID(); unsigned long dwTotalChangedCount = 0; const QUEST& quest_In = charQuest_InOut.GetQuest(); const HISTORY history_In = charQuest_InOut.GetHistory(); if (0 < quest_In.dwSize) { unsigned long dwChangedCount = 0; QUEST quest_Out; memset(&quest_Out, 0, sizeof(QUEST)); const PktQuestDB::ExecutingQuest* lpExecutingQuestPos = reinterpret_cast(quest_In.Data); const PktQuestDB::ExecutingQuest* lpExecutingQuestEnd = reinterpret_cast(quest_In.Data + quest_In.dwSize); PktQuestDB::ExecutingQuest* lpDst = reinterpret_cast(quest_Out.Data); for(; lpExecutingQuestPos < lpExecutingQuestEnd; ++lpExecutingQuestPos) { QSCommand command = IsProcessQuest(dwCID, lpExecutingQuestPos->m_wQuestID); if (REMOVE_ALL == command || REMOVE_CURRENT == command) { ++dwChangedCount; INFLOG2(g_Log, "CID:%10u / QuestID:0x%04X / ÁøÇàÁßÀÎ Äù½ºÆ®¸¦ Á¦°ÅÇß½À´Ï´Ù", dwCID, lpExecutingQuestPos->m_wQuestID); } else { // ¸ñ·Ï¿¡ ¾ø´Â °æ¿ì¿¡¸¸ º¹»çÇÑ´Ù. *lpDst = *lpExecutingQuestPos; ++lpDst; } } if (0 < dwChangedCount) { quest_Out.dwSize = static_cast( reinterpret_cast(lpDst) - quest_Out.Data); charQuest_InOut.SetQuest(quest_Out); dwTotalChangedCount += dwChangedCount; } } if (0 < history_In.dwSize) { unsigned long dwChangedCount = 0; HISTORY history_Out; memset(&history_Out, 0, sizeof(HISTORY)); const unsigned short* lpHistoryPos = reinterpret_cast(history_In.Data); const unsigned short* lpHistoryEnd = reinterpret_cast(history_In.Data + history_In.dwSize); unsigned short* lpDst = reinterpret_cast(history_Out.Data); for(; lpHistoryPos < lpHistoryEnd; ++lpHistoryPos) { QSCommand command = IsProcessQuest(dwCID, *lpHistoryPos); if (REMOVE_ALL == command || REMOVE_HISTORY == command) { ++dwChangedCount; INFLOG2(g_Log, "CID:%10u / QuestID:0x%04X / ¼öÇà ¿Ï·áµÈ Äù½ºÆ®¸¦ Á¦°ÅÇß½À´Ï´Ù", dwCID, *lpHistoryPos); } else { // ¸ñ·Ï¿¡ ¾ø´Â °æ¿ì¿¡¸¸ º¹»çÇÑ´Ù. *lpDst = *lpHistoryPos; ++lpDst; } } if (0 < dwChangedCount) { history_Out.dwSize = static_cast( reinterpret_cast(lpDst) - history_Out.Data); charQuest_InOut.SetHistory(history_Out); dwTotalChangedCount += dwChangedCount; } } return (0 < dwTotalChangedCount) ? CONVERT_SUCCEEDED : CONVERT_DO_NOT_WRITE; }