#include "stdafx.h" #include "../shared/database/OdbcConnection.h" #include "KnightsManager.h" #include "KingSystem.h" #include "DBAgent.h" #include "../shared/DateTime.h" CDBAgent g_DBAgent; using std::string; using std::unique_ptr; CDBAgent::CDBAgent() { m_GameDB = new OdbcConnection(); m_AccountDB = new OdbcConnection(); } CDBAgent::~CDBAgent() { delete m_GameDB; delete m_AccountDB; } bool CDBAgent::Startup(bool bMarsEnabled, tstring & strAccountDSN, tstring & strAccountUID, tstring & strAccountPWD, tstring & strGameDSN, tstring & strGameUID, tstring & strGamePWD) { if (!Connect(bMarsEnabled, strAccountDSN, strAccountUID, strAccountPWD, strGameDSN, strGameUID, strGamePWD)) { // we should probably be a little more specific (i.e. *which* database server) printf(_T("ERROR: Failed to connect to the database server.")); return false; } DatabaseThread::Startup(); return true; } bool CDBAgent::Connect(bool bMarsEnabled, tstring & strAccountDSN, tstring & strAccountUID, tstring & strAccountPWD, tstring & strGameDSN, tstring & strGameUID, tstring & strGamePWD) { if (!m_AccountDB->Connect(strAccountDSN, strAccountUID, strAccountPWD, bMarsEnabled)) { ReportSQLError(m_AccountDB->GetError()); return false; } if (!m_GameDB->Connect(strGameDSN, strGameUID, strGamePWD, bMarsEnabled)) { ReportSQLError(m_GameDB->GetError()); return false; } return true; } void CDBAgent::ReportSQLError(OdbcError *pError) { if (pError == nullptr) return; DateTime time; // This is *very* temporary. // I have to write an example code to this function as // save the query record to a map and try to get clear // this map repeatly. // About some seconds.... // If query effects warehouse or userdata or tb_user // Disconnect the user that effected about this error // And add him to waiting list, // Get block his character while his query upload.. string errorMessage = string_format(_T("[ ODBC Error - %d.%d.%d %d:%d:%d ] ] Source: %s Error: %s Description: %s\n"), time.GetDay(),time.GetMonth(),time.GetYear(),time.GetHour(),time.GetMinute(),time.GetSecond(), pError->Source.c_str(), pError->ExtendedErrorMessage.c_str(), pError->ErrorMessage.c_str()); Guard lock(m_lock); FILE *fp = fopen("./Logs/GameServer.log", "a"); if (fp != nullptr) { fwrite(errorMessage.c_str(), errorMessage.length(), 1, fp); fclose(fp); } TRACE("Database error: %s\n", errorMessage.c_str()); delete pError; } int8 CDBAgent::AccountLogin(string & strAccountID, string & strPasswd) { int8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strPasswd.c_str(), strPasswd.length()); if (!dbCommand->Execute(_T("{? = CALL GAME_LOGIN(?, ?)}"))) ReportSQLError(m_GameDB->GetError()); return bRet; } uint8 CDBAgent::NationSelect(string & strAccountID, uint8 bNation) { uint8 bRet = 0; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL NATION_SELECT(?, %d)}"), bNation))) ReportSQLError(m_GameDB->GetError()); return (bRet > 0 ? bNation : 0); } bool CDBAgent::GetAllCharID(string & strAccountID, string & strCharID1, string & strCharID2, string & strCharID3, string & strCharID4) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(_T("SELECT strCharID1, strCharID2, strCharID3, strCharID4 FROM ACCOUNT_CHAR WHERE strAccountID = ?"))) { ReportSQLError(m_GameDB->GetError()); return false; } if (!dbCommand->hasData()) return false; dbCommand->FetchString(1, strCharID1); dbCommand->FetchString(2, strCharID2); dbCommand->FetchString(3, strCharID3); dbCommand->FetchString(4, strCharID4); return true; } bool CDBAgent::SetAllCharID(string & strAccountID, string & strCharID1, string & strCharID2, string & strCharID3, string & strCharID4) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; string ID1, ID2,ID3, ID4; if (strCharID1 == "") ID1 = ""; else ID1 = strCharID1; if (strCharID2 == "") ID2 = ""; else ID2 = strCharID2; if (strCharID3 == "") ID3 = ""; else ID3 = strCharID3; if (strCharID4 == "") ID4 = ""; else ID4 = strCharID4; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, ID1.c_str(), ID1.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, ID2.c_str(), ID2.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, ID3.c_str(), ID3.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, ID4.c_str(), ID4.length()); if (!dbCommand->Execute(_T("{CALL UPDATE_ALL_CHAR_ID(" "?, ?, ?, ?, ?)}"))) { ReportSQLError(m_GameDB->GetError()); return false; } return true; } void CDBAgent::LoadCharInfo(string & strCharID, ByteBuffer & result) { uint32 nHair = 0; uint16 sClass = 0; uint8 bRace = 0, bLevel = 0, bFace = 0, bZone = 0; char strItem[INVENTORY_TOTAL * 8]; char strItemTime[INVENTORY_TOTAL * 8]; ByteBuffer itemData; // ensure it's all 0'd out initially. memset(strItem, 0x00, sizeof(strItem)); memset(strItemTime, 0x00, sizeof(strItemTime)); if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT Race, Class, HairRGB, [Level], Face, Zone, strItem, strItemTime FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchByte(1, bRace); dbCommand->FetchUInt16(2, sClass); dbCommand->FetchUInt32(3, nHair); dbCommand->FetchByte(4, bLevel); dbCommand->FetchByte(5, bFace); dbCommand->FetchByte(6, bZone); dbCommand->FetchBinary(7, strItem, sizeof(strItem)); dbCommand->FetchBinary(8, strItemTime, sizeof(strItemTime)); } } itemData.append(strItem, sizeof(strItem)); result << strCharID << bRace << sClass << bLevel << bFace << nHair << bZone; for (int i = 0; i < SLOT_MAX; i++) { uint32 nItemID; uint16 sDurability, sCount; itemData >> nItemID >> sDurability >> sCount; if (i == HEAD || i == BREAST || i == SHOULDER || i == LEG || i == GLOVE || i == FOOT || i == RIGHTHAND || i == LEFTHAND) result << nItemID << sDurability; } } void CDBAgent::LoadCharSeal(string & strCharID, ByteBuffer & result) { uint32 nHair = 0, Gold = 0; uint16 sClass = 0; uint8 bRace = 0, bLevel = 0, bFace = 0, bZone = 0, Sta = 0, Cha = 0, Intel = 0, Dex = 0, Strong = 0, Points = 0; uint8 strSkill[10]; char strItem[INVENTORY_TOTAL * 8]; char strItemTime[INVENTORY_TOTAL * 8]; char strSerial[INVENTORY_TOTAL * 8]; ByteBuffer itemData; ByteBuffer serialBuffer; ByteBuffer itemTimeBuffer; // ensure it's all 0'd out initially. memset(strItem, 0x00, sizeof(strItem)); memset(strItemTime, 0x00, sizeof(strItemTime)); memset(strSerial, 0x00, sizeof(strSerial)); memset(strSkill, 0, sizeof(strSkill)); if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT Race, Class, [Level], strItem, strItemTime, strSerial, Strong, Sta, Dex, Cha, Intel, Gold, Points, strSkill FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchByte(1, bRace); dbCommand->FetchUInt16(2, sClass); dbCommand->FetchByte(3, bLevel); dbCommand->FetchBinary(4, strItem, sizeof(strItem)); dbCommand->FetchBinary(5, strItemTime, sizeof(strItemTime)); dbCommand->FetchBinary(6, strSerial, sizeof(strSerial)); dbCommand->FetchByte(7, Strong); dbCommand->FetchByte(8, Sta); dbCommand->FetchByte(9, Dex); dbCommand->FetchByte(10, Cha); dbCommand->FetchByte(11, Intel); dbCommand->FetchUInt32(12, Gold); dbCommand->FetchByte(13, Points); dbCommand->FetchString(14, (char *)strSkill, sizeof(strSkill)); } } itemData.append(strItem, sizeof(strItem)); serialBuffer.append(strSerial, sizeof(strSerial)); itemTimeBuffer.append(strItemTime, sizeof(strItemTime)); result.SByte(); result << strCharID << uint8(sClass) << uint16(bRace) << uint8(0) << bLevel << Strong << Sta << Dex << Intel << Cha << Gold << Points << uint8(0) << uint8(0) << uint8(0) << uint8(0) << strSkill[SkillPointCat1] << strSkill[SkillPointCat2] << strSkill[SkillPointCat3] << strSkill[SkillPointMaster]; UserItemSealMap m_sealedItemMap; LoadItemSealData(strCharID, strCharID, m_sealedItemMap); for (int i = 0; i < SLOT_MAX + HAVE_MAX; i++) { uint32 nItemID, nItemTime; uint16 sDurability, sCount; uint64 nSerialNum; uint8 bFlag; itemData >> nItemID >> sDurability >> sCount; serialBuffer >> nSerialNum; itemTimeBuffer >> nItemTime; UserItemSealMap::iterator sealitr = m_sealedItemMap.find(nSerialNum); if (sealitr != m_sealedItemMap.end()) { if (sealitr->second->bSealType == 1) bFlag = ITEM_FLAG_SEALED; else if (sealitr->second->bSealType == 3) bFlag = ITEM_FLAG_BOUND; } if (g_pMain->IsDuplicateItem(nItemID,nSerialNum)) bFlag = ITEM_FLAG_DUPLICATE; if(sCount < 1) result << uint32(0) << uint16(0) << uint16(0) << uint8(0); else result << nItemID << sDurability << sCount << bFlag; // item type flag (e.g. rented) } result << uint8(0) << uint8(0) << uint8(0) << uint8(0) << uint8(0)/* Unique Level */ << uint8(0) /* Unique STR */; } uint8 CDBAgent::LoadCharRace(std::string & strCharID) { uint8 sClass = 0; if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT Race FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchByte(1, sClass); } } return sClass; } uint64 CDBAgent::LoadCharExp(std::string & strCharID) { uint64 sClass = 0; if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT [exp] FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchUInt64(1, sClass); } } return sClass; } uint8 CDBAgent::LoadYanCharHAS(string & strAccountID, std::string & strCharID) { uint8 sClass = 0; if (!strAccountID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT COUNT(*) FROM ACCOUNT_CHAR WHERE strAccountID = ? AND (strCharID1 = ? or strCharID2 = ? or strCharID3 = ? or strCharID4 = ?)"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchByte(1, sClass); } } return sClass; } uint64 CDBAgent::GetSerialByID(uint32 ID) { uint64 sClass = 0; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; if (!dbCommand->Execute(string_format(_T("SELECT strSerial FROM USERDATA_CYPHER WHERE id = %d"),ID))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchUInt64(1, sClass); } return sClass; } uint8 CDBAgent::LoadCharLevel(string & strCharID) { uint8 sClass = 0; if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT [Level] FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchByte(1, sClass); } } return sClass; } uint16 CDBAgent::LoadCharKnights(string & strCharID) { uint16 sClass = 0; if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT Knights FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchUInt16(1, sClass); } } return sClass; } uint8 CDBAgent::LoadCharNation(string & strCharID) { uint8 sClass = 0; if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT [Nation] FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchByte(1, sClass); } } return sClass; } uint16 CDBAgent::LoadAccountNTS(string & strCharID) { uint16 sClass = 0; if (!strCharID.empty()) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("SELECT Class FROM USERDATA WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchUInt16(1, sClass); } } return sClass; } int8 CDBAgent::CreateNewChar(string & strAccountID, int index, string & strCharID, uint8 bRace, uint16 sClass, uint32 nHair, uint8 bFace, uint8 bStr, uint8 bSta, uint8 bDex, uint8 bInt, uint8 bCha) { int8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL CREATE_NEW_CHAR(?, %d, ?, %d, %d, %d, %d, %d, %d, %d, %d, %d)}"), index, bRace, sClass, nHair, bFace, bStr, bSta, bDex, bInt, bCha))) ReportSQLError(m_GameDB->GetError()); return bRet; } int8 CDBAgent::ChangeHair(std::string & strAccountID, std::string & strCharID, uint8 bOpcode, uint8 bFace, uint32 nHair) { int8 bRet = 1; // failed unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL CHANGE_HAIR(?, ?, %d, %d, %d)}"), bOpcode, bFace, nHair))) ReportSQLError(m_GameDB->GetError()); return bRet; } void CDBAgent::LoadRentalData(string & strAccountID, string & strCharID, UserRentalMap & rentalData) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(_T("{CALL LOAD_RENTAL_DATA(?)}"))) { ReportSQLError(m_GameDB->GetError()); return; } if (!dbCommand->hasData()) return; do { _USER_RENTAL_ITEM *pItem = new _USER_RENTAL_ITEM(); _RENTAL_ITEM *pRentalItem = nullptr; dbCommand->FetchString(1, pItem->strUserID); if (STRCASECMP(pItem->strUserID.c_str(), strCharID.c_str()) != 0) { delete pItem; continue; } dbCommand->FetchByte(2, pItem->byRentalType); dbCommand->FetchByte(3, pItem->byRegType); dbCommand->FetchUInt32(4, pItem->nRentalIndex); dbCommand->FetchUInt32(5, pItem->nItemID); dbCommand->FetchUInt16(6, pItem->sDurability); dbCommand->FetchUInt64(7, pItem->nSerialNum); dbCommand->FetchUInt32(8, pItem->nRentalMoney); dbCommand->FetchUInt16(9, pItem->sRentalTime); dbCommand->FetchInt16(10, pItem->sMinutesRemaining); dbCommand->FetchString(11, pItem->szTimeRental, sizeof(pItem->szTimeRental)); pRentalItem = g_pMain->m_RentalItemArray.GetData(pItem->nRentalIndex); if (pRentalItem == nullptr || rentalData.find(pItem->nSerialNum) != rentalData.end()) delete pItem; else rentalData.insert(std::make_pair(pItem->nSerialNum, pItem)); } while (dbCommand->MoveNext()); } void CDBAgent::LoadItemSealData(string & strAccountID, string & strCharID, UserItemSealMap & itemSealData) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(_T("SELECT nItemSerial, nItemID, bSealType FROM SEALED_ITEMS WHERE strAccountID = ?"))) { ReportSQLError(m_GameDB->GetError()); return; } if (!dbCommand->hasData()) return; do { _USER_SEAL_ITEM *pItem = new _USER_SEAL_ITEM; dbCommand->FetchUInt64(1, pItem->nSerialNum); dbCommand->FetchUInt32(2, pItem->nItemID); dbCommand->FetchByte(3, pItem->bSealType); if (pItem == nullptr) delete pItem; else itemSealData.insert(std::make_pair(pItem->nSerialNum, pItem)); } while (dbCommand->MoveNext()); } uint8 CDBAgent::LoadPetData(uint64 PetSerial, CPet *pPet) { uint8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); if (!dbCommand->Execute(string_format(_T("{? = CALL LOAD_PET_DATA(" I64FMTD ", ?)}"), PetSerial))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return false; //PET_NAME, PET_EXP, PET_LEVEL, PET_STOMACH, PET_ITEMID, PET_CLASS int i = 1; pPet->m_bIsKaul = true; dbCommand->FetchString(i++, pPet->m_strPetID); dbCommand->FetchUInt64(i++, pPet->m_iExp); dbCommand->FetchByte(i++, pPet->m_bLevel); dbCommand->FetchUInt16(i++, pPet->m_sSatisfaction); dbCommand->FetchUInt64(i++, pPet->m_Serial); dbCommand->FetchByte(i++, pPet->m_sClass); return bRet; } uint8 CDBAgent::UpdatePetData(uint64 PetSerial, CPet *pPet) { uint8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; uint8 Slot = 0; uint32 FinishTime = 0, ItemNum = 0; for (int i=0; i < PET_MAX; i++) { if (pPet->m_sItemArray[i].nNum > 0) { Slot = i; FinishTime = pPet->m_sItemArray[i].nExpirationTime; ItemNum = pPet->m_sItemArray[i].nNum; break; } } dbCommand->AddParameter(SQL_PARAM_INPUT, pPet->m_strPetID.c_str(), pPet->m_strPetID.length()); if (!dbCommand->Execute(string_format(_T("UPDATE PET_DATA SET PET_SLOT=%d, PET_FINISHTIME=%d,PET_ITEMID=%d,PET_NAME=?,PET_EXP=" I64FMTD ",PET_LEVEL=%d,PET_STOMACH=%d,PET_CLASS=%d WHERE PET_SERIAL = " I64FMTD ""),Slot,FinishTime,ItemNum,pPet->m_iExp,pPet->m_bLevel,pPet->m_sSatisfaction,pPet->m_sClass,PetSerial))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return false; return 1; } uint8 CDBAgent::InsertPetData(uint64 PetSerial, CPet *pPet) { uint8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, pPet->m_strPetID.c_str(), pPet->m_strPetID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL INSERT_PET_DATA(" I64FMTD ", ?, " I64FMTD ", %d, %d, %d, %d)}"), PetSerial, pPet->m_iExp, pPet->m_bLevel, pPet->m_sSatisfaction, pPet->m_sClass, pPet->SpecialPetID))) ReportSQLError(m_GameDB->GetError()); return bRet; } uint8 CDBAgent::InsertCypherRingData(uint64 Serial, _CYPHERRING_DATA *pData, std::string strPasswd) { uint8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, pData->UserName.c_str(), pData->UserName.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strPasswd.c_str(), strPasswd.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL INSERT_CYPHER_RING_DATA(" I64FMTD ", ?, " I64FMTD ", %d, %d, %d, %d, ?)}"), Serial, pData->iExp, pData->bLevel, pData->bRace, pData->sClass, pData->ID))) ReportSQLError(m_GameDB->GetError()); return bRet; } uint8 CDBAgent::InsertCypherRingChar(std::string strAccountID, uint64 Serial) { uint8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL INSERT_CYPHER_RING_CHAR( ?, " I64FMTD ")}"), Serial))) ReportSQLError(m_GameDB->GetError()); return bRet; } bool CDBAgent::LoadUserData(string & strAccountID, string & strCharID, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; if (pUser == nullptr || pUser->m_bLogout || !pUser->GetName().empty() || strCharID.length() > MAX_ID_SIZE) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("{CALL LOAD_USER_DATA(?, ?)}"))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return false; char strItem[INVENTORY_TOTAL * 8] = {0}, strSerial[INVENTORY_TOTAL * 8] = {0}, strVIPItem[MAX_SLOT_VIP_STORAGE * 8] = {0}, strVIPSerial[MAX_SLOT_VIP_STORAGE * 8] = {0}, strVIPItemTime[MAX_SLOT_VIP_STORAGE * 8], strQuest[QUEST_ARRAY_SIZE],strQuestUse[100 * 6] = {0}, strRebStats[5] = {0},strAchieveQuest[ACHIEVE_QUEST_ARRAY_SIZE], strItemTime[INVENTORY_TOTAL * 8];; uint16 strAchieveQuestKill[ACHIEVE_QUEST_ARRAY_SIZE * 2]; uint16 sQuestCount = 0; uint16 sQuestUseCount = 0; uint16 sAchieveQuestCount = 0; int field = 1; dbCommand->FetchByte(field++, pUser->m_bNation); dbCommand->FetchByte(field++, pUser->m_bRace); dbCommand->FetchUInt16(field++, pUser->m_sClass); dbCommand->FetchUInt32(field++, pUser->m_nHair); dbCommand->FetchByte(field++, pUser->m_bRank); dbCommand->FetchByte(field++, pUser->m_bTitle); dbCommand->FetchByte(field++, pUser->m_bLevel); dbCommand->FetchByte(field++, pUser->m_reblvl); dbCommand->FetchInt64(field++, pUser->m_iExp); dbCommand->FetchUInt32(field++, pUser->m_iLoyalty); dbCommand->FetchByte(field++, pUser->m_bFace); dbCommand->FetchByte(field++, pUser->m_bCity); dbCommand->FetchInt16(field++, pUser->m_bKnights); dbCommand->FetchByte(field++, pUser->m_bFame); dbCommand->FetchInt16(field++, pUser->m_sHp); dbCommand->FetchInt16(field++, pUser->m_sMp); dbCommand->FetchInt16(field++, pUser->m_sSp); dbCommand->FetchByte(field++, pUser->m_bStats[STAT_STR]); dbCommand->FetchByte(field++, pUser->m_bStats[STAT_STA]); dbCommand->FetchByte(field++, pUser->m_bStats[STAT_DEX]); dbCommand->FetchByte(field++, pUser->m_bStats[STAT_INT]); dbCommand->FetchByte(field++, pUser->m_bStats[STAT_CHA]); dbCommand->FetchByte(field++, pUser->m_bAuthority); dbCommand->FetchInt16(field++, pUser->m_sPoints); dbCommand->FetchUInt32(field++, pUser->m_iGold); dbCommand->FetchByte(field++, pUser->m_bZone); dbCommand->FetchInt16(field++, pUser->m_sBind); pUser->m_curx = (float)(dbCommand->FetchInt32(field++) / 100.0f); pUser->m_curz = (float)(dbCommand->FetchInt32(field++) / 100.0f); pUser->m_cury = (float)(dbCommand->FetchInt32(field++) / 100.0f); pUser->m_oldx = pUser->m_curx; pUser->m_oldy = pUser->m_cury; pUser->m_oldz = pUser->m_curz; dbCommand->FetchUInt32(field++, pUser->m_dwTime); dbCommand->FetchString(field++, (char *)pUser->m_bstrSkill, sizeof(pUser->m_bstrSkill)); dbCommand->FetchBinary(field++, strItem, sizeof(strItem)); dbCommand->FetchBinary(field++, strSerial, sizeof(strSerial)); dbCommand->FetchBinary(field++, strVIPItem, sizeof(strVIPItem)); dbCommand->FetchBinary(field++, strVIPSerial, sizeof(strVIPSerial)); dbCommand->FetchUInt16(field++, sQuestCount); dbCommand->FetchUInt16(field++, sQuestUseCount); dbCommand->FetchUInt16(field++, sAchieveQuestCount); dbCommand->FetchBinary(field++, strQuest, sizeof(strQuest)); dbCommand->FetchBinary(field++, strQuestUse, sizeof(strQuestUse)); dbCommand->FetchBinary(field++, strAchieveQuest, sizeof(strAchieveQuest)); dbCommand->FetchUInt32(field++, pUser->m_iMannerPoint); dbCommand->FetchUInt32(field++, pUser->m_iLoyaltyMonthly); dbCommand->FetchBinary(field++, strItemTime, sizeof(strItemTime)); dbCommand->FetchBinary(field++, strVIPItemTime, sizeof(strVIPItemTime)); dbCommand->FetchString(field++, pUser->m_strMemo); dbCommand->FetchUInt16(field++, pUser->m_GenieTime); dbCommand->FetchString(field++, (char *)pUser->m_GenieOptions, sizeof(pUser->m_GenieOptions)); dbCommand->FetchString(field++, (char *)strAchieveQuestKill, sizeof(strAchieveQuestKill)); dbCommand->FetchBinary(field++, strRebStats, sizeof(strRebStats)); dbCommand->FetchUInt16(field++, pUser->m_sAchieveSkillTitle); dbCommand->FetchUInt16(field++, pUser->m_sAchieveCoverTitle); dbCommand->FetchString(field++, pUser->VIPStorePassword); dbCommand->FetchUInt32(field++, pUser->nVIPExpirationTime); dbCommand->FetchUInt32(field++, pUser->m_iMonsterDefeatedCount); dbCommand->FetchUInt32(field++, pUser->m_iUserDefeatedCount); dbCommand->FetchUInt32(field++, pUser->m_iUserDeathCount); dbCommand->FetchUInt32(field++, pUser->m_iAchievementPoint); dbCommand->FetchUInt32(field++, pUser->m_LastOnline); pUser->m_strUserID = strCharID; pUser->m_lastSaveTime = UNIXTIME; pUser->m_lastBonusTime = UNIXTIME; pUser->m_TimeOnline = UNIXTIME; ByteBuffer QuestUseBufer; QuestUseBufer.append(strQuestUse, sizeof(strQuestUse)); // Convert the old quest storage format to the new one. pUser->m_questMap.clear(); if (sQuestCount > QUEST_LIMIT) sQuestCount = QUEST_LIMIT; for (int i = 0, index = 0; i < sQuestCount; i++, index += 3) { uint16 sQuestID = *(uint16 *)(strQuest + index); uint8 bQuestState = *(uint8 *)(strQuest + index + 2); pUser->m_questMap.insert(std::make_pair(sQuestID, bQuestState)); } // Start the Seed quest if it doesn't already exist. if (pUser->V3_CheckExistEvent(STARTER_SEED_QUEST, 0)) pUser->V3_QuestEvent(STARTER_SEED_QUEST, 1); /*if (pUser->V3_CheckExistEvent(PET_QUEST, 0)) pUser->V3_QuestEvent(PET_QUEST, 1);*/ pUser->m_QuestMonMap.clear(); for(int i = 0; i < sQuestUseCount; i++) { _QUEST_DATA * pData = new _QUEST_DATA; uint16 nQuestID; QuestUseBufer >> nQuestID; if (nQuestID == 0) continue; QuestUseBufer >> pData->dCKills[0]; QuestUseBufer >> pData->dCKills[1]; QuestUseBufer >> pData->dCKills[2]; QuestUseBufer >> pData->dCKills[3]; pUser->m_QuestMonMap.insert(std::make_pair(nQuestID, pData)); } pUser->m_AchievequestMap.clear(); if (sAchieveQuestCount > ACHIEVE_QUEST_LIMIT) sAchieveQuestCount = ACHIEVE_QUEST_LIMIT; for (int i = 0, index = 0; i < sAchieveQuestCount; i++, index += 3) { uint16 sAchieveQuestID = *(uint16 *)(strAchieveQuest + index); uint8 bQuestState = *(uint8 *)(strAchieveQuest + index + 2); pUser->m_AchievequestMap.insert(std::make_pair(sAchieveQuestID, bQuestState)); _ACHIEVE_MAIN * pMainData = g_pMain->GetAchieveMainPointer(sAchieveQuestID); if(pMainData == nullptr) continue; if (bQuestState == 2) { switch(pMainData->TabIndex) { case 0: pUser->AchieveNormalCount++; // Normal Count break; case 1: pUser->AchieveQuestCount++; // Quest Count break; case 2: pUser->AchieveWarCount++; // War Count break; case 3: pUser->AchieveAdventureCount++; // Adventure Count break; case 4: pUser->AchieveChallengeCount++;// Challenge Count break; default: break; } } if(bQuestState == 2) { if(pUser->AchieveLast3 == 0 && pUser->AchieveLast2 == 0 && pUser->AchieveLast1 == 0) pUser->AchieveLast1 = sAchieveQuestID; else { pUser->AchieveLast3 = pUser->AchieveLast2; pUser->AchieveLast2 = pUser->AchieveLast1; pUser->AchieveLast1 = sAchieveQuestID; } } } for (int i = 0, index = 0; i < sAchieveQuestCount; i++, index += 6) { uint16 sQuestID2 = strAchieveQuestKill[index]; uint16 bCount = strAchieveQuestKill[index + 2]; uint16 bCount1 = strAchieveQuestKill[index + 4]; if (sQuestID2 > 0){ _ACHIEVE_QUEST * pAchieveQuest = new _ACHIEVE_QUEST; pAchieveQuest->ID = sQuestID2; pAchieveQuest->KillCount[0] = bCount; pAchieveQuest->KillCount[1] = bCount1; if(!pUser->m_bAchieveKillCount.PutData(pAchieveQuest->ID,pAchieveQuest)) delete pAchieveQuest; } } ByteBuffer itemBuffer, serialBuffer, itemTimeBuffer,RebStatsBuffer; ByteBuffer VIPitemBuffer, VIPserialBuffer, VIPitemTimeBuffer; itemBuffer.append(strItem, sizeof(strItem)); serialBuffer.append(strSerial, sizeof(strSerial)); itemTimeBuffer.append(strItemTime, sizeof(strItemTime)); VIPitemBuffer.append(strVIPItem, sizeof(strVIPItem)); VIPserialBuffer.append(strVIPSerial, sizeof(strVIPSerial)); VIPitemTimeBuffer.append(strVIPItemTime, sizeof(strVIPItemTime)); RebStatsBuffer.append(strRebStats, sizeof(strRebStats)); QuestUseBufer.append(strQuestUse, sizeof(strQuestUse)); memset(pUser->m_sItemArray, 0x00, sizeof(pUser->m_sItemArray)); memset(pUser->m_sVIPItemArray, 0x00, sizeof(pUser->m_sVIPItemArray)); UserRentalMap rentalData; // Until this statement is cleaned up, // no other statements can be processed. delete dbCommand.release(); LoadRentalData(strAccountID, strCharID, rentalData); LoadItemSealData(strAccountID, strCharID, pUser->m_sealedItemMap); //RebStats Read Start uint8 RebStr, RebSta, RebDex, RebInt, RebCha; RebStatsBuffer >> RebStr >> RebSta >> RebDex >> RebInt >> RebCha; pUser->SetRebStatBuff(STAT_STR, RebStr); pUser->SetRebStatBuff(STAT_STA, RebSta); pUser->SetRebStatBuff(STAT_DEX, RebDex); pUser->SetRebStatBuff(STAT_INT, RebInt); pUser->SetRebStatBuff(STAT_CHA, RebCha); //RebStats Read Ends for (int i = 0; i < INVENTORY_TOTAL; i++) { uint64 nSerialNum; uint32 nItemID; int16 sDurability, sCount; uint32 nItemTime; itemBuffer >> nItemID >> sDurability >> sCount; serialBuffer >> nSerialNum; itemTimeBuffer >> nItemTime; _ITEM_TABLE *pTable = g_pMain->GetItemPtr(nItemID); if (pTable == nullptr || sCount <= 0) continue; if (!pTable->m_bCountable && sCount > 1) sCount = 1; else if (sCount > ITEMCOUNT_MAX) sCount = ITEMCOUNT_MAX; if (nSerialNum == 0) nSerialNum = g_pMain->GenerateItemSerial(); _ITEM_DATA *pItem = pUser->GetItem(i); pItem->nNum = nItemID; pItem->sDuration = pTable->isAccessory() ? pTable->m_sDuration : sDurability; pItem->sCount = sCount; pItem->nSerialNum = nSerialNum; pItem->nExpirationTime = nItemTime; // If the serial was found in the rental data, mark as rented. UserRentalMap::iterator itr = rentalData.find(nSerialNum); if (itr != rentalData.end()) { pItem->bFlag = ITEM_FLAG_RENTED; pItem->sRemainingRentalTime = itr->second->sMinutesRemaining; } UserItemSealMap::iterator sealitr = pUser->m_sealedItemMap.find(nSerialNum); if (sealitr != pUser->m_sealedItemMap.end()) { if (sealitr->second->bSealType == 1) pItem->bFlag = ITEM_FLAG_SEALED; else if (sealitr->second->bSealType == 3) pItem->bFlag = ITEM_FLAG_BOUND; else if (sealitr->second->bSealType == 4) pItem->bFlag = ITEM_FLAG_NOT_BOUND; } g_pMain->AddUserItem(nItemID, nSerialNum); if (g_pMain->IsDuplicateItem(nItemID,nSerialNum)) pItem->bFlag = ITEM_FLAG_DUPLICATE; } for (int a = 0; a < MAX_SLOT_VIP_STORAGE; a++) { uint64 nSerialNum; uint32 nItemID; int16 sDurability, sCount; uint32 nItemTime; VIPitemBuffer >> nItemID >> sDurability >> sCount; VIPserialBuffer >> nSerialNum; VIPitemTimeBuffer >> nItemTime; _ITEM_TABLE *pTable = g_pMain->GetItemPtr(nItemID); if (pTable == nullptr || sCount <= 0) continue; if (!pTable->m_bCountable && sCount > 1) sCount = 1; else if (sCount > ITEMCOUNT_MAX) sCount = ITEMCOUNT_MAX; if (nSerialNum == 0) nSerialNum = g_pMain->GenerateItemSerial(); _ITEM_DATA *pItem = pUser->GetVipStorageSlot(a); pItem->nNum = nItemID; pItem->sDuration = pTable->isAccessory() ? pTable->m_sDuration : sDurability; pItem->sCount = sCount; pItem->nSerialNum = nSerialNum; pItem->nExpirationTime = nItemTime; // If the serial was found in the rental data, mark as rented. UserRentalMap::iterator itr = rentalData.find(nSerialNum); if (itr != rentalData.end()) { pItem->bFlag = ITEM_FLAG_RENTED; pItem->sRemainingRentalTime = itr->second->sMinutesRemaining; } UserItemSealMap::iterator sealitr = pUser->m_sealedItemMap.find(nSerialNum); if (sealitr != pUser->m_sealedItemMap.end()) { if (sealitr->second->bSealType == 1) pItem->bFlag = ITEM_FLAG_SEALED; else if (sealitr->second->bSealType == 3) pItem->bFlag = ITEM_FLAG_BOUND; else if (sealitr->second->bSealType == 4) pItem->bFlag = ITEM_FLAG_NOT_BOUND; } g_pMain->AddUserItem(nItemID, nSerialNum); if (g_pMain->IsDuplicateItem(nItemID,nSerialNum)) pItem->bFlag = ITEM_FLAG_DUPLICATE; } // Clean up the rental data foreach (itr, rentalData) delete itr->second; rentalData.clear(); // Starter items. This needs fixing eventually. if (pUser->GetLevel() == 1 && pUser->m_iExp == 0) // going back to their initial bugginess { uint32 nItemID = 0; uint16 sDurability = 0; switch (pUser->m_sClass) { case 101: nItemID = 120010000; sDurability = 5000; break; case 102: nItemID = 110010000; sDurability = 4000; break; case 103: nItemID = 180010000; sDurability = 5000; break; case 104: nItemID = 190010000; sDurability = 10000; break; case 201: nItemID = 120050000; sDurability = 5000; break; case 202: nItemID = 110050000; sDurability = 4000; break; case 203: nItemID = 180050000; sDurability = 5000; break; case 204: nItemID = 190050000; sDurability = 10000; break; } if (nItemID && !pUser->CheckExistItem(nItemID, 1)) { int slot = pUser->GetEmptySlot(); if (slot < 0) return true; _ITEM_DATA * pItem = pUser->GetItem(slot); pItem->nNum = nItemID; pItem->sDuration = sDurability; pItem->sCount = 1; pItem->nSerialNum = g_pMain->GenerateItemSerial(); } } return true; } bool CDBAgent::LoadWarehouseData(string & strAccountID, CUser *pUser) { char strItem[WAREHOUSE_MAX * 8], strSerial[WAREHOUSE_MAX * 8], strItemTime[WAREHOUSE_MAX * 8]; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; if (pUser == nullptr || pUser->m_bLogout) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(_T("SELECT nMoney, WarehouseData, strSerial, WarehouseDataTime FROM WAREHOUSE WHERE strAccountID = ?"))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return false; memset(strItem, 0x00, sizeof(strItem)); memset(strSerial, 0x00, sizeof(strSerial)); memset(strItemTime, 0x00, sizeof(strItemTime)); dbCommand->FetchUInt32(1, pUser->m_iBank); dbCommand->FetchBinary(2, strItem, sizeof(strItem)); dbCommand->FetchBinary(3, strSerial, sizeof(strSerial)); dbCommand->FetchBinary(4, strItemTime, sizeof(strItemTime)); ByteBuffer itemBuffer, serialBuffer, itemTimeBuffer; itemBuffer.append(strItem, sizeof(strItem)); serialBuffer.append(strSerial, sizeof(strSerial)); itemTimeBuffer.append(strItemTime, sizeof(strItemTime)); memset(pUser->m_sWarehouseArray, 0x00, sizeof(pUser->m_sWarehouseArray)); for (int i = 0; i < WAREHOUSE_MAX; i++) { uint64 nSerialNum; uint32 nItemID, nItemTime; int16 sDurability, sCount; itemBuffer >> nItemID >> sDurability >> sCount; serialBuffer >> nSerialNum; itemTimeBuffer >> nItemTime; _ITEM_TABLE *pTable = g_pMain->GetItemPtr(nItemID); if (pTable == nullptr || sCount <= 0) continue; if (!pTable->m_bCountable && sCount > 1) sCount = 1; else if (sCount > ITEMCOUNT_MAX) sCount = ITEMCOUNT_MAX; pUser->m_sWarehouseArray[i].nNum = nItemID; pUser->m_sWarehouseArray[i].sDuration = sDurability; pUser->m_sWarehouseArray[i].sCount = sCount; pUser->m_sWarehouseArray[i].nSerialNum = nSerialNum; pUser->m_sWarehouseArray[i].nExpirationTime = nItemTime; UserItemSealMap::iterator sealitr = pUser->m_sealedItemMap.find(nSerialNum); if (sealitr != pUser->m_sealedItemMap.end()) { if (sealitr->second->bSealType == 1) pUser->m_sWarehouseArray[i].bFlag = ITEM_FLAG_SEALED; else if (sealitr->second->bSealType == 3) pUser->m_sWarehouseArray[i].bFlag = ITEM_FLAG_BOUND; else if (sealitr->second->bSealType == 4) pUser->m_sWarehouseArray[i].bFlag = ITEM_FLAG_NOT_BOUND; } g_pMain->AddUserItem(nItemID, nSerialNum); if (g_pMain->IsDuplicateItem(nItemID,nSerialNum)) pUser->m_sWarehouseArray[i].bFlag = ITEM_FLAG_DUPLICATE; } return true; } bool CDBAgent::LoadPremiumServiceUser(string & strAccountID, CUser *pUser) { if (pUser == nullptr) return false; unique_ptr dbCommand(m_AccountDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_OUTPUT, &pUser->PremiumID); if (!dbCommand->Execute(_T("{CALL LOAD_PREMIUM_SERVICE_USER(?,?)}"))) ReportSQLError(m_AccountDB->GetError()); uint16 count = 0; do { _PREMIUM_TYPE * pPremium = new _PREMIUM_TYPE; dbCommand->FetchByte(1, pPremium->PremiumType); dbCommand->FetchUInt16(2, pPremium->PremiumTime); pUser->PremiumList.PutData(pPremium->PremiumType,pPremium); count++; } while (dbCommand->MoveNext()); // this is hardcoded because we don't really care about the other mode if (pUser->PremiumID != 0) pUser->m_bAccountStatus = 1; // normal premium with expiry time else pUser->m_bAccountStatus = 0; return true; } bool CDBAgent::LoadSavedMagic(CUser *pUser) { if (pUser == nullptr) return false; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); if (!dbCommand->Execute(_T("SELECT " "nSkill1, nDuring1, nSkill2, nDuring2, nSkill3, nDuring3, nSkill4, nDuring4, nSkill5, nDuring5, " "nSkill6, nDuring6, nSkill7, nDuring7, nSkill8, nDuring8, nSkill9, nDuring9, nSkill10, nDuring10 " "FROM USER_SAVED_MAGIC WHERE strCharID = ?"))) { ReportSQLError(m_GameDB->GetError()); return false; } pUser->m_savedMagicMap.clear(); if (!dbCommand->hasData()) return true; for (int i = 1; i <= 20; i += 2) { uint32 nSkillID; uint16 nExpiry; dbCommand->FetchUInt32(i, nSkillID); dbCommand->FetchUInt16(i + 1, nExpiry); if (nSkillID != 0) pUser->m_savedMagicMap[nSkillID] = (nExpiry + UNIXTIME); } return true; } bool CDBAgent::UpdateSavedMagic(CUser *pUser) { if (pUser == nullptr) return false; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; Guard lock(pUser->_unitlock); uint32 nSkillID[10] = {0}; uint16 tExpiryTime[10] = {0}; uint32 i = 0; foreach (itr, pUser->m_savedMagicMap) { nSkillID[i] = itr->first; if (itr->first != 0) tExpiryTime[i] = uint16(itr->second - UNIXTIME); if (++i == 10) break; } dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_SAVED_MAGIC(?, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)}"), nSkillID[0], tExpiryTime[0], nSkillID[1], tExpiryTime[1], nSkillID[2], tExpiryTime[2], nSkillID[3], tExpiryTime[3], nSkillID[4], tExpiryTime[4], nSkillID[5], tExpiryTime[5], nSkillID[6], tExpiryTime[6], nSkillID[7], tExpiryTime[7], nSkillID[8], tExpiryTime[8], nSkillID[9], tExpiryTime[9]))) { ReportSQLError(m_GameDB->GetError()); return false; } return true; } bool CDBAgent::SetLogInInfo(string & strAccountID, string & strCharID, string & strServerIP, short sServerNo, string & strClientIP, uint8 bInit) { uint8 result = 0; unique_ptr dbCommand(m_AccountDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &result); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strServerIP.c_str(), strServerIP.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strClientIP.c_str(), strClientIP.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL SET_LOGIN_INFO(?, ?, %d, ?, ?, %d)}"), sServerNo, bInit))) ReportSQLError(m_AccountDB->GetError()); return (bool)(result == 0 ? false : true); } bool CDBAgent::ClearWebItemMall(CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); // TODO: Add an arg for the free slot count so we only need to pull/delete what we can hold. if (!dbCommand->Execute(_T("{CALL CLEAR_WEB_ITEMMALL(?)}"))) { ReportSQLError(m_AccountDB->GetError()); return false; }else return true; } bool CDBAgent::LoadWebItemMall(std::vector<_ITEM_DATA> & itemList, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); // TODO: Add an arg for the free slot count so we only need to pull/delete what we can hold. if (!dbCommand->Execute(_T("{CALL LOAD_WEB_ITEMMALL(?)}"))) ReportSQLError(m_AccountDB->GetError()); if (dbCommand->hasData()) { do { _ITEM_DATA item; dbCommand->FetchUInt32(2, item.nNum); // 1 is the account name, which we don't need to use unless we're logging dbCommand->FetchUInt16(3, item.sCount); dbCommand->FetchUInt32(5, item.nExpirationTime); itemList.push_back(item); } while (dbCommand->MoveNext()); } return true; } bool CDBAgent::LoadSkillShortcut(Packet & result, CUser *pUser) { if (pUser == nullptr) return false; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; uint16 sCount; char strSkillData[260]; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); if (!dbCommand->Execute(_T("SELECT nCount, strSkillData FROM USERDATA_SKILLSHORTCUT WHERE strCharID = ?"))) { ReportSQLError(m_GameDB->GetError()); return false; } if (!dbCommand->hasData()) return false; dbCommand->FetchUInt16(1, sCount); dbCommand->FetchString(2, strSkillData, sizeof(strSkillData)); result << sCount; for (uint32 i = 0; i < sCount; i++) result << *(uint32 *)(strSkillData + (i * sizeof(uint32))); return true; } void CDBAgent::SaveSkillShortcut(uint16 sCount, char *buff, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); dbCommand->AddParameter(SQL_PARAM_INPUT, buff, 260); if (!dbCommand->Execute(string_format(_T("{CALL SKILLSHORTCUT_SAVE(?, %d, ?)}"), sCount))) ReportSQLError(m_GameDB->GetError()); } bool CDBAgent::SavePremiumServiceUser(CUser *pUser, _PREMIUM_TYPE * pPremium) { if (pUser == nullptr) return false; if (pPremium->PremiumTime == 0 && pPremium->PremiumType == 0) return false; unique_ptr dbCommand(m_AccountDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetAccountName().c_str(), pUser->GetAccountName().length()); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); if (!dbCommand->Execute(string_format(_T("{CALL SAVE_PREMIUM_SERVICE_USER(?, ?, %d, %d)}"), pPremium->PremiumType, pPremium->PremiumTime))) ReportSQLError(m_GameDB->GetError()); return true; } uint8 CDBAgent::SealItem(string strSealPasswd, uint64 nItemSerial, uint32 nItemID, uint8 bSealType, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 3; uint8 bRet = 1; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetAccountName().c_str(), pUser->GetAccountName().length()); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strSealPasswd.c_str(), strSealPasswd.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL USER_ITEM_SEAL(?, ?, ?, " I64FMTD ", %d, %d)}"), nItemSerial, nItemID, bSealType))) ReportSQLError(m_GameDB->GetError()); return bRet; } void CDBAgent::RequestFriendList(std::vector & friendList, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); if (!dbCommand->Execute(_T("SELECT * FROM FRIEND_LIST WHERE strUserID = ?"))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return; string strCharID; for (int i = 2; i <= 25; i++) { if (dbCommand->FetchString(i, strCharID) && strCharID.length()) friendList.push_back(strCharID); } } FriendAddResult CDBAgent::AddFriend(short sid, short tid) { CUser *pSrcUser = g_pMain->GetUserPtr(sid), *pTargetUser = g_pMain->GetUserPtr(tid); CBot *pTargetBot = g_pMain->m_arBotArray.GetData(tid); if (pSrcUser == nullptr || (pTargetUser == nullptr && pTargetBot == nullptr)) return FRIEND_ADD_ERROR; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return FRIEND_ADD_ERROR; int16 sRet = (int16)FRIEND_ADD_ERROR; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, pSrcUser->GetName().c_str(), pSrcUser->GetName().length()); dbCommand->AddParameter(SQL_PARAM_INPUT, pTargetUser == nullptr ? pTargetBot->GetName().c_str() : pTargetUser->GetName().c_str(), pTargetUser == nullptr ? pTargetBot->GetName().length() : pTargetUser->GetName().length()); if (!dbCommand->Execute(_T("{? = CALL INSERT_FRIEND_LIST(?, ?)}"))) ReportSQLError(m_GameDB->GetError()); return (FriendAddResult)sRet; } FriendRemoveResult CDBAgent::RemoveFriend(string & strCharID, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return FRIEND_REMOVE_ERROR; int16 sRet = (int16)FRIEND_REMOVE_ERROR; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("{? = CALL DELETE_FRIEND_LIST(?, ?)}"))) ReportSQLError(m_GameDB->GetError()); return (FriendRemoveResult)sRet; } bool CDBAgent::UpdateUser(string & strCharID, UserUpdateType type, CUser *pUser) { if (strCharID != pUser->GetName()) return false; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; pUser->m_dwTime += (uint32(UNIXTIME - pUser->m_TimeOnline) / 60); pUser->m_TimeOnline = UNIXTIME; char strQuest[QUEST_ARRAY_SIZE]; char strAchieveQuest[QUEST_ARRAY_SIZE]; uint16 strAchieveQuestKill[QUEST_ARRAY_SIZE]; memset(strQuest, 0, sizeof(strQuest)); memset(strAchieveQuest, 0, sizeof(strAchieveQuest)); memset(strAchieveQuestKill, 0, sizeof(strAchieveQuestKill)); int index = 0; foreach (itr, pUser->m_questMap) { *(uint16 *)(strQuest + index) = itr->first; *(uint8 *)(strQuest + index + 2) = itr->second; index += 3; } int index2 = 0; foreach (itr, pUser->m_AchievequestMap) { if(itr->first > 32000 || itr->first < 0 || itr->second == 0) continue; *(uint16 *)(strAchieveQuest + index2) = itr->first; *(uint8 *)(strAchieveQuest + index2 + 2) = itr->second; //printf("UpdateUser ID:%d ST:%d\n",itr->first,itr->second); index2 += 3; } index2 = 0; int AchieveQuestSize = 0; foreach(itr,pUser->m_AchievequestMap) { if (itr->second == 1 || itr->second == 2) { Guard lock(pUser->m_bAchieveKillCount.m_lock); _ACHIEVE_QUEST * pAchieveQuest = pUser->m_bAchieveKillCount.GetData(itr->first); if (pAchieveQuest == nullptr) continue; strAchieveQuestKill[index2] = itr->first; // 0,1 strAchieveQuestKill[index2 + 2] = pAchieveQuest->KillCount[0]; // 2,3 strAchieveQuestKill[index2 + 4] = pAchieveQuest->KillCount[1]; // 4,5 AchieveQuestSize++; index2 += 6; } } ByteBuffer itemBuffer, serialBuffer, itemTimeBuffer,RebStatsBuffer,QuestBuffer; ByteBuffer VIPitemBuffer, VIPserialBuffer, VIPitemTimeBuffer; uint8 kcount = 0; foreach(itr, pUser->m_QuestMonMap) { QuestBuffer << itr->first; QuestBuffer << itr->second->dCKills[0]; QuestBuffer << itr->second->dCKills[1]; QuestBuffer << itr->second->dCKills[2]; QuestBuffer << itr->second->dCKills[3]; kcount++; } if (kcount == 0) QuestBuffer << uint16(0); for (int i = 0; i < INVENTORY_TOTAL; i++) { _ITEM_DATA *pItem = &pUser->m_sItemArray[i]; itemBuffer << pItem->nNum << pItem->sDuration << pItem->sCount; serialBuffer << pItem->nSerialNum; itemTimeBuffer << pItem->nExpirationTime; } for (int i = CWING; i <= CTOP; i++) { _ITEM_DATA *pItem = &pUser->m_sItemArray[i]; itemBuffer << pItem->nNum << pItem->sDuration << pItem->sCount; serialBuffer << pItem->nSerialNum; itemTimeBuffer << pItem->nExpirationTime; } for (int a = 0; a < MAX_SLOT_VIP_STORAGE; a++) { _ITEM_DATA *pItem = &pUser->m_sVIPItemArray[a]; VIPitemBuffer << pItem->nNum << pItem->sDuration << pItem->sCount; VIPserialBuffer << pItem->nSerialNum; VIPitemTimeBuffer << pItem->nExpirationTime; } RebStatsBuffer << pUser->GetRebStatBuff(STAT_STR) << pUser->GetRebStatBuff(STAT_STA) << pUser->GetRebStatBuff(STAT_DEX) << pUser->GetRebStatBuff(STAT_INT) << pUser->GetRebStatBuff(STAT_CHA); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)pUser->m_bstrSkill, sizeof(pUser->m_bstrSkill)); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)itemBuffer.contents(), itemBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)serialBuffer.contents(), serialBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)VIPitemBuffer.contents(), VIPitemBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)VIPserialBuffer.contents(), VIPserialBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)strQuest, sizeof(strQuest), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)QuestBuffer.contents(), QuestBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)strAchieveQuest, sizeof(strAchieveQuest), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)itemTimeBuffer.contents(), itemTimeBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)VIPitemTimeBuffer.contents(), VIPitemTimeBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strMemo.c_str(), pUser->m_strMemo.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)pUser->m_GenieOptions, sizeof(pUser->m_GenieOptions)); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)strAchieveQuestKill, sizeof(strAchieveQuestKill)); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)RebStatsBuffer.contents(), RebStatsBuffer.size(), SQL_BINARY); if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_USER_DATA(" "?, " // strCharID "%d, %d, %d, %d, %d, " // nation, race, class, hair, rank "%d, %d, %d, " I64FMTD ", %d, %d, " // title, level,rebLevel, exp, loyalty, face "%d, %d, %d, " // city, knights, fame "%d, %d, %d, " // hp, mp, sp "%d, %d, %d, %d, %d, " // str, sta, dex, int, cha "%d, %d, %d, %d, %d, " // authority, free points, gold, zone, bind "%d, %d, %d, %d, %d, %d, %d, " // x, z, y, dwTime, sQuestCount, sQuestMonsterCount, sAchieveQuestCount "?, ?, ?, ?, ?, ?,?, ?," // strSkill, strItem, strSerial, strVIPItem, strVIPSerial, strQuest, strQuestKill, strAchieveQuest "%d, %d, ?, ?," // manner points, monthly NP, strItemTime, strVIPItemTime "?, %d, ?, ?, ?, %d, %d, %d, " // ClanMemo Genie Time , Genie Options, strAchieveQuestKill, rebirthstats, dtUpdateClan, AchieveSkill, AchieveCover "%d,%d, %d, %d, %d, " // vipExTime,m_iMonsterDefeatedCount, m_iUserDefeatedCount, m_iUserDeathCount, m_iAchievementPoint,LastOnline "%d)}"), pUser->m_bNation, pUser->m_bRace, pUser->m_sClass, pUser->m_nHair, pUser->m_bRank, pUser->m_bTitle, pUser->m_bLevel, pUser->m_reblvl, pUser->m_iExp /* temp hack, database needs to support it */, pUser->m_iLoyalty, pUser->m_bFace, pUser->m_bCity, pUser->m_bKnights, pUser->m_bFame, pUser->m_sHp, pUser->m_sMp, pUser->m_sSp, pUser->m_bStats[STAT_STR], pUser->m_bStats[STAT_STA], pUser->m_bStats[STAT_DEX], pUser->m_bStats[STAT_INT], pUser->m_bStats[STAT_CHA], pUser->m_bAuthority, pUser->m_sPoints, pUser->m_iGold, pUser->m_bZone, pUser->m_sBind, (int)(pUser->m_curx*100), (int)(pUser->m_curz*100), (int)(pUser->m_cury*100), pUser->m_dwTime, pUser->m_questMap.size(), pUser->m_QuestMonMap.size(), AchieveQuestSize, pUser->m_iMannerPoint, pUser->m_iLoyaltyMonthly, pUser->m_GenieTime, uint32(UNIXTIME), pUser->m_sAchieveSkillTitle,pUser->m_sAchieveCoverTitle, pUser->nVIPExpirationTime,pUser->m_iMonsterDefeatedCount,pUser->m_iUserDefeatedCount,pUser->m_iUserDeathCount,pUser->m_iAchievementPoint, pUser->m_LastOnline))) { ReportSQLError(m_GameDB->GetError()); return false; } pUser->m_lastSaveTime = UNIXTIME; pUser->m_lastBonusTime = UNIXTIME; return true; } bool CDBAgent::UpdateWarehouseData(string & strAccountID, UserUpdateType type, CUser *pUser) { if (strAccountID.length() == 0) return false; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; // This *should* be padded like the database field is (unnecessarily), but I want to see how MSSQL responds. ByteBuffer itemBuffer, serialBuffer, itemTimeBuffer; for (int i = 0; i < WAREHOUSE_MAX; i++) { _ITEM_DATA *pItem = &pUser->m_sWarehouseArray[i]; itemBuffer << pItem->nNum << pItem->sDuration << pItem->sCount; serialBuffer << pItem->nSerialNum; itemTimeBuffer << pItem->nExpirationTime; } dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)itemBuffer.contents(), itemBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)serialBuffer.contents(), serialBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)itemTimeBuffer.contents(), itemTimeBuffer.size(), SQL_BINARY); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(string_format(_T("UPDATE WAREHOUSE SET nMoney=%d, dwTime=%d, WarehouseData=?, strSerial=?, WarehouseDataTime=? WHERE strAccountID=?"), pUser->m_iBank, pUser->m_dwTime))) { ReportSQLError(m_GameDB->GetError()); return false; } return true; } int8 CDBAgent::CreateAlliance(uint8 byType, uint16 shAlliancIndex, uint16 shKnightsIndex, uint8 byEmptyIndex, uint8 bySiegeFlag) { int8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_KNIGHTS_ALLIANCE(%d, %d, %d, %d, %d)}"), byType, shAlliancIndex, shKnightsIndex, byEmptyIndex,bySiegeFlag))) ReportSQLError(m_GameDB->GetError()); return bRet; } int8 CDBAgent::InsertAlliance(uint8 byType, uint16 shAlliancIndex, uint16 shKnightsIndex, uint8 byEmptyIndex, uint8 bySiegeFlag) { int8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_KNIGHTS_ALLIANCE(%d, %d, %d, %d, %d)}"), byType, shAlliancIndex, shKnightsIndex, byEmptyIndex,bySiegeFlag))) ReportSQLError(m_GameDB->GetError()); return bRet; } int8 CDBAgent::RemoveAlliance(uint8 byType, uint16 shAlliancIndex, uint16 shKnightsIndex, uint8 byEmptyIndex, uint8 bySiegeFlag) { int8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_KNIGHTS_ALLIANCE(%d, %d, %d, %d, %d)}"), byType, shAlliancIndex, shKnightsIndex, byEmptyIndex,bySiegeFlag))) ReportSQLError(m_GameDB->GetError()); return bRet; } int8 CDBAgent::DestoryAlliance(uint8 byType, uint16 shAlliancIndex, uint16 shKnightsIndex, uint8 byEmptyIndex, uint8 bySiegeFlag) { int8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_KNIGHTS_ALLIANCE(%d, %d, %d, %d, %d)}"), byType, shAlliancIndex, shKnightsIndex, byEmptyIndex,bySiegeFlag))) ReportSQLError(m_GameDB->GetError()); return bRet; } int8 CDBAgent::CreateKnights(uint16 sClanID, uint8 bNation, string & strKnightsName, string & strChief, uint8 bFlag) { int8 bRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strKnightsName.c_str(), strKnightsName.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strChief.c_str(), strChief.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL CREATE_KNIGHTS(%d, %d, %d, ?, ?)}"), sClanID, bNation, bFlag))) ReportSQLError(m_GameDB->GetError()); return bRet; } int CDBAgent::UpdateKnights(uint8 bType, string & strCharID, uint16 sClanID, uint8 bDomination) { int16 sRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return sRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL UPDATE_KNIGHTS(%d, ?, %d, %d)}"), bType + 0x10, sClanID, bDomination))) ReportSQLError(m_GameDB->GetError()); if (bType == KNIGHTS_VICECHIEF && sRet == 0) { CKnights * pKnights = g_pMain->GetClanPtr(sClanID); if (pKnights != nullptr) { if (pKnights->m_strViceChief_1 == "") pKnights->m_strViceChief_1 = strCharID; else if (pKnights->m_strViceChief_2 == "") pKnights->m_strViceChief_2 = strCharID; else if (pKnights->m_strViceChief_3 == "") pKnights->m_strViceChief_3 = strCharID; } } return sRet; } int CDBAgent::DeleteKnights(uint16 sClanID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; int16 sRet = -1; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); if (!dbCommand->Execute(string_format(_T("{? = CALL DELETE_KNIGHTS (%d)}"), sClanID))) ReportSQLError(m_GameDB->GetError()); return sRet; } void CDBAgent::UpdateVIPStoragePassword(std::string strUserID, std::string VIPPassword) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return ; dbCommand->AddParameter(SQL_PARAM_INPUT, strUserID.c_str(), strUserID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, VIPPassword.c_str(), VIPPassword.length()); if (!dbCommand->Execute(string_format(_T("EXEC UPDATE_USER_VIP_PASSWORD ?,?")))) ReportSQLError(m_GameDB->GetError()); return; } void CDBAgent::UpdateVIPStorageMinute(std::string strUserID, uint32 VIPMinute) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strUserID.c_str(), strUserID.length()); if (!dbCommand->Execute(string_format(_T("EXEC UPDATE_USER_VIP_MINUTE ?,%d"), VIPMinute))) ReportSQLError(m_GameDB->GetError()); return; } uint16 CDBAgent::LoadKnightsAllMembers(uint16 sClanID, Packet & result) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; if (!dbCommand->Execute(string_format(_T("SELECT strUserID, Fame, [Level], Class FROM USERDATA WHERE Knights = %d"), sClanID))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return 0; uint16 count = 0; do { string strCharID; uint16 sClass; uint8 bFame, bLevel; dbCommand->FetchString(1, strCharID); dbCommand->FetchByte(2, bFame); dbCommand->FetchByte(3, bLevel); dbCommand->FetchUInt16(4, sClass); result << strCharID << bFame << bLevel << sClass // check if user's logged in (i.e. grab logged in state) << uint8(g_pMain->GetUserPtr(strCharID, TYPE_CHARACTER) == nullptr ? 0 : 1); count++; } while (dbCommand->MoveNext()); return count; } bool CDBAgent::LoadKnightsInfo(uint16 sClanID, uint8 & bNation, std::string & strKnightsName, uint16 & sMembers, uint32 & nPoints, uint8 & bRank) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; if (!dbCommand->Execute(string_format(_T("SELECT Nation, IDName, Members, Points, Ranking FROM KNIGHTS WHERE IDNum=%d" ), sClanID))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return false; dbCommand->FetchByte(1, bNation); dbCommand->FetchString(2, strKnightsName); dbCommand->FetchUInt16(3, sMembers); dbCommand->FetchUInt32(4, nPoints); dbCommand->FetchByte(5, bRank); return true; } void CDBAgent::LoadKnightsAllList() { unique_ptr dbCommand(m_GameDB->CreateCommand()); const tstring szSQL = _T("SELECT IDNum, Points, Ranking FROM KNIGHTS WHERE Points != 0 ORDER BY Points DESC"); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(szSQL)) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return; Packet result(WIZ_KNIGHTS_PROCESS); uint8 bCount = 0; int offset; do { if (bCount == 0) { result.clear(); offset = result.wpos(); result << uint8(0); } uint32 nPoints; uint16 sClanID; uint8 bRanking; dbCommand->FetchUInt16(1, sClanID); dbCommand->FetchUInt32(2, nPoints); dbCommand->FetchByte(3, bRanking); result << sClanID << nPoints << bRanking; // only send 100 clans at a time (no shared memory limit, yay!) if (++bCount >= 100) { // overwrite the count result.put(offset, bCount); CKnightsManager::RecvKnightsAllList(result); bCount = 0; } } while (dbCommand->MoveNext()); // didn't quite make it in the last batch (if any)? send the remainder. if (bCount < 100) { result.put(offset, bCount); CKnightsManager::RecvKnightsAllList(result); } } bool CDBAgent::UpdateClanSymbol(uint16 sClanID, uint16 sSymbolSize, char *clanSymbol) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, clanSymbol, MAX_KNIGHTS_MARK, SQL_BINARY); if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS SET Mark=?, sMarkVersion += 1, sMarkLen=%d WHERE IDNum=%d"), sSymbolSize, sClanID))) { ReportSQLError(m_GameDB->GetError()); return false; } return true; } /** * @brief Handles the clan NP donations database request. * It is essentially the client packet's real handler * as the packet is simply forwarded here. * * @param pUser The user. * @param pkt The packet. */ void CKnightsManager::ReqDonateNP(CUser *pUser, Packet & pkt) { if (pUser == nullptr || !pUser->isInClan()) return; uint32 amountNP; pkt >> amountNP; // Ensure the user has enough NP to donate to the clan. if (amountNP > pUser->GetLoyalty() // Users must have at least MIN_NP_TO_DONATE to donate. || (pUser->GetLoyalty() - amountNP) < MIN_NP_TO_DONATE) return; // Ensure the clan exists CKnights * pKnights = g_pMain->GetClanPtr(pUser->GetClanID()); if (pKnights == nullptr) return; // Take player's donated NP. Don't affect monthly NP. if (g_DBAgent.DonateClanPoints(pUser, amountNP)) { // Update the user's donated NP CKnightsManager::AddUserDonatedNPinGame(pUser->GetClanID(), pUser, amountNP); // Take the NP from the user and update the client. pUser->m_iLoyalty -= amountNP; Packet result(WIZ_LOYALTY_CHANGE, uint8(LOYALTY_NATIONAL_POINTS)); result << pUser->m_iLoyalty << pUser->m_iLoyaltyMonthly << uint32(0) // Clan donations(? Donations made by this user? For the clan overall?) << amountNP; // Premium NP(? Additional NP gained?) pUser->Send(&result); } } /** * @brief Donates (clanPoints) clan points to the specified user's clan. * Also increases the user's total NP donated. * * @param pUser The donor user. * @param amountNP The number of national points being donated by the user. * * @return true if it succeeds, false if it fails. */ bool CDBAgent::DonateClanPoints(CUser * pUser, uint32 amountNP) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); if (!dbCommand->Execute(string_format(_T("{CALL DONATE_CLAN_POINTS(?, %d, %d)}"), pUser->GetClanID(), amountNP))) { ReportSQLError(m_GameDB->GetError()); return false; } return true; } /** * @brief Handles the database request to refund the specified * logged out character's donated NP. * * NOTE: Logged in players don't need to be handled as their NP is * refunded in-game. * * @param pkt The packet. */ void CKnightsManager::ReqRefundNP(Packet & pkt) { string strUserID; uint32 nRefundNP; pkt >> strUserID >> nRefundNP; g_DBAgent.RefundNP(strUserID, nRefundNP); } /** * @brief Handles the database request to update the * specified clan's clan point fund. * * @param pkt The packet. */ void CKnightsManager::ReqUpdateNP(Packet & pkt) { uint16 sClanID; uint32 nClanPointFund; pkt >> sClanID >> nClanPointFund; g_DBAgent.UpdateClanFund(sClanID, nClanPointFund); } /** * @brief Refunds the specified amount of NP to a logged out character. * * @param strUserID Character's name. * @param nRefundNP The amount of NP to refund. */ void CDBAgent::RefundNP(string & strUserID, uint32 nRefundNP) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strUserID.c_str(), strUserID.length()); if (!dbCommand->Execute(string_format(_T("UPDATE USERDATA SET Loyalty += %d WHERE strUserID = ?"), nRefundNP))) ReportSQLError(m_GameDB->GetError()); } /** * @brief Change authority is logged out character. * * @param strUserID Character's name. * @param nAuthority New user authority. */ void CDBAgent::UpdateUserAuthority(string & strUserID, uint16 nAuthority) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strUserID.c_str(), strUserID.length()); if (!dbCommand->Execute(string_format(_T("UPDATE USERDATA SET Authority = %d WHERE strUserID = ?"), nAuthority))) ReportSQLError(m_GameDB->GetError()); } /** * @brief Updates the clan fund. * * @param sClanID Identifier for the clan. * @param nClanPointFund The current clan point fund. */ void CDBAgent::UpdateClanFund(uint16 sClanID, uint32 nClanPointFund) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS SET ClanPointFund = %d WHERE IDNum = %d"), nClanPointFund, sClanID))) ReportSQLError(m_GameDB->GetError()); } /** * @brief Updates the clan notice. * * @param sClanID Identifier for the clan. * @param strClanNotice The clan notice. */ void CDBAgent::UpdateClanNotice(uint16 sClanID, std::string & strClanNotice) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strClanNotice.c_str(), strClanNotice.length()); if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS SET strClanNotice = ? WHERE IDNum = %d"), sClanID))) ReportSQLError(m_GameDB->GetError()); } NameChangeOpcode CDBAgent::UpdateCharacterName(std::string & strAccountID, std::string & strUserID, std::string & strNewUserID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return NameChangeInvalidName; int16 sRet = 1; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strUserID.c_str(), strUserID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strNewUserID.c_str(), strNewUserID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL CHANGE_NEW_ID(%d, ?, ?, ?, 1)}"), g_pMain->m_nServerNo))) ReportSQLError(m_GameDB->GetError()); return NameChangeOpcode(sRet); } ClanNameChangeOpcode CDBAgent::UpdateClanName(std::string & strUserID, uint16 sClanID, std::string & strNewKnightsID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return ClanNameChangeInvalidName; int16 sRet = 1; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strUserID.c_str(), strUserID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strNewKnightsID.c_str(), strNewKnightsID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL CHANGE_NEW_KNIGHTS_ID(%d, ?, ?, %d, 1)}"), g_pMain->m_nServerNo, sClanID))) ReportSQLError(m_GameDB->GetError()); return ClanNameChangeOpcode(sRet); } /** * @brief Handles clan cape database updates. * * @param sClanID Identifier for the clan. * @param sCapeID Identifier for the cape. * @param r Red colour component. * @param g Green colour component. * @param b Blue colour component. * * @return true if it succeeds, false if it fails. */ void CDBAgent::UpdateCape(uint16 sClanID, uint16 sCapeID, uint8 r, uint8 g, uint8 b) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS SET sCape=%d, bCapeR=%d, bCapeG=%d, bCapeB=%d WHERE IDNum=%d"), sCapeID, r, g, b, sClanID))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::UpdatePremiumType(uint8 bType, std::string StrAccountID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, StrAccountID.c_str(), StrAccountID.length()); if (!dbCommand->Execute(string_format(_T("UPDATE TB_USER SET bPremiumType=%d WHERE strAccountID=?"), bType))) ReportSQLError(m_GameDB->GetError()); } /** * @brief Updates the clan grade. * * @param sClanID Identifier for the clan. * @param byFlag The clan type (training, promoted, etc). * @param sCapeID Identifier for the cape. */ void CDBAgent::UpdateClanGrade(uint16 sClanID, uint8 byFlag, uint16 sCapeID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS SET sCape=%d, Flag=%d WHERE IDNum=%d"), sCapeID, byFlag, sClanID))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::UpdateBattleEvent(string & strCharID, uint8 bNation) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("UPDATE BATTLE SET byNation=%d, strUserName=? WHERE sIndex=%d"), bNation, g_pMain->m_nServerNo))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::AccountLogout(string & strAccountID) { unique_ptr dbCommand(m_AccountDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(_T("{CALL ACCOUNT_LOGOUT(?)}"))) ReportSQLError(m_AccountDB->GetError()); } void CDBAgent::UpdateConCurrentUserCount(int nServerNo, int nZoneNo, int nCount) { unique_ptr dbCommand(m_AccountDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("UPDATE CONCURRENT SET zone%d_count = %d WHERE serverid = %d"), nZoneNo, nCount, nServerNo))) ReportSQLError(m_AccountDB->GetError()); } // This is what everything says it should do, // but the client doesn't seem to care if it's over 1 uint8 CDBAgent::GetUnreadLetterCount(string & strCharID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; uint8 bCount = 0; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bCount); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(_T("{? = CALL MAIL_BOX_CHECK_COUNT(?)}"))) { ReportSQLError(m_GameDB->GetError()); return 0; } return bCount; } bool CDBAgent::GetLetterList(string & strCharID, Packet & result, bool bNewLettersOnly /* = true*/) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; int8 bCount = 0; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bCount); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL MAIL_BOX_REQUEST_LIST(?, %d)}"), bNewLettersOnly))) { ReportSQLError(m_GameDB->GetError()); return false; } result << uint8(1); int offset = result.wpos(); result << bCount; // placeholder for count if (!dbCommand->hasData()) return true; result.SByte(); do { string strSubject, strSender; uint32 nLetterID, nItemID, nCoins, nDate; uint16 sCount, sDaysRemaining; uint8 bStatus, bType; dbCommand->FetchUInt32(1, nLetterID); dbCommand->FetchByte(2, bStatus); dbCommand->FetchByte(3, bType); dbCommand->FetchString(4, strSubject); dbCommand->FetchString(5, strSender); dbCommand->FetchByte(6, bType); dbCommand->FetchUInt32(7, nItemID); dbCommand->FetchUInt16(8, sCount); dbCommand->FetchUInt32(9, nCoins); dbCommand->FetchUInt32(10, nDate); dbCommand->FetchUInt16(11, sDaysRemaining); result << nLetterID // letter ID << bStatus // letter status, doesn't seem to affect anything << strSubject << strSender << bType; if (bType == 2) result << nItemID << sCount << nCoins; result << nDate // date (yy*10000 + mm*100 + dd) << uint8(sDaysRemaining) << uint8(1); } while (dbCommand->MoveNext()); result.put(offset, bCount); // set count now that the result set's been read return true; } int8 CDBAgent::SendLetter(string & strSenderID, string & strRecipientID, string & strSubject, string & strMessage, uint8 bType, _ITEM_DATA * pItem, int32 nCoins) { uint64 nSerialNum = 0; uint32 nItemID = 0; uint16 sCount = 0, sDurability = 0; uint32 nExpirationTime = 0; int8 bRet = 0; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return 0; // This is a little bit redundant, but best to be sure. if (bType == 2 && pItem != nullptr) { nItemID = pItem->nNum; sCount = pItem->sCount; sDurability = pItem->sDuration; nSerialNum = pItem->nSerialNum; nExpirationTime = pItem->nExpirationTime; } dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strSenderID.c_str(), strSenderID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strRecipientID.c_str(), strRecipientID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strSubject.c_str(), strSubject.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strMessage.c_str(), strMessage.length()); // MSSQL uses signed types. if (!dbCommand->Execute(string_format(_T("{? = CALL MAIL_BOX_SEND(?, ?, ?, ?, %d, %d, %d, %d, " I64FMTD ",%d, %d)}"), bType, nItemID, sCount, sDurability, nSerialNum,nExpirationTime, nCoins))) { ReportSQLError(m_GameDB->GetError()); return 0; } return bRet; } bool CDBAgent::ReadLetter(string & strCharID, uint32 nLetterID, string & strMessage) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("{CALL MAIL_BOX_READ(?, %d)}"), nLetterID))) { ReportSQLError(m_GameDB->GetError()); return false; } if (!dbCommand->hasData()) return false; dbCommand->FetchString(1, strMessage); return true; } int8 CDBAgent::GetItemFromLetter(string & strCharID, uint32 nLetterID, uint32 & nItemID, uint16 & sCount, uint16 & sDurability, uint32 & nCoins, uint64 & nSerialNum, uint32 & nExpirationTime) { int8 bRet = -1; // error unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return bRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL MAIL_BOX_GET_ITEM(?, %d)}"), nLetterID))) ReportSQLError(m_GameDB->GetError()); if (dbCommand->hasData()) { dbCommand->FetchUInt32(1, nItemID); dbCommand->FetchUInt16(2, sCount); dbCommand->FetchUInt16(3, sDurability); dbCommand->FetchUInt32(4, nCoins); dbCommand->FetchUInt64(5, nSerialNum); dbCommand->FetchUInt32(6, nExpirationTime); } return bRet=1; } void CDBAgent::DeleteLetter(string & strCharID, uint32 nLetterID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); // NOTE: The official implementation passes all 5 letter IDs. if (!dbCommand->Execute(string_format(_T("UPDATE MAIL_BOX SET bDeleted = 1 WHERE nLetterID = %d AND strRecipientID = ?"), nLetterID))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::ResendLetter(string & strCharID, uint32 nLetterID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); // NOTE: The official implementation passes all 5 letter IDs. if (!dbCommand->Execute(string_format(_T("UPDATE MAIL_BOX SET bStatus = 1 WHERE nLetterID = %d AND strRecipientID = ?"), nLetterID))) ReportSQLError(m_GameDB->GetError()); } /** * @brief Updates the election status. * * @param byType Election status. * @param byNation Electoral nation. */ void CDBAgent::UpdateElectionStatus(uint8 byType, uint8 byNation) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("{CALL KING_UPDATE_ELECTION_STATUS(%d, %d)}"), byType, byNation))) ReportSQLError(m_GameDB->GetError()); } /** * @brief Updates the election list. * * @param byDBType Procedure-specific database action. * If 1, insert. If 2, delete. * @param byType Flag to specify what the user's in the election list for (election, impeachment, and thereof). * @param byNation Electoral nation. * @param sKnights The nominee's clan ID. * @param nAmount Vote count. * @param strNominee The nominee's name. */ void CDBAgent::UpdateElectionList(uint8 byDBType, uint8 byType, uint8 byNation, uint16 sKnights, uint32 nAmount, string & strNominee, CUser * pUser) { int16 sRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr || pUser == nullptr) return; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strAccountID.c_str(), pUser->m_strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strNominee.c_str(), strNominee.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL KING_ELECTION_PROC(?, ?, %d, ?, %d)}"), pUser->GetNation(), sRet))) ReportSQLError(m_GameDB->GetError()); Packet result(WIZ_KING, uint8(1)); result << byType << uint8(2) << sRet; pUser->Send(&result); } int16 CDBAgent::UpdateElectionProc(CUser *pUser) { int16 sRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr || pUser == nullptr) return sRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strAccountID.c_str(), pUser->m_strAccountID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->GetName().c_str(), pUser->GetName().length()); if (!dbCommand->Execute(string_format(_T("{? = CALL KING_ELECTION_PROC(?, ?, %d, ?, 0)}"),pUser->GetNation()))) ReportSQLError(m_GameDB->GetError()); return sRet; } void CDBAgent::SendUDP_ElectionStatus(uint8 m_byType) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("UPDATE KING_SYSTEM SET byType = %d"), m_byType))) ReportSQLError(m_GameDB->GetError()); } bool CDBAgent::GetElectionResult(uint8 byNation, CKingSystem *KingSystem) { if (KingSystem == nullptr) return false; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; if (!dbCommand->Execute(string_format(_T("{CALL KING_ELECTION_FINISH(%d)}"),byNation))) ReportSQLError(m_GameDB->GetError()); if (!dbCommand->hasData()) return false; dbCommand->FetchString(1, KingSystem->m_strOldKingName); dbCommand->FetchString(2, KingSystem->m_strKingName); dbCommand->FetchUInt16(3, KingSystem->winPercent); return true; } /** * @brief Nominates/recommends strNominee as King. * * @param strNominator The nominator. * @param strNominee The nominee. * @param byNation Their nation. * * @return . */ int16 CDBAgent::UpdateCandidacyRecommend(std::string & strNominator, std::string & strNominee, uint8 byNation) { int16 sRet = -1; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return sRet; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &sRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strNominee.c_str(), strNominee.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strNominator.c_str(), strNominator.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL KING_CANDIDACY_RECOMMEND(?, ?, %d, 0)}"), byNation))) ReportSQLError(m_GameDB->GetError()); return sRet; } /** * @brief Updates the candidacy notice board. * * @param strCharID Candidate's name. * @param byNation Candidate's nation. * @param strNotice The notice. */ void CDBAgent::UpdateCandidacyNoticeBoard(string & strCharID, uint8 byNation, string & strNotice) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; // Field is 1024 bytes in the database. uint8 strBinaryNotice[1024] = {0}; uint16 sNoticeLen = strNotice.length(); // This shouldn't happen, but... in the horribly unlikely event it does... we're ready. if (sNoticeLen > sizeof(strBinaryNotice)) sNoticeLen = sizeof(strBinaryNotice); memcpy(strBinaryNotice, strNotice.c_str(), sNoticeLen); dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, strBinaryNotice, sizeof(strBinaryNotice)); if (!dbCommand->Execute(string_format(_T("{CALL KING_CANDIDACY_NOTICE_BOARD_PROC(?, %d, %d, ?)}"), sNoticeLen, byNation))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::UpdateNoahOrExpEvent(uint8 byType, uint8 byNation, uint8 byAmount, uint8 byDay, uint8 byHour, uint8 byMinute, uint16 sDuration) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("{CALL KING_UPDATE_NOAH_OR_EXP_EVENT(%d, %d, %d, %d, %d, %d, %d)}"), byType, byNation, byAmount, byDay, byHour, byMinute, sDuration))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::InsertPrizeEvent(uint8 byType, uint8 byNation, uint32 nCoins, std::string & strCharID) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strCharID.c_str(), strCharID.length()); if (!dbCommand->Execute(string_format(_T("{CALL KING_INSERT_PRIZE_EVENT(%d, %d, %d, ?)}"), byType, byNation, nCoins))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::InsertTaxEvent(uint8 KingNationTax, uint8 Nation, uint32 TerritoryTax) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (TerritoryTax > 0) { if (!dbCommand->Execute(string_format(_T("UPDATE KING_SYSTEM SET nTerritoryTax -= %d WHERE byNation = %d"), TerritoryTax, Nation))) ReportSQLError(m_GameDB->GetError()); } else { if (!dbCommand->Execute(string_format(_T("UPDATE KING_SYSTEM SET byTerritoryTariff = %d WHERE byNation = %d"), KingNationTax, Nation))) ReportSQLError(m_GameDB->GetError()); } } void CDBAgent::InsertTaxUpEvent(uint8 Nation, uint32 TerritoryTax) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (Nation == ZONE_ELMORAD || Nation == ZONE_KARUS) { if (!dbCommand->Execute(string_format(_T("UPDATE KING_SYSTEM SET nTerritoryTax += %d WHERE byNation = %d"), TerritoryTax, Nation))) ReportSQLError(m_GameDB->GetError()); }else if(Nation == ZONE_ELMORAD_ESLANT || Nation == ZONE_KARUS_ESLANT) { if (!dbCommand->Execute(string_format(_T("UPDATE KING_SYSTEM SET nNationalTreasury += %d WHERE byNation = %d"), TerritoryTax, (Nation - 10)))) ReportSQLError(m_GameDB->GetError()); } else if (Nation == ZONE_MORADON) { if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS_SIEGE_WARFARE SET nMoradonTax += %d WHERE sCastleIndex = 1"), TerritoryTax))) ReportSQLError(m_GameDB->GetError()); } else if (Nation == ZONE_DELOS) { if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS_SIEGE_WARFARE SET nDellosTax += %d WHERE sCastleIndex = 1"), TerritoryTax))) ReportSQLError(m_GameDB->GetError()); } } /** * @brief Resets the monthly NP total accumulated in the last month. */ void CDBAgent::ResetLoyaltyMonthly() { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(_T("{CALL RESET_LOYALTY_MONTHLY}"))) ReportSQLError(m_GameDB->GetError()); } /** * @brief Clears the remaining users who were connected to this server from the logged in user list that may still be there as the result of an improper shutdown. */ void CDBAgent::ClearRemainUsers() { _ZONE_SERVERINFO * pInfo = g_pMain->m_ServerArray.GetData(g_pMain->m_nServerNo); if (pInfo == nullptr) return; unique_ptr dbCommand(m_AccountDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, pInfo->strServerIP.c_str(), pInfo->strServerIP.length()); if (!dbCommand->Execute(_T("{CALL CLEAR_REMAIN_USERS(?)}"))) ReportSQLError(m_AccountDB->GetError()); } void CDBAgent::InsertUserDailyOp(_USER_DAILY_OP * pUserDailyOp) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, pUserDailyOp->strUserId.c_str(), pUserDailyOp->strUserId.length()); if (!dbCommand->Execute(string_format(_T("{CALL INSERT_USER_DAILY_OP(?, %d, %d, %d, %d, %d, %d, %d, %d)}"), pUserDailyOp->ChaosMapTime, pUserDailyOp->UserRankRewardTime, pUserDailyOp->PersonalRankRewardTime, pUserDailyOp->KingWingTime))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::UpdateUserDailyOp(std::string strUserId, uint8 type, int32 sUnixTime) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strUserId.c_str(), strUserId.length()); if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_USER_DAILY_OP(?, %d, %d)}"), type, sUnixTime))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::UpdateRanks() { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(_T("{CALL UPDATE_RANKS}"))) ReportSQLError(m_GameDB->GetError()); } int8 CDBAgent::NationTransfer(std::string strAccountID, uint16 Race1, uint16 Race2, uint16 Race3, uint16 Race4) { int8 bRet = 3; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(string_format(_T("{? = CALL ACCOUNT_NATION_TRANSFER(?,%d,%d,%d,%d)}"),Race1,Race2,Race3,Race4))) ReportSQLError(m_GameDB->GetError()); return bRet; } int8 CDBAgent::YanChar(std::string strAccountID) { int8 bRet = 0; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(_T("{? = CALL ACCOUNT_NATION_CHAR_COUNT(?)}"))) ReportSQLError(m_GameDB->GetError()); return bRet; } int8 CDBAgent::YanCharClan(std::string strAccountID) { int8 bRet = 0; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return false; dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet); dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(_T("{? = CALL ACCOUNT_NATION_CHAR_CLAN(?)}"))) ReportSQLError(m_GameDB->GetError()); return bRet; } /** * @brief Change knight cash is account. * * @param strAccountID Character's Account name. * @param KnightCash Added knight cash amount */ void CDBAgent::UpdateAccountKnightCash(string & strAccountID, uint32 KnightCash) { unique_ptr dbCommand(m_AccountDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, strAccountID.c_str(), strAccountID.length()); if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_KNIGHT_CASH (?, %d)}"), KnightCash))) ReportSQLError(m_AccountDB->GetError()); } void CDBAgent::GetClanUserData(uint16 sClanID, _KNIGHTS_USER & p) { _KNIGHTS_USER * pUser = &p; unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->strUserName.c_str(), pUser->strUserName.length()); if (!dbCommand->Execute(string_format(_T("SELECT Fame, [Level], Class, strMemo, dtUpdateClan FROM USERDATA WHERE Knights = %d AND strUserID = ?"), sClanID))) { ReportSQLError(m_GameDB->GetError()); return; } if (!dbCommand->hasData()) return; int i = 1; dbCommand->FetchByte(i++,pUser->m_sFame); dbCommand->FetchByte(i++,pUser->m_bLevel); dbCommand->FetchUInt16(i++, pUser->m_sClass); dbCommand->FetchString(i++, pUser->strUserMemo); dbCommand->FetchUInt32(i++, pUser->m_lastLogined); return; } void CDBAgent::UpdateSiege(int16 m_sCastleIndex, int16 m_sMasterKnights, int16 m_bySiegeType, int16 m_byWarDay, int16 m_byWarTime, int16 m_byWarMinute) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (!dbCommand->Execute(string_format(_T("{CALL UPDATE_SIEGE (%d, %d, %d, %d, %d, %d)}"), m_sCastleIndex, m_sMasterKnights, m_bySiegeType, m_byWarDay, m_byWarTime, m_byWarMinute))) ReportSQLError(m_AccountDB->GetError()); } void CDBAgent::UpdateSiegeTax(uint8 Zone, int16 ZoneTarrif) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (Zone == ZONE_DELOS) { if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS_SIEGE_WARFARE SET sDellosTariff = %d"), ZoneTarrif))) ReportSQLError(m_GameDB->GetError()); } else if (Zone == ZONE_MORADON) { if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS_SIEGE_WARFARE SET sMoradonTariff = %d"), ZoneTarrif))) ReportSQLError(m_GameDB->GetError()); } else if (Zone == 0) { if (!dbCommand->Execute(string_format(_T("UPDATE KNIGHTS_SIEGE_WARFARE SET nDungeonCharge = 0, nMoradonTax = 0, nDellosTax = 0")))) ReportSQLError(m_GameDB->GetError()); } } void CDBAgent::InsertRepurchase(uint32 nItemID, time_t RepTime, uint64 nSerial, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (pUser == nullptr || pUser->m_bLogout) return; ByteBuffer rSerial; rSerial << nSerial; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); dbCommand->AddParameter(SQL_PARAM_INPUT, (char *)rSerial.contents(), rSerial.size(), SQL_BINARY); if (!dbCommand->Execute(string_format(_T("{CALL INSERT_REPURCHASE(?, %d, %d, ?)}"), nItemID, RepTime))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::DeleteRepurchase(uint32 nItemID, time_t RepTime, CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (pUser == nullptr || pUser->m_bLogout) return; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); if (!dbCommand->Execute(string_format(_T("DELETE FROM REPURCHASE_ITEMS WHERE strUserID = ? and nItemID = %d and nRepTime = %d"), nItemID, RepTime))) ReportSQLError(m_GameDB->GetError()); } void CDBAgent::LoadRepurchase(CUser *pUser) { unique_ptr dbCommand(m_GameDB->CreateCommand()); if (dbCommand.get() == nullptr) return; if (pUser == nullptr || pUser->m_bLogout) return; dbCommand->AddParameter(SQL_PARAM_INPUT, pUser->m_strUserID.c_str(), pUser->m_strUserID.length()); if (!dbCommand->Execute(_T("SELECT nItemID, nRepTime FROM REPURCHASE_ITEMS WHERE strUserID = ? ORDER BY nRepTime ASC"))) ReportSQLError(m_GameDB->GetError()); pUser->m_RepurchaseMap.clear(); uint32 rCount = 1, rTime, rItemID;; if (dbCommand->hasData()) { do { dbCommand->FetchUInt32(1, rItemID); dbCommand->FetchUInt32(2, rTime); if (rTime <= UNIXTIME) { DeleteRepurchase(rItemID, rTime, pUser); continue; } _ITEM_REPURCHASE * rItem = new _ITEM_REPURCHASE; rItem->nNum = rItemID; rItem->tRepTime = rTime; pUser->m_RepurchaseMap.insert(std::make_pair(rCount, rItem)); rCount++; } while (dbCommand->MoveNext()); } }