diff --git a/config.lua.dist b/config.lua.dist index 9a2fa89fe..de9f5f785 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -12,6 +12,15 @@ coreDirectory = "data" -- NOTE: Will only display logs with level higher or equal the one set. logLevel = "info" +--- Toggles the server's maintenance mode. +-- When enabled, it restricts user access and indicates maintenance operations. +-- @field [parent=#global] #boolean toggleMaintainMode false by default, set to true to enable maintenance mode. +toggleMaintainMode = false +--- Message displayed during maintenance mode. +-- Should inform the expected downtime or resumption details succinctly. +-- @field [parent=#global] #string maintainModeMessage an empty string by default, set a custom message if needed. +maintainModeMessage = "" + -- Combat settings -- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced" worldType = "pvp" diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 3af622c82..da5251605 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -89,8 +89,14 @@ int CanaryServer::run() { g_game().start(&serviceManager); g_game().setGameState(GAME_STATE_NORMAL); - - g_webhook().sendMessage("Server is now online", "Server has successfully started.", WEBHOOK_COLOR_ONLINE); + if (g_configManager().getBoolean(TOGGLE_MAINTAIN_MODE)) { + g_game().setGameState(GAME_STATE_CLOSED); + g_logger().warn("Initialized in maintain mode!"); + g_webhook().sendMessage("Server is now online", "The server is now online. Access is currently restricted to administrators only.", WEBHOOK_COLOR_ONLINE); + } else { + g_game().setGameState(GAME_STATE_NORMAL); + g_webhook().sendMessage("Server is now online", "Server has successfully started.", WEBHOOK_COLOR_ONLINE); + } loaderStatus = LoaderStatus::LOADED; } catch (FailedToInitializeCanary &err) { diff --git a/src/config/config_definitions.hpp b/src/config/config_definitions.hpp index d3bf0b87e..1704b3075 100644 --- a/src/config/config_definitions.hpp +++ b/src/config/config_definitions.hpp @@ -82,16 +82,14 @@ enum booleanConfig_t { RESET_SESSIONS_ON_STARTUP, TOGGLE_WHEELSYSTEM, TOGGLE_ATTACK_SPEED_ONFIST, - VIP_SYSTEM_ENABLED, VIP_AUTOLOOT_VIP_ONLY, VIP_STAY_ONLINE, - REWARD_CHEST_COLLECT_ENABLED, TOGGLE_MOUNT_IN_PZ, TOGGLE_HOUSE_TRANSFER_ON_SERVER_RESTART, - TOGGLE_RECEIVE_REWARD, + TOGGLE_MAINTAIN_MODE, LAST_BOOLEAN_CONFIG }; @@ -128,6 +126,7 @@ enum stringConfig_t { FORGE_FIENDISH_INTERVAL_TIME, TIBIADROME_CONCOCTION_TICK_TYPE, M_CONST, + MAINTAIN_MODE_MESSAGE, LAST_STRING_CONFIG }; diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index d0abcc935..baf93d769 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -99,6 +99,8 @@ bool ConfigManager::load() { boolean[BIND_ONLY_GLOBAL_ADDRESS] = getGlobalBoolean(L, "bindOnlyGlobalAddress", false); boolean[OPTIMIZE_DATABASE] = getGlobalBoolean(L, "startupDatabaseOptimization", true); boolean[TOGGLE_MAP_CUSTOM] = getGlobalBoolean(L, "toggleMapCustom", true); + boolean[TOGGLE_MAINTAIN_MODE] = getGlobalBoolean(L, "toggleMaintainMode", false); + string[MAINTAIN_MODE_MESSAGE] = getGlobalString(L, "maintainModeMessage", ""); string[IP] = getGlobalString(L, "ip", "127.0.0.1"); string[MAP_NAME] = getGlobalString(L, "mapName", "canary"); diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 38f2c5de2..9a80ad55c 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -1311,7 +1311,7 @@ std::vector>> Combat::pickChainTargets std::vector>> resultMap; std::vector> targets; - std::set visited; + phmap::flat_hash_set visited; if (initialTarget && initialTarget != caster) { targets.push_back(initialTarget); diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 7058753ac..c29fe9067 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -142,10 +142,8 @@ void Creature::onThink(uint32_t interval) { }; if (isUpdatingPath) { - g_dispatcher().asyncEvent([self = getCreature(), onThink = std::move(onThink)] { - self->isUpdatingPath = false; - self->goToFollowCreature_async(onThink); - }); + isUpdatingPath = false; + goToFollowCreature_async(onThink); return; } @@ -433,9 +431,9 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { if (hasSummons()) { std::vector> despawnMonsterList; for (const auto &summon : getSummons()) { - const Position &pos = summon->getPosition(); - std::shared_ptr monster = summon->getMonster(); - auto tile = getTile(); + const auto &pos = summon->getPosition(); + const auto &monster = summon->getMonster(); + const auto &tile = getTile(); bool protectionZoneCheck = tile ? tile->hasFlag(TILESTATE_PROTECTIONZONE) : false; // Check if any of our summons is out of range (+/- 0 floors or 15 tiles away) bool checkSummonDist = Position::getDistanceZ(newPos, pos) > 0 || (std::max(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 15); @@ -443,12 +441,12 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { bool checkRemoveDist = Position::getDistanceZ(newPos, pos) > 2 || (std::max(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 30); if (monster && monster->isFamiliar() && checkSummonDist || teleportSummon && !protectionZoneCheck && checkSummonDist) { - auto creatureMaster = summon->getMaster(); + const auto &creatureMaster = summon->getMaster(); if (!creatureMaster) { continue; } - if (std::shared_ptr masterTile = creatureMaster->getTile()) { + if (const auto &masterTile = creatureMaster->getTile()) { if (masterTile->hasFlag(TILESTATE_TELEPORT)) { g_logger().warn("[{}] cannot teleport summon, position has teleport. {}", __FUNCTION__, creatureMaster->getPosition().toString()); } else { @@ -463,7 +461,7 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { } } - for (std::shared_ptr despawnCreature : despawnMonsterList) { + for (const auto &despawnCreature : despawnMonsterList) { if (!despawnMonsterList.empty()) { g_game().removeCreature(despawnCreature, true); } @@ -632,6 +630,14 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s void Creature::onDeath() { bool lastHitUnjustified = false; bool mostDamageUnjustified = false; + std::shared_ptr lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); + std::shared_ptr lastHitCreatureMaster; + if (lastHitCreature) { + lastHitUnjustified = lastHitCreature->onKilledCreature(static_self_cast(), true); + lastHitCreatureMaster = lastHitCreature->getMaster(); + } else { + lastHitCreatureMaster = nullptr; + } std::shared_ptr mostDamageCreature = nullptr; @@ -673,15 +679,11 @@ void Creature::onDeath() { it.first->onGainExperience(it.second, getCreature()); } - std::shared_ptr mostDamageCreatureMaster = nullptr; - if (mostDamageCreature) { - mostDamageCreatureMaster = mostDamageCreature->getMaster(); - mostDamageUnjustified = mostDamageCreature->onKilledCreature(getCreature(), false); - } - - std::shared_ptr lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); - if (lastHitCreature && lastHitCreature != mostDamageCreature && lastHitCreature != mostDamageCreatureMaster) { - lastHitUnjustified = lastHitCreature->onKilledCreature(getCreature(), true); + if (mostDamageCreature && mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) { + auto mostDamageCreatureMaster = mostDamageCreature->getMaster(); + if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) { + mostDamageUnjustified = mostDamageCreature->onKilledCreature(static_self_cast(), false); + } } bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified); @@ -1245,13 +1247,16 @@ bool Creature::setMaster(std::shared_ptr newMaster, bool reloadCreatur g_game().reloadCreature(self); } if (newMaster) { - newMaster->m_summons.insert(self); + newMaster->m_summons.emplace_back(self); } m_master = newMaster; if (oldMaster) { - oldMaster->m_summons.erase(self); + const auto &it = std::ranges::find(oldMaster->m_summons, self); + if (it != oldMaster->m_summons.end()) { + oldMaster->m_summons.erase(it); + } } return true; } @@ -1798,9 +1803,8 @@ void Creature::setIncreasePercent(CombatType_t combat, int32_t value) { } } -phmap::flat_hash_set> Creature::getZones() { - auto tile = getTile(); - if (tile) { +std::unordered_set> Creature::getZones() { + if (const auto &tile = getTile()) { return tile->getZones(); } return {}; diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index 5e03e33d7..e6e8e005e 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -267,7 +267,7 @@ class Creature : virtual public Thing, public SharedObject { return ZONE_NORMAL; } - phmap::flat_hash_set> getZones(); + std::unordered_set> getZones(); // walk functions void startAutoWalk(const std::vector &listDir, bool ignoreConditions = false); @@ -341,7 +341,7 @@ class Creature : virtual public Thing, public SharedObject { return m_master.lock(); } - const phmap::flat_hash_set> &getSummons() const { + const auto &getSummons() const { return m_summons; } @@ -666,7 +666,7 @@ class Creature : virtual public Thing, public SharedObject { CountMap damageMap; - phmap::flat_hash_set> m_summons; + std::vector> m_summons; CreatureEventList eventsList; ConditionList conditions; diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp index e6178a4f7..29182fe68 100644 --- a/src/creatures/monsters/monster.hpp +++ b/src/creatures/monsters/monster.hpp @@ -17,7 +17,6 @@ class Creature; class Game; class Spawn; -using CreatureHashSet = phmap::flat_hash_set>; using CreatureList = std::list>; using CreatureWeakHashMap = phmap::flat_hash_map>; @@ -99,7 +98,7 @@ class Monster final : public Creature { if (master && master->getMonster()) { return master->getMonster()->isEnemyFaction(faction); } - return mType->info.enemyFactions.empty() ? false : mType->info.enemyFactions.find(faction) != mType->info.enemyFactions.end(); + return mType->info.enemyFactions.empty() ? false : mType->info.enemyFactions.contains(faction); } bool isPushable() override { @@ -204,17 +203,19 @@ class Monster final : public Creature { } return list; } - CreatureHashSet getFriendList() { - CreatureHashSet set; + + std::vector> getFriendList() { + std::vector> list; + for (auto it = friendList.begin(); it != friendList.end();) { if (auto friendCreature = it->second.lock()) { - set.insert(friendCreature); + list.emplace_back(friendCreature); ++it; } else { it = friendList.erase(it); } } - return set; + return list; } bool isTarget(std::shared_ptr creature); diff --git a/src/creatures/monsters/monsters.hpp b/src/creatures/monsters/monsters.hpp index e0cc79b88..a4723fcaa 100644 --- a/src/creatures/monsters/monsters.hpp +++ b/src/creatures/monsters/monsters.hpp @@ -136,7 +136,7 @@ class MonsterType { bool targetPreferMaster = false; Faction_t faction = FACTION_DEFAULT; - phmap::flat_hash_set enemyFactions; + stdext::vector_set enemyFactions; bool canPushItems = false; bool canPushCreatures = false; diff --git a/src/creatures/npcs/npc.cpp b/src/creatures/npcs/npc.cpp index 2df46c285..431d3113c 100644 --- a/src/creatures/npcs/npc.cpp +++ b/src/creatures/npcs/npc.cpp @@ -151,7 +151,7 @@ void Npc::onPlayerAppear(std::shared_ptr player) { if (player->hasFlag(PlayerFlags_t::IgnoredByNpcs) || playerSpectators.contains(player)) { return; } - playerSpectators.emplace_back(player); + playerSpectators.emplace(player); manageIdle(); } @@ -531,7 +531,7 @@ void Npc::onThinkWalk(uint32_t interval) { void Npc::onCreatureWalk() { Creature::onCreatureWalk(); - playerSpectators.erase_if([this](const auto &creature) { return !this->canSee(creature->getPosition()); }); + phmap::erase_if(playerSpectators, [this](const auto &creature) { return !this->canSee(creature->getPosition()); }); } void Npc::onPlacedCreature() { @@ -542,7 +542,7 @@ void Npc::loadPlayerSpectators() { auto spec = Spectators().find(position, true); for (const auto &creature : spec) { if (!creature->getPlayer()->hasFlag(PlayerFlags_t::IgnoredByNpcs)) { - playerSpectators.emplace_back(creature->getPlayer()); + playerSpectators.emplace(creature->getPlayer()); } } } diff --git a/src/creatures/npcs/npc.hpp b/src/creatures/npcs/npc.hpp index 38cd9840a..993934374 100644 --- a/src/creatures/npcs/npc.hpp +++ b/src/creatures/npcs/npc.hpp @@ -188,7 +188,7 @@ class Npc final : public Creature { bool ignoreHeight; - stdext::vector_set> playerSpectators; + phmap::flat_hash_set> playerSpectators; Position masterPos; friend class LuaScriptInterface; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 1178a666e..d26952bc5 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -484,54 +484,48 @@ uint32_t Player::getClientIcons() { } void Player::addMonsterToCyclopediaTrackerList(const std::shared_ptr mtype, bool isBoss, bool reloadClient /* = false */) { - if (client) { - uint16_t raceId = mtype ? mtype->info.raceid : 0; - // Bostiary tracker logic - if (isBoss) { - m_bosstiaryMonsterTracker.insert(mtype); - if (reloadClient && raceId != 0) { + if (!client) { + return; + } + + const uint16_t raceId = mtype ? mtype->info.raceid : 0; + auto &tracker = isBoss ? m_bosstiaryMonsterTracker : m_bestiaryMonsterTracker; + if (tracker.emplace(mtype).second) { + if (reloadClient && raceId != 0) { + if (isBoss) { client->parseSendBosstiary(); + } else { + client->sendBestiaryEntryChanged(raceId); } - client->refreshCyclopediaMonsterTracker(m_bosstiaryMonsterTracker, true); - return; } - // Bestiary tracker logic - m_bestiaryMonsterTracker.insert(mtype); - if (reloadClient && raceId != 0) { - client->sendBestiaryEntryChanged(raceId); - } - client->refreshCyclopediaMonsterTracker(m_bestiaryMonsterTracker, false); + client->refreshCyclopediaMonsterTracker(tracker, isBoss); } } void Player::removeMonsterFromCyclopediaTrackerList(std::shared_ptr mtype, bool isBoss, bool reloadClient /* = false */) { - if (client) { - uint16_t raceId = mtype ? mtype->info.raceid : 0; - // Bostiary tracker logic - if (isBoss) { - m_bosstiaryMonsterTracker.erase(mtype); - if (reloadClient && raceId != 0) { + if (!client) { + return; + } + + const uint16_t raceId = mtype ? mtype->info.raceid : 0; + auto &tracker = isBoss ? m_bosstiaryMonsterTracker : m_bestiaryMonsterTracker; + + if (tracker.erase(mtype) > 0) { + if (reloadClient && raceId != 0) { + if (isBoss) { client->parseSendBosstiary(); + } else { + client->sendBestiaryEntryChanged(raceId); } - client->refreshCyclopediaMonsterTracker(m_bosstiaryMonsterTracker, true); - return; } - // Bestiary tracker logic - m_bestiaryMonsterTracker.erase(mtype); - if (reloadClient && raceId != 0) { - client->sendBestiaryEntryChanged(raceId); - } - client->refreshCyclopediaMonsterTracker(m_bestiaryMonsterTracker, false); + client->refreshCyclopediaMonsterTracker(tracker, isBoss); } } -bool Player::isBossOnBosstiaryTracker(const std::shared_ptr monsterType) const { - if (!monsterType) { - return false; - } - return m_bosstiaryMonsterTracker.contains(monsterType); +bool Player::isBossOnBosstiaryTracker(const std::shared_ptr &monsterType) const { + return monsterType ? m_bosstiaryMonsterTracker.contains(monsterType) : false; } void Player::updateInventoryWeight() { @@ -2925,7 +2919,7 @@ void Player::removePlayer(bool displayEffect, bool forced /*= true*/) { } } -void Player::notifyStatusChange(std::shared_ptr loginPlayer, VipStatus_t status, bool message) { +void Player::notifyStatusChange(std::shared_ptr loginPlayer, VipStatus_t status, bool message) const { if (!client) { return; } @@ -2989,7 +2983,7 @@ bool Player::addVIPInternal(uint32_t vipGuid) { return VIPList.insert(vipGuid).second; } -bool Player::editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify) { +bool Player::editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify) const { auto it = VIPList.find(vipGuid); if (it == VIPList.end()) { return false; // player is not in VIP diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 2a32a838c..418f8659e 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -304,7 +304,7 @@ class Player final : public Creature, public Cylinder, public Bankable { return guildWarVector; } - const phmap::parallel_flat_hash_set> &getCyclopediaMonsterTrackerSet(bool isBoss) const { + const std::unordered_set> &getCyclopediaMonsterTrackerSet(bool isBoss) const { return isBoss ? m_bosstiaryMonsterTracker : m_bestiaryMonsterTracker; } @@ -318,17 +318,17 @@ class Player final : public Creature, public Cylinder, public Bankable { } } - void refreshCyclopediaMonsterTracker(bool isBoss = false) const { + void refreshCyclopediaMonsterTracker(bool isBoss = false) { refreshCyclopediaMonsterTracker(getCyclopediaMonsterTrackerSet(isBoss), isBoss); } - void refreshCyclopediaMonsterTracker(const phmap::parallel_flat_hash_set> &trackerList, bool isBoss) const { + void refreshCyclopediaMonsterTracker(const std::unordered_set> &trackerList, bool isBoss) const { if (client) { client->refreshCyclopediaMonsterTracker(trackerList, isBoss); } } - bool isBossOnBosstiaryTracker(const std::shared_ptr monsterType) const; + bool isBossOnBosstiaryTracker(const std::shared_ptr &monsterType) const; Vocation* getVocation() const { return vocation; @@ -804,11 +804,11 @@ class Player final : public Creature, public Cylinder, public Bankable { } // V.I.P. functions - void notifyStatusChange(std::shared_ptr player, VipStatus_t status, bool message = true); + void notifyStatusChange(std::shared_ptr player, VipStatus_t status, bool message = true) const; bool removeVIP(uint32_t vipGuid); bool addVIP(uint32_t vipGuid, const std::string &vipName, VipStatus_t status); bool addVIPInternal(uint32_t vipGuid); - bool editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify); + bool editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify) const; // follow functions bool setFollowCreature(std::shared_ptr creature) override; @@ -2502,7 +2502,7 @@ class Player final : public Creature, public Cylinder, public Bankable { } bool checkAutoLoot() const { - const bool autoLoot = g_configManager().getBoolean(AUTOLOOT) && getStorageValue(STORAGEVALUE_AUTO_LOOT) != 0; + const bool autoLoot = g_configManager().getBoolean(AUTOLOOT) && getStorageValue(STORAGEVALUE_AUTO_LOOT) > 0; if (g_configManager().getBoolean(VIP_SYSTEM_ENABLED) && g_configManager().getBoolean(VIP_AUTOLOOT_VIP_ONLY)) { return autoLoot && isVip(); } @@ -2609,7 +2609,6 @@ class Player final : public Creature, public Cylinder, public Bankable { bool onKilledMonster(const std::shared_ptr &target, bool lastHit); phmap::flat_hash_set attackedSet; - phmap::flat_hash_set VIPList; std::map openContainers; @@ -2646,8 +2645,8 @@ class Player final : public Creature, public Cylinder, public Bankable { // TODO: This variable is only temporarily used when logging in, get rid of it somehow. std::forward_list> storedConditionList; - phmap::parallel_flat_hash_set> m_bestiaryMonsterTracker; - phmap::parallel_flat_hash_set> m_bosstiaryMonsterTracker; + std::unordered_set> m_bestiaryMonsterTracker; + std::unordered_set> m_bosstiaryMonsterTracker; std::string name; std::string guildNick; diff --git a/src/game/bank/bank.cpp b/src/game/bank/bank.cpp index 63952e917..f1a700388 100644 --- a/src/game/bank/bank.cpp +++ b/src/game/bank/bank.cpp @@ -97,7 +97,7 @@ bool Bank::transferTo(const std::shared_ptr destination, uint64_t amount) return false; } if (destinationBankable->getPlayer() != nullptr) { - auto player = bankable->getPlayer(); + auto player = destinationBankable->getPlayer(); auto name = asLowerCaseString(player->getName()); replaceString(name, " ", ""); if (deniedNames.contains(name)) { diff --git a/src/game/game.cpp b/src/game/game.cpp index a01ac60bf..64cbf5cec 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -7617,8 +7617,7 @@ void Game::updatePlayerHelpers(std::shared_ptr player) { return; } - uint16_t helpers = player->getHelpers(); - + const uint16_t helpers = player->getHelpers(); for (const auto &spectator : Spectators().find(player->getPosition(), true)) { spectator->getPlayer()->sendCreatureHelpers(player->getID(), helpers); } @@ -9925,25 +9924,28 @@ void Game::setTransferPlayerHouseItems(uint32_t houseId, uint32_t playerId) { } template -phmap::parallel_flat_hash_set setDifference(const phmap::flat_hash_set &setA, const phmap::flat_hash_set &setB) { - phmap::parallel_flat_hash_set setResult; +std::vector setDifference(const std::unordered_set &setA, const std::unordered_set &setB) { + std::vector setResult; + setResult.reserve(setA.size()); + for (const auto &elem : setA) { - if (setB.find(elem) == setB.end()) { - setResult.insert(elem); + if (!setB.contains(elem)) { + setResult.emplace_back(elem); } } + return setResult; } -ReturnValue Game::beforeCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones, bool force /* = false*/) const { +ReturnValue Game::beforeCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones, bool force /* = false*/) const { if (!creature) { return RETURNVALUE_NOTPOSSIBLE; } // fromZones - toZones = zones that creature left - auto zonesLeaving = setDifference(fromZones, toZones); + const auto &zonesLeaving = setDifference(fromZones, toZones); // toZones - fromZones = zones that creature entered - auto zonesEntering = setDifference(toZones, fromZones); + const auto &zonesEntering = setDifference(toZones, fromZones); if (zonesLeaving.empty() && zonesEntering.empty()) { return RETURNVALUE_NOERROR; @@ -9965,15 +9967,15 @@ ReturnValue Game::beforeCreatureZoneChange(std::shared_ptr creature, c return RETURNVALUE_NOERROR; } -void Game::afterCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones) const { +void Game::afterCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones) const { if (!creature) { return; } // fromZones - toZones = zones that creature left - auto zonesLeaving = setDifference(fromZones, toZones); + const auto &zonesLeaving = setDifference(fromZones, toZones); // toZones - fromZones = zones that creature entered - auto zonesEntering = setDifference(toZones, fromZones); + const auto &zonesEntering = setDifference(toZones, fromZones); for (const auto &zone : zonesLeaving) { zone->creatureRemoved(creature); diff --git a/src/game/game.hpp b/src/game/game.hpp index 2b30a31d2..9dbbbca9f 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -557,7 +557,7 @@ class Game { Raids raids; Canary::protobuf::appearances::Appearances appearances; - phmap::flat_hash_set> getTilesToClean() const { + auto getTilesToClean() const { return tilesToClean; } void addTileToClean(std::shared_ptr tile) { @@ -599,11 +599,11 @@ class Game { mapLuaItemsStored[position] = itemId; } - std::set getFiendishMonsters() const { + auto getFiendishMonsters() const { return fiendishMonsters; } - std::set getInfluencedMonsters() const { + auto getInfluencedMonsters() const { return influencedMonsters; } @@ -673,8 +673,8 @@ class Game { */ bool tryRetrieveStashItems(std::shared_ptr player, std::shared_ptr item); - ReturnValue beforeCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones, bool force = false) const; - void afterCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones) const; + ReturnValue beforeCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones, bool force = false) const; + void afterCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones) const; std::unique_ptr &getIOWheel(); const std::unique_ptr &getIOWheel() const; @@ -684,8 +684,8 @@ class Game { private: std::map forgeMonsterEventIds; - std::set fiendishMonsters; - std::set influencedMonsters; + std::unordered_set fiendishMonsters; + std::unordered_set influencedMonsters; void checkImbuements(); bool playerSaySpell(std::shared_ptr player, SpeakClasses type, const std::string &text); void playerWhisper(std::shared_ptr player, const std::string &text); @@ -822,7 +822,7 @@ class Game { std::map> bedSleepersMap; - phmap::flat_hash_set> tilesToClean; + std::unordered_set> tilesToClean; ModalWindow offlineTrainingWindow { std::numeric_limits::max(), "Choose a Skill", "Please choose a skill:" }; diff --git a/src/game/scheduling/events_scheduler.cpp b/src/game/scheduling/events_scheduler.cpp index d5c71378f..fc41f2c8b 100644 --- a/src/game/scheduling/events_scheduler.cpp +++ b/src/game/scheduling/events_scheduler.cpp @@ -28,7 +28,7 @@ bool EventsScheduler::loadScheduleEventFromXml() { // Keep track of loaded scripts to check for duplicates int count = 0; - std::set> loadedScripts; + phmap::flat_hash_set loadedScripts; std::map eventsOnSameDay; for (const auto &eventNode : doc.child("events").children()) { std::string eventScript = eventNode.attribute("script").as_string(); diff --git a/src/game/zones/zone.hpp b/src/game/zones/zone.hpp index 4a0c03180..91fa6f25e 100644 --- a/src/game/zones/zone.hpp +++ b/src/game/zones/zone.hpp @@ -9,7 +9,6 @@ #pragma once -#include #include "game/movement/position.hpp" #include "items/item.hpp" #include "creatures/creature.hpp" diff --git a/src/io/io_bosstiary.cpp b/src/io/io_bosstiary.cpp index e4aecee5f..10c4f2f08 100644 --- a/src/io/io_bosstiary.cpp +++ b/src/io/io_bosstiary.cpp @@ -234,14 +234,13 @@ uint32_t IOBosstiary::calculateBossPoints(uint16_t lootBonus) const { return static_cast((2.5 * lootBonus * lootBonus) - (477.5 * lootBonus) + 24000); } -phmap::parallel_flat_hash_set IOBosstiary::getBosstiaryFinished(std::shared_ptr player, uint8_t level /* = 1*/) const { - phmap::parallel_flat_hash_set unlockedMonsters; +std::vector IOBosstiary::getBosstiaryFinished(const std::shared_ptr &player, uint8_t level /* = 1*/) const { if (!player) { - return unlockedMonsters; + return {}; } - for (std::map bossesMap = getBosstiaryMap(); - const auto &[bossId, bossName] : bossesMap) { + stdext::vector_set unlockedMonsters; + for (const auto &[bossId, bossName] : getBosstiaryMap()) { uint32_t bossKills = player->getBestiaryKillCount(bossId); if (bossKills == 0) { continue; @@ -258,14 +257,14 @@ phmap::parallel_flat_hash_set IOBosstiary::getBosstiaryFinished(std::s const std::vector &infoForCurrentRace = it->second; auto levelKills = infoForCurrentRace.at(level - 1).kills; if (bossKills >= levelKills) { - unlockedMonsters.insert(bossId); + unlockedMonsters.emplace(bossId); } } else { g_logger().warn("[{}] boss with id {} and name {} not found in bossRace", __FUNCTION__, bossId, bossName); } } - return unlockedMonsters; + return unlockedMonsters.data(); } uint8_t IOBosstiary::getBossCurrentLevel(std::shared_ptr player, uint16_t bossId) const { diff --git a/src/io/io_bosstiary.hpp b/src/io/io_bosstiary.hpp index a253be3b4..b491247b2 100644 --- a/src/io/io_bosstiary.hpp +++ b/src/io/io_bosstiary.hpp @@ -63,7 +63,7 @@ class IOBosstiary { void addBosstiaryKill(std::shared_ptr player, const std::shared_ptr mtype, uint32_t amount = 1) const; uint16_t calculateLootBonus(uint32_t bossPoints) const; uint32_t calculateBossPoints(uint16_t lootBonus) const; - phmap::parallel_flat_hash_set getBosstiaryFinished(std::shared_ptr player, uint8_t level = 1) const; + std::vector getBosstiaryFinished(const std::shared_ptr &player, uint8_t level = 1) const; uint8_t getBossCurrentLevel(std::shared_ptr player, uint16_t bossId) const; uint32_t calculteRemoveBoss(uint8_t removeTimes) const; const std::vector &getBossRaceKillStages(BosstiaryRarity_t race) const; diff --git a/src/io/iobestiary.cpp b/src/io/iobestiary.cpp index c9fb933bc..2f66c53ad 100644 --- a/src/io/iobestiary.cpp +++ b/src/io/iobestiary.cpp @@ -227,7 +227,6 @@ void IOBestiary::addBestiaryKill(std::shared_ptr player, const std::shar (curCount < mtype->info.bestiaryFirstUnlock && (curCount + amount) >= mtype->info.bestiaryFirstUnlock) || // First kill stage reached (curCount < mtype->info.bestiarySecondUnlock && (curCount + amount) >= mtype->info.bestiarySecondUnlock) || // Second kill stage reached (curCount < mtype->info.bestiaryToUnlock && (curCount + amount) >= mtype->info.bestiaryToUnlock)) { // Final kill stage reached - ss << "You unlocked details for the creature '" << mtype->name << "'"; player->sendTextMessage(MESSAGE_STATUS, ss.str()); player->sendBestiaryEntryChanged(raceid); @@ -305,7 +304,6 @@ void IOBestiary::sendBuyCharmRune(std::shared_ptr player, charmRune_t ru int32_t value = bitToggle(player->getUnlockedRunesBit(), charm, true); player->setUnlockedRunesBit(value); - } else if (action == 1) { std::list usedRunes = getCharmUsedRuneBitAll(player); uint16_t limitRunes = 0; @@ -396,18 +394,21 @@ std::map IOBestiary::getBestiaryKillCountByMonsterIDs(std::s return raceMonsters; } -phmap::parallel_flat_hash_set IOBestiary::getBestiaryFinished(std::shared_ptr player) const { - phmap::parallel_flat_hash_set finishedMonsters; - auto bestiaryMap = g_game().getBestiaryList(); +std::vector IOBestiary::getBestiaryFinished(const std::shared_ptr &player) const { + const auto &bestiaryMap = g_game().getBestiaryList(); + + stdext::vector_set finishedMonsters; + finishedMonsters.reserve(bestiaryMap.size()); for (const auto &[monsterTypeRaceId, monsterTypeName] : bestiaryMap) { - uint32_t thisKilled = player->getBestiaryKillCount(monsterTypeRaceId); - auto mtype = g_monsters().getMonsterType(monsterTypeName); + const auto &mtype = g_monsters().getMonsterType(monsterTypeName); + const uint32_t thisKilled = player->getBestiaryKillCount(monsterTypeRaceId); + if (mtype && thisKilled >= mtype->info.bestiaryToUnlock) { finishedMonsters.insert(monsterTypeRaceId); } } - return finishedMonsters; + return finishedMonsters.data(); } int8_t IOBestiary::calculateDifficult(uint32_t chance) const { diff --git a/src/io/iobestiary.hpp b/src/io/iobestiary.hpp index 26f802dcb..896e00434 100644 --- a/src/io/iobestiary.hpp +++ b/src/io/iobestiary.hpp @@ -72,7 +72,7 @@ class IOBestiary { bool hasCharmUnlockedRuneBit(const std::shared_ptr charm, int32_t input) const; std::list getCharmUsedRuneBitAll(std::shared_ptr player); - phmap::parallel_flat_hash_set getBestiaryFinished(std::shared_ptr player) const; + std::vector getBestiaryFinished(const std::shared_ptr &player) const; charmRune_t getCharmFromTarget(std::shared_ptr player, const std::shared_ptr mtype); diff --git a/src/items/containers/container.cpp b/src/items/containers/container.cpp index 54ce00ace..af17ce692 100644 --- a/src/items/containers/container.cpp +++ b/src/items/containers/container.cpp @@ -278,8 +278,8 @@ std::deque> Container::getStoreInboxFilteredItems() const return storeInboxFilteredList; } -phmap::flat_hash_set Container::getStoreInboxValidCategories() const { - phmap::flat_hash_set validCategories; +std::vector Container::getStoreInboxValidCategories() const { + stdext::vector_set validCategories; for (const auto &item : itemlist) { auto itemId = item->getID(); auto attribute = item->getCustomAttribute("unWrapId"); @@ -297,7 +297,7 @@ phmap::flat_hash_set Container::getStoreInboxValidCategorie } } - return validCategories; + return validCategories.data(); } std::shared_ptr Container::getFilteredItemByIndex(size_t index) const { diff --git a/src/items/containers/container.hpp b/src/items/containers/container.hpp index 0b014aee5..56d048f3b 100644 --- a/src/items/containers/container.hpp +++ b/src/items/containers/container.hpp @@ -109,7 +109,7 @@ class Container : public Item, public Cylinder { bool isStoreInbox() const; bool isStoreInboxFiltered() const; std::deque> getStoreInboxFilteredItems() const; - phmap::flat_hash_set getStoreInboxValidCategories() const; + std::vector getStoreInboxValidCategories() const; std::shared_ptr getFilteredItemByIndex(size_t index) const; std::shared_ptr getItemByIndex(size_t index) const; bool isHoldingItem(std::shared_ptr item); diff --git a/src/items/tile.cpp b/src/items/tile.cpp index 44631406f..22c325cfd 100644 --- a/src/items/tile.cpp +++ b/src/items/tile.cpp @@ -1800,12 +1800,8 @@ std::shared_ptr Tile::getDoorItem() const { return nullptr; } -phmap::flat_hash_set> Tile::getZones() { - return zones; -} - void Tile::addZone(std::shared_ptr zone) { - zones.insert(zone); + zones.emplace(zone); const auto &items = getItemList(); if (items) { for (const auto &item : *items) { @@ -1821,12 +1817,12 @@ void Tile::addZone(std::shared_ptr zone) { } void Tile::clearZones() { - phmap::flat_hash_set> zonesToRemove; + std::vector> zonesToRemove; for (const auto &zone : zones) { if (zone->isStatic()) { continue; } - zonesToRemove.insert(zone); + zonesToRemove.emplace_back(zone); const auto &items = getItemList(); if (items) { for (const auto &item : *items) { diff --git a/src/items/tile.hpp b/src/items/tile.hpp index c54717561..bb10b3091 100644 --- a/src/items/tile.hpp +++ b/src/items/tile.hpp @@ -176,7 +176,9 @@ class Tile : public Cylinder, public SharedObject { void addZone(std::shared_ptr zone); void clearZones(); - phmap::flat_hash_set> getZones(); + auto getZones() const { + return zones; + } ZoneType_t getZoneType() const { if (hasFlag(TILESTATE_PROTECTIONZONE)) { @@ -270,7 +272,7 @@ class Tile : public Cylinder, public SharedObject { std::shared_ptr ground = nullptr; Position tilePos; uint32_t flags = 0; - phmap::flat_hash_set> zones; + std::unordered_set> zones; }; // Used for walkable tiles, where there is high likeliness of diff --git a/src/lua/creature/events.cpp b/src/lua/creature/events.cpp index 176044d66..055394214 100644 --- a/src/lua/creature/events.cpp +++ b/src/lua/creature/events.cpp @@ -30,14 +30,14 @@ bool Events::loadFromXml() { info = {}; - std::set classes; + phmap::flat_hash_set classes; for (auto eventNode : doc.child("events").children()) { if (!eventNode.attribute("enabled").as_bool()) { continue; } const std::string &className = eventNode.attribute("class").as_string(); - auto res = classes.insert(className); + auto res = classes.emplace(className); if (res.second) { const std::string &lowercase = asLowerCaseString(className); const std::string &scriptName = lowercase + ".lua"; diff --git a/src/lua/functions/creatures/monster/loot_functions.cpp b/src/lua/functions/creatures/monster/loot_functions.cpp index 81e42535f..b23508033 100644 --- a/src/lua/functions/creatures/monster/loot_functions.cpp +++ b/src/lua/functions/creatures/monster/loot_functions.cpp @@ -259,7 +259,13 @@ int LootFunctions::luaLootAddChildLoot(lua_State* L) { // loot:addChildLoot(loot) const auto loot = getUserdataShared(L, 1); if (loot) { - loot->lootBlock.childLoot.push_back(getUserdata(L, 2)->lootBlock); + const auto childLoot = getUserdata(L, 2); + if (childLoot) { + loot->lootBlock.childLoot.push_back(childLoot->lootBlock); + pushBoolean(L, true); + } else { + pushBoolean(L, false); + } } else { lua_pushnil(L); } diff --git a/src/lua/functions/creatures/monster/monster_functions.cpp b/src/lua/functions/creatures/monster/monster_functions.cpp index 60e60fe87..e0f702f24 100644 --- a/src/lua/functions/creatures/monster/monster_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_functions.cpp @@ -219,11 +219,11 @@ int MonsterFunctions::luaMonsterGetFriendList(lua_State* L) { return 1; } - const auto friendList = monster->getFriendList(); + const auto &friendList = monster->getFriendList(); lua_createtable(L, friendList.size(), 0); int index = 0; - for (std::shared_ptr creature : friendList) { + for (const auto &creature : friendList) { pushUserdata(L, creature); setCreatureMetatable(L, -1, creature); lua_rawseti(L, -2, ++index); diff --git a/src/lua/functions/creatures/monster/monster_type_functions.cpp b/src/lua/functions/creatures/monster/monster_type_functions.cpp index 0db51998e..146ee7b1a 100644 --- a/src/lua/functions/creatures/monster/monster_type_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_type_functions.cpp @@ -426,13 +426,13 @@ int MonsterTypeFunctions::luaMonsterTypeEnemyFactions(lua_State* L) { lua_createtable(L, monsterType->info.enemyFactions.size(), 0); int index = 0; - for (auto faction : monsterType->info.enemyFactions) { + for (const auto &faction : monsterType->info.enemyFactions) { lua_pushnumber(L, faction); lua_rawseti(L, -2, ++index); } } else { Faction_t faction = getNumber(L, 2); - monsterType->info.enemyFactions.emplace(faction); + monsterType->info.enemyFactions.insert(faction); pushBoolean(L, true); } } else { diff --git a/src/lua/functions/creatures/player/player_functions.cpp b/src/lua/functions/creatures/player/player_functions.cpp index 12e7379a2..7c8934b45 100644 --- a/src/lua/functions/creatures/player/player_functions.cpp +++ b/src/lua/functions/creatures/player/player_functions.cpp @@ -328,8 +328,7 @@ int PlayerFunctions::luaPlayerIsMonsterBestiaryUnlocked(lua_State* L) { return 0; } - for (auto finishedMonsters = g_iobestiary().getBestiaryFinished(player); - uint16_t finishedRaceId : finishedMonsters) { + for (uint16_t finishedRaceId : g_iobestiary().getBestiaryFinished(player)) { if (raceId == finishedRaceId) { pushBoolean(L, true); return 1; diff --git a/src/lua/functions/lua_functions_loader.cpp b/src/lua/functions/lua_functions_loader.cpp index 0973876c2..bdf7dbb37 100644 --- a/src/lua/functions/lua_functions_loader.cpp +++ b/src/lua/functions/lua_functions_loader.cpp @@ -239,11 +239,11 @@ void LuaFunctionsLoader::setMetatable(lua_State* L, int32_t index, const std::st } void LuaFunctionsLoader::setWeakMetatable(lua_State* L, int32_t index, const std::string &name) { + static phmap::flat_hash_set weakObjectTypes; if (validateDispatcherContext(__FUNCTION__)) { return; } - static std::set weakObjectTypes; const std::string &weakName = name + "_weak"; auto result = weakObjectTypes.emplace(name); diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index 8bb26bcfb..748e24aee 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -163,7 +163,7 @@ void House::updateDoorDescription() const { } } -AccessHouseLevel_t House::getHouseAccessLevel(std::shared_ptr player) { +AccessHouseLevel_t House::getHouseAccessLevel(std::shared_ptr player) const { if (!player) { return HOUSE_OWNER; } @@ -369,10 +369,6 @@ bool House::getAccessList(uint32_t listId, std::string &list) const { return door->getAccessList(list); } -bool House::isInvited(std::shared_ptr player) { - return getHouseAccessLevel(player) != HOUSE_NOT_INVITED; -} - void House::addDoor(std::shared_ptr door) { doorList.push_back(door); door->setHouse(static_self_cast()); @@ -414,7 +410,7 @@ std::shared_ptr House::getDoorByPosition(const Position &pos) { return nullptr; } -bool House::canEditAccessList(uint32_t listId, std::shared_ptr player) { +bool House::canEditAccessList(uint32_t listId, const std::shared_ptr &player) const { switch (getHouseAccessLevel(player)) { case HOUSE_OWNER: return true; @@ -602,18 +598,17 @@ void AccessList::addGuildRank(const std::string &name, const std::string &guildN } } -bool AccessList::isInList(std::shared_ptr player) { +bool AccessList::isInList(std::shared_ptr player) const { if (allowEveryone) { return true; } - auto playerIt = playerList.find(player->getGUID()); - if (playerIt != playerList.end()) { + if (playerList.contains(player->getGUID())) { return true; } - GuildRank_ptr rank = player->getGuildRank(); - return rank && guildRankList.find(rank->id) != guildRankList.end(); + const auto &rank = player->getGuildRank(); + return rank && guildRankList.contains(rank->id); } void AccessList::getList(std::string &retList) const { @@ -648,7 +643,7 @@ void Door::setHouse(std::shared_ptr newHouse) { } } -bool Door::canUse(std::shared_ptr player) { +bool Door::canUse(std::shared_ptr player) const { if (!house) { return true; } diff --git a/src/map/house/house.hpp b/src/map/house/house.hpp index 845693e30..2e8427a57 100644 --- a/src/map/house/house.hpp +++ b/src/map/house/house.hpp @@ -25,7 +25,7 @@ class AccessList { void addGuild(const std::string &name); void addGuildRank(const std::string &name, const std::string &rankName); - bool isInList(std::shared_ptr player); + bool isInList(std::shared_ptr player) const; void getList(std::string &list) const; @@ -63,7 +63,7 @@ class Door final : public Item { return getAttribute(ItemAttribute_t::DOORID); } - bool canUse(std::shared_ptr player); + bool canUse(std::shared_ptr player) const; void setAccessList(const std::string &textlist); bool getAccessList(std::string &list) const; @@ -104,16 +104,18 @@ class House : public SharedObject { void addTile(std::shared_ptr tile); void updateDoorDescription() const; - bool canEditAccessList(uint32_t listId, std::shared_ptr player); + bool canEditAccessList(uint32_t listId, const std::shared_ptr &player) const; // listId special = values: // GUEST_LIST = guest list // SUBOWNER_LIST = subowner list void setAccessList(uint32_t listId, const std::string &textlist); bool getAccessList(uint32_t listId, std::string &list) const; - bool isInvited(std::shared_ptr player); + bool isInvited(const std::shared_ptr &player) const { + return getHouseAccessLevel(player) != HOUSE_NOT_INVITED; + } - AccessHouseLevel_t getHouseAccessLevel(std::shared_ptr player); + AccessHouseLevel_t getHouseAccessLevel(std::shared_ptr player) const; bool kickPlayer(std::shared_ptr player, std::shared_ptr target); void setEntryPos(Position pos) { diff --git a/src/map/map.cpp b/src/map/map.cpp index 72e867551..3771f5662 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -325,8 +325,8 @@ void Map::moveCreature(const std::shared_ptr &creature, const std::sha Position oldPos = oldTile->getPosition(); Position newPos = newTile->getPosition(); - auto fromZones = oldTile->getZones(); - auto toZones = newTile->getZones(); + const auto &fromZones = oldTile->getZones(); + const auto &toZones = newTile->getZones(); if (auto ret = g_game().beforeCreatureZoneChange(creature, fromZones, toZones); ret != RETURNVALUE_NOERROR) { return; } @@ -694,13 +694,13 @@ uint32_t Map::clean() { } std::vector> toRemove; - for (auto tile : g_game().getTilesToClean()) { + for (const auto &tile : g_game().getTilesToClean()) { if (!tile) { continue; } - if (auto items = tile->getItemList()) { + if (const auto items = tile->getItemList()) { ++tiles; - for (auto item : *items) { + for (const auto &item : *items) { if (item->isCleanable()) { toRemove.emplace_back(item); } @@ -708,7 +708,7 @@ uint32_t Map::clean() { } } - for (auto item : toRemove) { + for (const auto &item : toRemove) { g_game().internalRemoveItem(item, -1); } diff --git a/src/map/mapcache.cpp b/src/map/mapcache.cpp index c39629806..e0e58e5f0 100644 --- a/src/map/mapcache.cpp +++ b/src/map/mapcache.cpp @@ -107,6 +107,8 @@ std::shared_ptr MapCache::getOrCreateTileFromCache(const std::unique_ptrgetTile(x, y); } + std::unique_lock l(floor->getMutex()); + const uint8_t z = floor->getZ(); auto map = static_cast(this); diff --git a/src/map/mapcache.hpp b/src/map/mapcache.hpp index 7dda032b7..6265e979f 100644 --- a/src/map/mapcache.hpp +++ b/src/map/mapcache.hpp @@ -86,6 +86,7 @@ struct Floor { z(z) {}; std::shared_ptr getTile(uint16_t x, uint16_t y) const { + std::shared_lock sl(mutex); return tiles[x & FLOOR_MASK][y & FLOOR_MASK].first; } @@ -94,6 +95,7 @@ struct Floor { } std::shared_ptr getTileCache(uint16_t x, uint16_t y) const { + std::shared_lock sl(mutex); return tiles[x & FLOOR_MASK][y & FLOOR_MASK].second; } @@ -105,8 +107,13 @@ struct Floor { return z; } + auto &getMutex() const { + return mutex; + } + private: std::pair, std::shared_ptr> tiles[FLOOR_SIZE][FLOOR_SIZE] = {}; + mutable std::shared_mutex mutex; uint8_t z { 0 }; }; diff --git a/src/map/spectators.hpp b/src/map/spectators.hpp index 886a51d8c..8e73df9ad 100644 --- a/src/map/spectators.hpp +++ b/src/map/spectators.hpp @@ -64,7 +64,7 @@ class Spectators { Spectators insert(const std::shared_ptr &creature) { if (creature) { - creatures.emplace_back(creature); + creatures.emplace(creature); } return *this; } diff --git a/src/pch.hpp b/src/pch.hpp index ab57f178e..0f5775b73 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index e81933610..828980b83 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -217,7 +217,7 @@ namespace { * @param msg The network message to send the category to. */ template - void sendContainerCategory(NetworkMessage &msg, phmap::flat_hash_set categories = {}, uint8_t categoryType = 0) { + void sendContainerCategory(NetworkMessage &msg, const std::vector &categories = {}, uint8_t categoryType = 0) { msg.addByte(categoryType); g_logger().debug("Sendding category type '{}', categories total size '{}'", categoryType, categories.size()); msg.addByte(categories.size()); @@ -498,7 +498,12 @@ void ProtocolGame::login(const std::string &name, uint32_t accountId, OperatingS if (g_game().getGameState() == GAME_STATE_CLOSED && !player->hasFlag(PlayerFlags_t::CanAlwaysLogin)) { g_game().removePlayerUniqueLogin(player); - disconnectClient("Server is currently closed.\nPlease try again later."); + auto maintainMessage = g_configManager().getString(MAINTAIN_MODE_MESSAGE); + if (!maintainMessage.empty()) { + disconnectClient(maintainMessage); + } else { + disconnectClient("Server is currently closed.\nPlease try again later."); + } return; } @@ -2728,7 +2733,7 @@ void ProtocolGame::parseSendBuyCharmRune(NetworkMessage &msg) { g_iobestiary().sendBuyCharmRune(player, runeID, action, raceid); } -void ProtocolGame::refreshCyclopediaMonsterTracker(const phmap::parallel_flat_hash_set> &trackerSet, bool isBoss) { +void ProtocolGame::refreshCyclopediaMonsterTracker(const std::unordered_set> &trackerSet, bool isBoss) { if (!player || oldProtocol) { return; } @@ -2809,12 +2814,11 @@ void ProtocolGame::BestiarysendCharms() { msg.addByte(4); // Unknown auto finishedMonstersSet = g_iobestiary().getBestiaryFinished(player); - std::list usedRunes = g_iobestiary().getCharmUsedRuneBitAll(player); - - for (charmRune_t charmRune : usedRunes) { + for (charmRune_t charmRune : g_iobestiary().getCharmUsedRuneBitAll(player)) { const auto tmpCharm = g_iobestiary().getBestiaryCharm(charmRune); uint16_t tmp_raceid = player->parseRacebyCharm(tmpCharm->id, false, 0); - finishedMonstersSet.erase(tmp_raceid); + + std::erase(finishedMonstersSet, tmp_raceid); } msg.add(finishedMonstersSet.size()); @@ -4261,7 +4265,7 @@ void ProtocolGame::sendContainer(uint8_t cid, std::shared_ptr contain } if (container->isStoreInbox()) { - auto categories = container->getStoreInboxValidCategories(); + const auto &categories = container->getStoreInboxValidCategories(); const auto enumName = container->getAttribute(ItemAttribute_t::STORE_INBOX_CATEGORY); auto category = magic_enum::enum_cast(enumName); if (category.has_value()) { @@ -5819,7 +5823,7 @@ void ProtocolGame::sendPartyCreatureUpdate(std::shared_ptr target) { void ProtocolGame::sendPartyCreatureShield(std::shared_ptr target) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -5837,7 +5841,7 @@ void ProtocolGame::sendPartyCreatureSkull(std::shared_ptr target) { } uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -5851,7 +5855,7 @@ void ProtocolGame::sendPartyCreatureSkull(std::shared_ptr target) { void ProtocolGame::sendPartyCreatureHealth(std::shared_ptr target, uint8_t healthPercent) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -5865,7 +5869,7 @@ void ProtocolGame::sendPartyCreatureHealth(std::shared_ptr target, uin void ProtocolGame::sendPartyPlayerMana(std::shared_ptr target, uint8_t manaPercent) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); } @@ -5883,7 +5887,7 @@ void ProtocolGame::sendPartyPlayerMana(std::shared_ptr target, uint8_t m void ProtocolGame::sendPartyCreatureShowStatus(std::shared_ptr target, bool showStatus) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); } @@ -5901,7 +5905,7 @@ void ProtocolGame::sendPartyCreatureShowStatus(std::shared_ptr target, void ProtocolGame::sendPartyPlayerVocation(std::shared_ptr target) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -7808,8 +7812,7 @@ void ProtocolGame::reloadCreature(std::shared_ptr creature) { NetworkMessage msg; - phmap::flat_hash_set::iterator it = std::find(knownCreatureSet.begin(), knownCreatureSet.end(), creature->getID()); - if (it != knownCreatureSet.end()) { + if (knownCreatureSet.contains(creature->getID())) { msg.addByte(0x6B); msg.addPosition(creature->getPosition()); msg.addByte(stackpos); @@ -8308,7 +8311,7 @@ void ProtocolGame::parseBosstiarySlot(NetworkMessage &msg) { addGameTask(&Game::playerBosstiarySlot, player->getID(), slotBossId, selectedBossId); } -void ProtocolGame::sendPodiumDetails(NetworkMessage &msg, const phmap::parallel_flat_hash_set &toSendMonsters, bool isBoss) const { +void ProtocolGame::sendPodiumDetails(NetworkMessage &msg, const std::vector &toSendMonsters, bool isBoss) const { auto toSendMonstersSize = static_cast(toSendMonsters.size()); msg.add(toSendMonstersSize); for (const auto &raceId : toSendMonsters) { @@ -8388,10 +8391,10 @@ void ProtocolGame::sendMonsterPodiumWindow(std::shared_ptr podium, const P bool isBossPodium = podium->getID() == ITEM_PODIUM_OF_VIGOUR; msg.addByte(isBossPodium ? 0x01 : 0x00); // Bosstiary or bestiary if (isBossPodium) { - const auto unlockedBosses = g_ioBosstiary().getBosstiaryFinished(player, 2); + const auto &unlockedBosses = g_ioBosstiary().getBosstiaryFinished(player, 2); sendPodiumDetails(msg, unlockedBosses, true); } else { - const auto unlockedMonsters = g_iobestiary().getBestiaryFinished(player); + const auto &unlockedMonsters = g_iobestiary().getBestiaryFinished(player); sendPodiumDetails(msg, unlockedMonsters, false); } diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 2295c1036..8838fc39e 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -145,7 +145,7 @@ class ProtocolGame final : public Protocol { void parseBestiarysendCreatures(NetworkMessage &msg); void BestiarysendCharms(); void sendBestiaryEntryChanged(uint16_t raceid); - void refreshCyclopediaMonsterTracker(const phmap::parallel_flat_hash_set> &trackerSet, bool isBoss); + void refreshCyclopediaMonsterTracker(const std::unordered_set> &trackerSet, bool isBoss); void sendTeamFinderList(); void sendLeaderTeamFinder(bool reset); void createLeaderTeamFinder(NetworkMessage &msg); @@ -265,7 +265,7 @@ class ProtocolGame final : public Protocol { void parseSendBosstiary(); void parseSendBosstiarySlots(); void parseBosstiarySlot(NetworkMessage &msg); - void sendPodiumDetails(NetworkMessage &msg, const phmap::parallel_flat_hash_set &toSendMonsters, bool isBoss) const; + void sendPodiumDetails(NetworkMessage &msg, const std::vector &toSendMonsters, bool isBoss) const; void sendMonsterPodiumWindow(std::shared_ptr podium, const Position &position, uint16_t itemId, uint8_t stackPos); void parseSetMonsterPodium(NetworkMessage &msg) const; void sendBosstiaryCooldownTimer(); @@ -471,7 +471,7 @@ class ProtocolGame final : public Protocol { friend class Player; friend class PlayerWheel; - phmap::flat_hash_set knownCreatureSet; + std::unordered_set knownCreatureSet; std::shared_ptr player = nullptr; uint32_t eventConnect = 0; diff --git a/src/server/network/protocol/protocolstatus.cpp b/src/server/network/protocol/protocolstatus.cpp index 315e49a35..778e9c161 100644 --- a/src/server/network/protocol/protocolstatus.cpp +++ b/src/server/network/protocol/protocolstatus.cpp @@ -18,7 +18,7 @@ std::string ProtocolStatus::SERVER_NAME = "OTX Server"; std::string ProtocolStatus::SERVER_VERSION = "6.2"; -std::string ProtocolStatus::SERVER_DEVELOPERS = "Canary Base - OpenTibiaBR Organization and data editor: Mattyx14"; +std::string ProtocolStatus::SERVER_DEVELOPERS = "Canary Base (3.1.1) - OpenTibiaBR Organization and data editor: Mattyx14"; std::map ProtocolStatus::ipConnectMap; const uint64_t ProtocolStatus::start = OTSYS_TIME(); diff --git a/src/utils/vectorset.hpp b/src/utils/vectorset.hpp index 29c6b3766..dab8901bf 100644 --- a/src/utils/vectorset.hpp +++ b/src/utils/vectorset.hpp @@ -22,13 +22,13 @@ namespace stdext { public: bool contains(const T &v) { update(); - return v && std::ranges::binary_search(container, v); + return std::ranges::binary_search(container.begin(), container.end(), v, std::less()); } bool erase(const T &v) { update(); - const auto &it = std::ranges::lower_bound(container, v); + const auto it = std::ranges::lower_bound(container.begin(), container.end(), v, std::less()); if (it == container.end()) { return false; } @@ -43,13 +43,13 @@ namespace stdext { return std::erase_if(container, std::move(fnc)) > 0; } - void push_back(const T &v) { + void insert(const T &v) { needUpdate = true; return container.push_back(v); } template - auto emplace_back(_Valty &&... v) { + auto emplace(_Valty &&... v) { needUpdate = true; return container.emplace_back(v...); } @@ -64,6 +64,22 @@ namespace stdext { return container.insert(container.end(), list.begin(), list.end()); } + constexpr auto insert(std::vector::const_iterator _Where, const T &_Val) { + needUpdate = true; + return container.insert(_Where, _Val); + } + + constexpr auto insert(std::vector::const_iterator _Where, T &&_Val) { + needUpdate = true; + return container.insert(_Where, std::move(_Val)); + } + + template + constexpr auto insert(std::vector::const_iterator _Where, _Iter _First, _Iter _Last) { + needUpdate = true; + return container.insert(_Where, _First, _Last); + } + bool empty() const noexcept { return container.empty(); } @@ -95,6 +111,11 @@ namespace stdext { return container; } + T &operator[](const size_t i) { + update(); + return container[i]; + } + private: void update() noexcept { if (!needUpdate) { @@ -102,7 +123,7 @@ namespace stdext { } needUpdate = false; - std::ranges::sort(container); + std::ranges::sort(container.begin(), container.end(), std::less()); const auto &[f, l] = std::ranges::unique(container); container.erase(f, l); }