/** * Tibia GIMUD Server - a free and open-source MMORPG server emulator * Copyright (C) 2019 Sabrehaven and Mark Samman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "otpch.h" #include "iologindata.h" #include "configmanager.h" #include "game.h" extern ConfigManager g_config; extern Game g_game; Account IOLoginData::loadAccount(uint32_t accno) { Account account; std::ostringstream query; query << "SELECT `id`, `name`, `password`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `id` = " << accno; DBResult_ptr result = Database::getInstance()->storeQuery(query.str()); if (!result) { return account; } account.id = result->getNumber("id"); account.name = result->getNumber("name"); account.accountType = static_cast(result->getNumber("type")); account.premiumDays = result->getNumber("premdays"); account.lastDay = result->getNumber("lastday"); return account; } bool IOLoginData::saveAccount(const Account& acc) { std::ostringstream query; query << "UPDATE `accounts` SET `premdays` = " << acc.premiumDays << ", `lastday` = " << acc.lastDay << " WHERE `id` = " << acc.id; return Database::getInstance()->executeQuery(query.str()); } bool IOLoginData::loginserverAuthentication(uint32_t accountName, const std::string& password, Account& account) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `id`, `name`, `password`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `name` = " << accountName; DBResult_ptr result = db->storeQuery(query.str()); if (!result) { return false; } if (transformToSHA1(password) != result->getString("password")) { return false; } account.id = result->getNumber("id"); account.name = result->getNumber("name"); account.accountType = static_cast(result->getNumber("type")); account.premiumDays = result->getNumber("premdays"); account.lastDay = result->getNumber("lastday"); query.str(std::string()); query << "SELECT `name`, `deletion` FROM `players` WHERE `account_id` = " << account.id; result = db->storeQuery(query.str()); if (result) { do { if (result->getNumber("deletion") == 0) { account.characters.push_back(result->getString("name")); } } while (result->next()); std::sort(account.characters.begin(), account.characters.end()); } return true; } uint32_t IOLoginData::gameworldAuthentication(uint32_t accountName, const std::string& password, std::string& characterName) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `id`, `password` FROM `accounts` WHERE `name` = " << accountName; DBResult_ptr result = db->storeQuery(query.str()); if (!result) { return 0; } if (transformToSHA1(password) != result->getString("password")) { return 0; } uint32_t accountId = result->getNumber("id"); query.str(std::string()); query << "SELECT `account_id`, `name`, `deletion` FROM `players` WHERE `name` = " << db->escapeString(characterName); result = db->storeQuery(query.str()); if (!result) { return 0; } if (result->getNumber("account_id") != accountId || result->getNumber("deletion") != 0) { return 0; } characterName = result->getString("name"); return accountId; } AccountType_t IOLoginData::getAccountType(uint32_t accountId) { std::ostringstream query; query << "SELECT `type` FROM `accounts` WHERE `id` = " << accountId; DBResult_ptr result = Database::getInstance()->storeQuery(query.str()); if (!result) { return ACCOUNT_TYPE_NORMAL; } return static_cast(result->getNumber("type")); } void IOLoginData::setAccountType(uint32_t accountId, AccountType_t accountType) { std::ostringstream query; query << "UPDATE `accounts` SET `type` = " << static_cast(accountType) << " WHERE `id` = " << accountId; Database::getInstance()->executeQuery(query.str()); } void IOLoginData::updateOnlineStatus(uint32_t guid, bool login) { if (g_config.getBoolean(ConfigManager::ALLOW_CLONES)) { return; } std::ostringstream query; if (login) { query << "INSERT INTO `players_online` VALUES (" << guid << ')'; } else { query << "DELETE FROM `players_online` WHERE `player_id` = " << guid; } Database::getInstance()->executeQuery(query.str()); } bool IOLoginData::preloadPlayer(Player* player, const std::string& name) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `id`, `account_id`, `group_id`, `deletion`, (SELECT `type` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `account_type`"; if (!g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { query << ", (SELECT `premdays` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `premium_days`"; } query << " FROM `players` WHERE `name` = " << db->escapeString(name); DBResult_ptr result = db->storeQuery(query.str()); if (!result) { return false; } if (result->getNumber("deletion") != 0) { return false; } player->setGUID(result->getNumber("id")); Group* group = g_game.groups.getGroup(result->getNumber("group_id")); if (!group) { std::cout << "[Error - IOLoginData::preloadPlayer] " << player->name << " has Group ID " << result->getNumber("group_id") << " which doesn't exist." << std::endl; return false; } player->setGroup(group); player->accountNumber = result->getNumber("account_id"); player->accountType = static_cast(result->getNumber("account_type")); if (!g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { player->premiumDays = result->getNumber("premium_days"); } else { player->premiumDays = std::numeric_limits::max(); } return true; } bool IOLoginData::loadPlayerById(Player* player, uint32_t id) { std::ostringstream query; query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id; return loadPlayer(player, Database::getInstance()->storeQuery(query.str())); } bool IOLoginData::loadPlayerByName(Player* player, const std::string& name) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name); return loadPlayer(player, db->storeQuery(query.str())); } bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result) { if (!result) { return false; } Database* db = Database::getInstance(); uint32_t accno = result->getNumber("account_id"); Account acc = loadAccount(accno); player->setGUID(result->getNumber("id")); player->name = result->getString("name"); player->accountNumber = accno; player->accountType = acc.accountType; if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { player->premiumDays = std::numeric_limits::max(); } else { player->premiumDays = acc.premiumDays; } Group* group = g_game.groups.getGroup(result->getNumber("group_id")); if (!group) { std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Group ID " << result->getNumber("group_id") << " which doesn't exist" << std::endl; return false; } player->setGroup(group); player->bankBalance = result->getNumber("balance"); player->setSex(static_cast(result->getNumber("sex"))); player->level = std::max(1, result->getNumber("level")); uint64_t experience = result->getNumber("experience"); uint64_t currExpCount = Player::getExpForLevel(player->level); uint64_t nextExpCount = Player::getExpForLevel(player->level + 1); if (experience < currExpCount || experience > nextExpCount) { experience = currExpCount; } player->experience = experience; if (currExpCount < nextExpCount) { player->levelPercent = Player::getPercentLevel(player->experience - currExpCount, nextExpCount - currExpCount); } else { player->levelPercent = 0; } player->soul = result->getNumber("soul"); player->capacity = std::max(400, result->getNumber("cap")) * 100; player->blessings = result->getNumber("blessings"); unsigned long conditionsSize; const char* conditions = result->getStream("conditions", conditionsSize); PropStream propStream; propStream.init(conditions, conditionsSize); Condition* condition = Condition::createCondition(propStream); while (condition) { if (condition->unserialize(propStream)) { player->storedConditionList.push_front(condition); } else { delete condition; } condition = Condition::createCondition(propStream); } if (!player->setVocation(result->getNumber("vocation"))) { std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Vocation ID " << result->getNumber("vocation") << " which doesn't exist" << std::endl; return false; } player->mana = result->getNumber("mana"); player->manaMax = result->getNumber("manamax"); player->magLevel = result->getNumber("maglevel"); uint64_t nextManaCount = player->vocation->getReqMana(player->magLevel + 1); uint64_t manaSpent = result->getNumber("manaspent"); if (manaSpent > nextManaCount) { manaSpent = 0; } player->manaSpent = manaSpent; player->magLevelPercent = Player::getPercentLevel(player->manaSpent, nextManaCount); player->health = result->getNumber("health"); player->healthMax = result->getNumber("healthmax"); player->defaultOutfit.lookType = result->getNumber("looktype"); player->defaultOutfit.lookHead = result->getNumber("lookhead"); player->defaultOutfit.lookBody = result->getNumber("lookbody"); player->defaultOutfit.lookLegs = result->getNumber("looklegs"); player->defaultOutfit.lookFeet = result->getNumber("lookfeet"); player->defaultOutfit.lookAddons = result->getNumber("lookaddons"); player->currentOutfit = player->defaultOutfit; if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) { player->playerKillerEnd = result->getNumber("skulltime"); uint16_t skull = result->getNumber("skull"); if (skull == SKULL_RED) { player->skull = SKULL_RED; } if (player->playerKillerEnd == 0) { player->skull = SKULL_NONE; } } player->loginPosition.x = result->getNumber("posx"); player->loginPosition.y = result->getNumber("posy"); player->loginPosition.z = result->getNumber("posz"); player->lastLoginSaved = result->getNumber("lastlogin"); player->lastLogout = result->getNumber("lastlogout"); Town* town = g_game.map.towns.getTown(result->getNumber("town_id")); if (!town) { std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Town ID " << result->getNumber("town_id") << " which doesn't exist" << std::endl; return false; } player->town = town; const Position& loginPos = player->loginPosition; if (loginPos.x == 0 && loginPos.y == 0 && loginPos.z == 0) { player->loginPosition = player->getTemplePosition(); } player->staminaMinutes = result->getNumber("stamina"); static const std::string skillNames[] = {"skill_fist", "skill_club", "skill_sword", "skill_axe", "skill_dist", "skill_shielding", "skill_fishing"}; static const std::string skillNameTries[] = {"skill_fist_tries", "skill_club_tries", "skill_sword_tries", "skill_axe_tries", "skill_dist_tries", "skill_shielding_tries", "skill_fishing_tries"}; static constexpr size_t size = sizeof(skillNames) / sizeof(std::string); for (uint8_t i = 0; i < size; ++i) { uint16_t skillLevel = result->getNumber(skillNames[i]); uint64_t skillTries = result->getNumber(skillNameTries[i]); uint64_t nextSkillTries = player->vocation->getReqSkillTries(i, skillLevel + 1); if (skillTries > nextSkillTries) { skillTries = 0; } player->skills[i].level = skillLevel; player->skills[i].tries = skillTries; player->skills[i].percent = Player::getPercentLevel(skillTries, nextSkillTries); } std::ostringstream query; query << "SELECT `date` FROM `player_murders` WHERE `player_id` = " << player->getGUID() << " ORDER BY `date` ASC"; if ((result = db->storeQuery(query.str()))) { do { player->murderTimeStamps.push_back(result->getNumber("date")); } while (result->next()); } query.str(std::string()); query << "SELECT `guild_id`, `rank_id`, `nick` FROM `guild_membership` WHERE `player_id` = " << player->getGUID(); if ((result = db->storeQuery(query.str()))) { uint32_t guildId = result->getNumber("guild_id"); uint32_t playerRankId = result->getNumber("rank_id"); player->guildNick = result->getString("nick"); Guild* guild = g_game.getGuild(guildId); if (!guild) { query.str(std::string()); query << "SELECT `name` FROM `guilds` WHERE `id` = " << guildId; if ((result = db->storeQuery(query.str()))) { guild = new Guild(guildId, result->getString("name")); g_game.addGuild(guild); query.str(std::string()); query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `guild_id` = " << guildId; if ((result = db->storeQuery(query.str()))) { do { guild->addRank(result->getNumber("id"), result->getString("name"), result->getNumber("level")); } while (result->next()); } } } if (guild) { player->guild = guild; const GuildRank* rank = guild->getRankById(playerRankId); if (!rank) { query.str(std::string()); query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `id` = " << playerRankId; if ((result = db->storeQuery(query.str()))) { guild->addRank(result->getNumber("id"), result->getString("name"), result->getNumber("level")); } rank = guild->getRankById(playerRankId); if (!rank) { player->guild = nullptr; } } player->guildRank = rank; IOGuild::getWarList(guildId, player->guildWarList); query.str(std::string()); query << "SELECT COUNT(*) AS `members` FROM `guild_membership` WHERE `guild_id` = " << guildId; if ((result = db->storeQuery(query.str()))) { guild->setMemberCount(result->getNumber("members")); } } } query.str(std::string()); query << "SELECT `player_id`, `name` FROM `player_spells` WHERE `player_id` = " << player->getGUID(); if ((result = db->storeQuery(query.str()))) { do { player->learnedInstantSpellList.emplace_front(result->getString("name")); } while (result->next()); } //load inventory items ItemMap itemMap; query.str(std::string()); query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_items` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC"; if ((result = db->storeQuery(query.str()))) { loadItems(itemMap, result); for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) { const std::pair& pair = it->second; Item* item = pair.first; int32_t pid = pair.second; if (pid >= 1 && pid <= 10) { player->internalAddThing(pid, item); } else { ItemMap::const_iterator it2 = itemMap.find(pid); if (it2 == itemMap.end()) { continue; } Container* container = it2->second.first->getContainer(); if (container) { container->internalAddThing(item); } } } } //load depot items itemMap.clear(); query.str(std::string()); query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_depotitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC"; if ((result = db->storeQuery(query.str()))) { loadItems(itemMap, result); for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) { const std::pair& pair = it->second; Item* item = pair.first; int32_t pid = pair.second; if (pid >= 0 && pid < 100) { Container* itemContainer = item->getContainer(); if (itemContainer) { DepotLocker* locker = itemContainer->getDepotLocker(); if (locker) { DepotLocker* existingLocker = player->getDepotLocker(pid, false); if (!existingLocker) { player->depotLockerMap[pid] = locker; } } } } else { ItemMap::const_iterator it2 = itemMap.find(pid); if (it2 == itemMap.end()) { continue; } Container* container = it2->second.first->getContainer(); if (container) { container->internalAddThing(item); } } } } //load storage map query.str(std::string()); query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID(); if ((result = db->storeQuery(query.str()))) { do { player->addStorageValue(result->getNumber("key"), result->getNumber("value")); } while (result->next()); } //load vip query.str(std::string()); query << "SELECT `player_id` FROM `account_viplist` WHERE `account_id` = " << player->getAccount(); if ((result = db->storeQuery(query.str()))) { do { player->addVIPInternal(result->getNumber("player_id")); } while (result->next()); } player->updateBaseSpeed(); player->updateInventoryWeight(); player->updateItemsLight(true); return true; } bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList, DBInsert& query_insert, PropWriteStream& propWriteStream) { std::ostringstream ss; typedef std::pair containerBlock; std::list queue; int32_t runningId = 100; Database* db = Database::getInstance(); for (const auto& it : itemList) { int32_t pid = it.first; Item* item = it.second; ++runningId; propWriteStream.clear(); item->serializeAttr(propWriteStream); size_t attributesSize; const char* attributes = propWriteStream.getStream(attributesSize); ss << player->getGUID() << ',' << pid << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db->escapeBlob(attributes, attributesSize); if (!query_insert.addRow(ss)) { return false; } if (Container* container = item->getContainer()) { queue.emplace_back(container, runningId); } } while (!queue.empty()) { const containerBlock& cb = queue.front(); Container* container = cb.first; int32_t parentId = cb.second; queue.pop_front(); for (Item* item : container->getItemList()) { ++runningId; Container* subContainer = item->getContainer(); if (subContainer) { queue.emplace_back(subContainer, runningId); } propWriteStream.clear(); item->serializeAttr(propWriteStream); size_t attributesSize; const char* attributes = propWriteStream.getStream(attributesSize); ss << player->getGUID() << ',' << parentId << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db->escapeBlob(attributes, attributesSize); if (!query_insert.addRow(ss)) { return false; } } } return query_insert.execute(); } bool IOLoginData::savePlayer(Player* player) { if (player->getHealth() <= 0) { player->changeHealth(1); } Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `save` FROM `players` WHERE `id` = " << player->getGUID(); DBResult_ptr result = db->storeQuery(query.str()); if (!result) { return false; } if (result->getNumber("save") == 0) { query.str(std::string()); query << "UPDATE `players` SET `lastlogin` = " << player->lastLoginSaved << ", `lastip` = " << player->lastIP << " WHERE `id` = " << player->getGUID(); return db->executeQuery(query.str()); } //serialize conditions PropWriteStream propWriteStream; for (Condition* condition : player->conditions) { if (condition->isPersistent()) { condition->serialize(propWriteStream); propWriteStream.write(CONDITIONATTR_END); } } size_t conditionsSize; const char* conditions = propWriteStream.getStream(conditionsSize); //First, an UPDATE query to write the player itself query.str(std::string()); query << "UPDATE `players` SET "; query << "`level` = " << player->level << ','; query << "`group_id` = " << player->group->id << ','; query << "`vocation` = " << player->getVocationId() << ','; query << "`health` = " << player->health << ','; query << "`healthmax` = " << player->healthMax << ','; query << "`experience` = " << player->experience << ','; query << "`lookbody` = " << static_cast(player->defaultOutfit.lookBody) << ','; query << "`lookfeet` = " << static_cast(player->defaultOutfit.lookFeet) << ','; query << "`lookhead` = " << static_cast(player->defaultOutfit.lookHead) << ','; query << "`looklegs` = " << static_cast(player->defaultOutfit.lookLegs) << ','; query << "`looktype` = " << player->defaultOutfit.lookType << ','; query << "`lookaddons` = " << static_cast(player->defaultOutfit.lookAddons) << ','; query << "`maglevel` = " << player->magLevel << ','; query << "`mana` = " << player->mana << ','; query << "`manamax` = " << player->manaMax << ','; query << "`manaspent` = " << player->manaSpent << ','; query << "`soul` = " << static_cast(player->soul) << ','; query << "`town_id` = " << player->town->getID() << ','; const Position& loginPosition = player->getLoginPosition(); query << "`posx` = " << loginPosition.getX() << ','; query << "`posy` = " << loginPosition.getY() << ','; query << "`posz` = " << loginPosition.getZ() << ','; query << "`cap` = " << (player->capacity / 100) << ','; query << "`sex` = " << player->sex << ','; if (player->lastLoginSaved != 0) { query << "`lastlogin` = " << player->lastLoginSaved << ','; } if (player->lastIP != 0) { query << "`lastip` = " << player->lastIP << ','; } query << "`conditions` = " << db->escapeBlob(conditions, conditionsSize) << ','; if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) { query << "`skulltime` = " << player->getPlayerKillerEnd() << ','; Skulls_t skull = SKULL_NONE; if (player->skull == SKULL_RED) { skull = SKULL_RED; } query << "`skull` = " << static_cast(skull) << ','; } query << "`lastlogout` = " << player->getLastLogout() << ','; query << "`balance` = " << player->bankBalance << ','; query << "`stamina` = " << player->getStaminaMinutes() << ','; query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ','; query << "`skill_fist_tries` = " << player->skills[SKILL_FIST].tries << ','; query << "`skill_club` = " << player->skills[SKILL_CLUB].level << ','; query << "`skill_club_tries` = " << player->skills[SKILL_CLUB].tries << ','; query << "`skill_sword` = " << player->skills[SKILL_SWORD].level << ','; query << "`skill_sword_tries` = " << player->skills[SKILL_SWORD].tries << ','; query << "`skill_axe` = " << player->skills[SKILL_AXE].level << ','; query << "`skill_axe_tries` = " << player->skills[SKILL_AXE].tries << ','; query << "`skill_dist` = " << player->skills[SKILL_DISTANCE].level << ','; query << "`skill_dist_tries` = " << player->skills[SKILL_DISTANCE].tries << ','; query << "`skill_shielding` = " << player->skills[SKILL_SHIELD].level << ','; query << "`skill_shielding_tries` = " << player->skills[SKILL_SHIELD].tries << ','; query << "`skill_fishing` = " << player->skills[SKILL_FISHING].level << ','; query << "`skill_fishing_tries` = " << player->skills[SKILL_FISHING].tries << ','; if (!player->isOffline()) { query << "`onlinetime` = `onlinetime` + " << (time(nullptr) - player->lastLoginSaved) << ','; } query << "`blessings` = " << static_cast(player->blessings); query << " WHERE `id` = " << player->getGUID(); DBTransaction transaction; if (!transaction.begin()) { return false; } if (!db->executeQuery(query.str())) { return false; } // learned spells query.str(std::string()); query << "DELETE FROM `player_spells` WHERE `player_id` = " << player->getGUID(); if (!db->executeQuery(query.str())) { return false; } query.str(std::string()); DBInsert spellsQuery("INSERT INTO `player_spells` (`player_id`, `name` ) VALUES "); for (const std::string& spellName : player->learnedInstantSpellList) { query << player->getGUID() << ',' << db->escapeString(spellName); if (!spellsQuery.addRow(query)) { return false; } } if (!spellsQuery.execute()) { return false; } query.str(std::string()); query << "DELETE FROM `player_murders` WHERE `player_id` = " << player->getGUID(); if (!db->executeQuery(query.str())) { return false; } query.str(std::string()); DBInsert murdersQuery("INSERT INTO `player_murders`(`id`, `player_id`, `date`) VALUES "); for (time_t timestamp : player->murderTimeStamps) { query << "NULL," << player->getGUID() << ',' << timestamp; if (!murdersQuery.addRow(query)) { return false; } } if (!murdersQuery.execute()) { return false; } //item saving query.str(std::string()); query << "DELETE FROM `player_items` WHERE `player_id` = " << player->getGUID(); if (!db->executeQuery(query.str())) { return false; } DBInsert itemsQuery("INSERT INTO `player_items` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES "); ItemBlockList itemList; for (int32_t slotId = 1; slotId <= 10; ++slotId) { Item* item = player->inventory[slotId]; if (item) { itemList.emplace_back(slotId, item); } } if (!saveItems(player, itemList, itemsQuery, propWriteStream)) { return false; } //save depot items query.str(std::string()); query << "DELETE FROM `player_depotitems` WHERE `player_id` = " << player->getGUID(); if (!db->executeQuery(query.str())) { return false; } DBInsert depotQuery("INSERT INTO `player_depotitems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES "); itemList.clear(); for (const auto& it : player->depotLockerMap) { itemList.emplace_back(it.first, it.second); } if (!saveItems(player, itemList, depotQuery, propWriteStream)) { return false; } query.str(std::string()); query << "DELETE FROM `player_storage` WHERE `player_id` = " << player->getGUID(); if (!db->executeQuery(query.str())) { return false; } query.str(std::string()); DBInsert storageQuery("INSERT INTO `player_storage` (`player_id`, `key`, `value`) VALUES "); player->genReservedStorageRange(); for (const auto& it : player->storageMap) { query << player->getGUID() << ',' << it.first << ',' << it.second; if (!storageQuery.addRow(query)) { return false; } } if (!storageQuery.execute()) { return false; } //End the transaction return transaction.commit(); } std::string IOLoginData::getNameByGuid(uint32_t guid) { std::ostringstream query; query << "SELECT `name` FROM `players` WHERE `id` = " << guid; DBResult_ptr result = Database::getInstance()->storeQuery(query.str()); if (!result) { return std::string(); } return result->getString("name"); } uint32_t IOLoginData::getGuidByName(const std::string& name) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `players` WHERE `name` = " << db->escapeString(name); DBResult_ptr result = db->storeQuery(query.str()); if (!result) { return 0; } return result->getNumber("id"); } bool IOLoginData::getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `name`, `id`, `group_id`, `account_id` FROM `players` WHERE `name` = " << db->escapeString(name); DBResult_ptr result = db->storeQuery(query.str()); if (!result) { return false; } name = result->getString("name"); guid = result->getNumber("id"); Group* group = g_game.groups.getGroup(result->getNumber("group_id")); uint64_t flags; if (group) { flags = group->flags; } else { flags = 0; } specialVip = (flags & PlayerFlag_SpecialVIP) != 0; return true; } bool IOLoginData::formatPlayerName(std::string& name) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `name` FROM `players` WHERE `name` = " << db->escapeString(name); DBResult_ptr result = db->storeQuery(query.str()); if (!result) { return false; } name = result->getString("name"); return true; } void IOLoginData::loadItems(ItemMap& itemMap, DBResult_ptr result) { do { uint32_t sid = result->getNumber("sid"); uint32_t pid = result->getNumber("pid"); uint16_t type = result->getNumber("itemtype"); uint16_t count = result->getNumber("count"); unsigned long attrSize; const char* attr = result->getStream("attributes", attrSize); PropStream propStream; propStream.init(attr, attrSize); Item* item = Item::CreateItem(type, count); if (item) { if (!item->unserializeAttr(propStream)) { std::cout << "WARNING: Serialize error in IOLoginData::loadItems" << std::endl; } std::pair pair(item, pid); itemMap[sid] = pair; } } while (result->next()); } void IOLoginData::increaseBankBalance(uint32_t guid, uint64_t bankBalance) { std::ostringstream query; query << "UPDATE `players` SET `balance` = `balance` + " << bankBalance << " WHERE `id` = " << guid; Database::getInstance()->executeQuery(query.str()); } bool IOLoginData::hasBiddedOnHouse(uint32_t guid) { Database* db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `houses` WHERE `highest_bidder` = " << guid << " LIMIT 1"; return db->storeQuery(query.str()).get() != nullptr; } std::forward_list IOLoginData::getVIPEntries(uint32_t accountId) { std::forward_list entries; std::ostringstream query; query << "SELECT `player_id`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `name` FROM `account_viplist` WHERE `account_id` = " << accountId; DBResult_ptr result = Database::getInstance()->storeQuery(query.str()); if (result) { do { entries.emplace_front( result->getNumber("player_id"), result->getString("name") ); } while (result->next()); } return entries; } void IOLoginData::addVIPEntry(uint32_t accountId, uint32_t guid) { Database* db = Database::getInstance(); std::ostringstream query; query << "INSERT INTO `account_viplist` (`account_id`, `player_id`) VALUES (" << accountId << ',' << guid << ')'; db->executeQuery(query.str()); } void IOLoginData::removeVIPEntry(uint32_t accountId, uint32_t guid) { std::ostringstream query; query << "DELETE FROM `account_viplist` WHERE `account_id` = " << accountId << " AND `player_id` = " << guid; Database::getInstance()->executeQuery(query.str()); } void IOLoginData::addPremiumDays(uint32_t accountId, int32_t addDays) { std::ostringstream query; query << "UPDATE `accounts` SET `premdays` = `premdays` + " << addDays << " WHERE `id` = " << accountId; Database::getInstance()->executeQuery(query.str()); } void IOLoginData::removePremiumDays(uint32_t accountId, int32_t removeDays) { std::ostringstream query; query << "UPDATE `accounts` SET `premdays` = `premdays` - " << removeDays << " WHERE `id` = " << accountId; Database::getInstance()->executeQuery(query.str()); }