diff --git a/src/creatures/monsters/spawns/spawn_monster.cpp b/src/creatures/monsters/spawns/spawn_monster.cpp index ed26b34568f..0353ee49bb0 100644 --- a/src/creatures/monsters/spawns/spawn_monster.cpp +++ b/src/creatures/monsters/spawns/spawn_monster.cpp @@ -156,8 +156,7 @@ void SpawnMonster::startSpawnMonsterCheck() { } SpawnMonster::~SpawnMonster() { - for (const auto &it : spawnedMonsterMap) { - std::shared_ptr monster = it.second; + for (const auto &[_, monster] : spawnedMonsterMap) { monster->setSpawnMonster(nullptr); } } @@ -177,6 +176,9 @@ bool SpawnMonster::isInSpawnMonsterZone(const Position &pos) { } bool SpawnMonster::spawnMonster(uint32_t spawnMonsterId, const std::shared_ptr monsterType, const Position &pos, Direction dir, bool startup /*= false*/) { + if (spawnedMonsterMap.contains(spawnMonsterId)) { + return false; + } auto monster = std::make_shared(monsterType); if (startup) { // No need to send out events to the surrounding since there is no one out there to listen! @@ -193,14 +195,14 @@ bool SpawnMonster::spawnMonster(uint32_t spawnMonsterId, const std::shared_ptrsetSpawnMonster(this); monster->setMasterPos(pos); - spawnedMonsterMap.insert(spawned_pair(spawnMonsterId, monster)); + spawnedMonsterMap[spawnMonsterId] = monster; spawnMonsterMap[spawnMonsterId].lastSpawn = OTSYS_TIME(); g_events().eventMonsterOnSpawn(monster, pos); g_callbacks().executeCallback(EventCallback_t::monsterOnSpawn, &EventCallback::monsterOnSpawn, monster, pos); return true; } -void SpawnMonster::startup() { +void SpawnMonster::startup(bool delayed) { if (g_configManager().getBoolean(RANDOM_MONSTER_SPAWN)) { for (auto it = spawnMonsterMap.begin(); it != spawnMonsterMap.end(); ++it) { auto &[spawnMonsterId, sb] = *it; @@ -230,7 +232,11 @@ void SpawnMonster::startup() { if (!mType) { continue; } - spawnMonster(spawnMonsterId, mType, sb.pos, sb.direction, true); + if (delayed) { + g_dispatcher().addEvent(std::bind(&SpawnMonster::scheduleSpawn, this, spawnMonsterId, sb, mType, 0), "SpawnMonster::startup"); + } else { + scheduleSpawn(spawnMonsterId, sb, mType, 0); + } } } @@ -243,13 +249,11 @@ void SpawnMonster::checkSpawnMonster() { cleanup(); uint32_t spawnMonsterCount = 0; - for (auto &it : spawnMonsterMap) { - uint32_t spawnMonsterId = it.first; - if (spawnedMonsterMap.find(spawnMonsterId) != spawnedMonsterMap.end()) { + for (auto &[spawnMonsterId, sb] : spawnMonsterMap) { + if (spawnedMonsterMap.contains(spawnMonsterId)) { continue; } - spawnBlock_t &sb = it.second; const auto &mType = sb.getMonsterType(); if (!mType) { continue; @@ -292,15 +296,15 @@ void SpawnMonster::scheduleSpawn(uint32_t spawnMonsterId, spawnBlock_t &sb, cons } void SpawnMonster::cleanup() { - auto it = spawnedMonsterMap.begin(); - while (it != spawnedMonsterMap.end()) { - auto monster = it->second; + std::vector removeList; + for (const auto &[spawnMonsterId, monster] : spawnedMonsterMap) { if (monster == nullptr || monster->isRemoved()) { - it = spawnedMonsterMap.erase(it); - } else { - ++it; + removeList.push_back(spawnMonsterId); } } + for (const auto &spawnMonsterId : removeList) { + spawnedMonsterMap.erase(spawnMonsterId); + } } bool SpawnMonster::addMonster(const std::string &name, const Position &pos, Direction dir, uint32_t scheduleInterval, uint32_t weight /*= 1*/) { @@ -354,12 +358,14 @@ bool SpawnMonster::addMonster(const std::string &name, const Position &pos, Dire } void SpawnMonster::removeMonster(std::shared_ptr monster) { - for (auto it = spawnedMonsterMap.begin(), end = spawnedMonsterMap.end(); it != end; ++it) { - if (it->second == monster) { - spawnedMonsterMap.erase(it); + uint32_t spawnMonsterId = 0; + for (const auto &[id, m] : spawnedMonsterMap) { + if (m == monster) { + spawnMonsterId = id; break; } } + spawnedMonsterMap.erase(spawnMonsterId); } void SpawnMonster::setMonsterVariant(const std::string &variant) { diff --git a/src/creatures/monsters/spawns/spawn_monster.hpp b/src/creatures/monsters/spawns/spawn_monster.hpp index bf4a47b1f52..36dd2e1ca09 100644 --- a/src/creatures/monsters/spawns/spawn_monster.hpp +++ b/src/creatures/monsters/spawns/spawn_monster.hpp @@ -42,7 +42,7 @@ class SpawnMonster { uint32_t getInterval() const { return interval; } - void startup(); + void startup(bool delayed = false); void startSpawnMonsterCheck(); void stopEvent(); @@ -58,12 +58,10 @@ class SpawnMonster { private: // map of the spawned creatures - using SpawnedMap = std::multimap>; - using spawned_pair = SpawnedMap::value_type; - SpawnedMap spawnedMonsterMap; + phmap::parallel_flat_hash_map_m> spawnedMonsterMap; // map of creatures in the spawn - std::map spawnMonsterMap; + phmap::parallel_flat_hash_map_m spawnMonsterMap; Position centerPos; int32_t radius; diff --git a/src/game/scheduling/task.hpp b/src/game/scheduling/task.hpp index f42602242c5..9f89a849a2c 100644 --- a/src/game/scheduling/task.hpp +++ b/src/game/scheduling/task.hpp @@ -100,6 +100,7 @@ class Task { "Raids::checkRaids", "SpawnMonster::checkSpawnMonster", "SpawnMonster::scheduleSpawn", + "SpawnMonster::startup", "SpawnNpc::checkSpawnNpc", "Webhook::run", "Protocol::sendRecvMessageCallback",