diff options
author | Treeston <treeston.mmoc@gmail.com> | 2020-02-08 20:22:37 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-12-21 15:16:26 +0100 |
commit | 94a79bac7a06aa0f931e9d651928de7eea0a8b5c (patch) | |
tree | 0f28508689237d951d0a44ae05c85ab3a29d8c62 /src/server/game/Maps/Map.cpp | |
parent | fe489e2be1312bc559d0c38691c9741ad69cfec8 (diff) |
Core/Misc: Some refactoring, #23603 prep: (#23676)
- Split SpawnMetadata off from SpawnData
- No longer allocate Creature/Gameobject objects in ObjectGridLoader just to check their typeid and delete them afterwards
Co-authored-by: Giacomo Pozzoni <giacomopoz@gmail.com>
(cherry picked from commit 9304e496cbf6ab6c028671fb8526c732ae5d799f)
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r-- | src/server/game/Maps/Map.cpp | 269 |
1 files changed, 162 insertions, 107 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 01e797e576b..32d371fe78d 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3190,75 +3190,66 @@ bool Map::CheckRespawn(RespawnInfo* info) return true; } -void Map::DoRespawn(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 gridId) +void Map::Respawn(RespawnInfo* info, CharacterDatabaseTransaction dbTrans) { - if (!IsGridLoaded(gridId)) // if grid isn't loaded, this will be processed in grid load handler - return; + info->respawnTime = GameTime::GetGameTime(); + SaveRespawnInfoDB(*info, dbTrans); +} +size_t Map::DespawnAll(SpawnObjectType type, ObjectGuid::LowType spawnId) +{ + std::vector<WorldObject*> toUnload; switch (type) { case SPAWN_TYPE_CREATURE: - { - Creature* obj = new Creature(); - if (!obj->LoadFromDB(spawnId, this, true, true)) - delete obj; + for (auto const& pair : Trinity::Containers::MapEqualRange(GetCreatureBySpawnIdStore(), spawnId)) + toUnload.push_back(pair.second); break; - } case SPAWN_TYPE_GAMEOBJECT: - { - GameObject* obj = new GameObject(); - if (!obj->LoadFromDB(spawnId, this, true)) - delete obj; - break; - } + for (auto const& pair : Trinity::Containers::MapEqualRange(GetGameObjectBySpawnIdStore(), spawnId)) + toUnload.push_back(pair.second); default: - ASSERT(false, "Invalid spawn type %u (spawnid " UI64FMTD ") on map %u", uint32(type), spawnId, GetId()); + break; } -} -void Map::Respawn(RespawnInfo* info, CharacterDatabaseTransaction dbTrans) -{ - if (!CheckRespawn(info)) - { - if (info->respawnTime) - { - _respawnTimes.decrease(info->handle); - SaveRespawnInfoDB(*info, dbTrans); - } - else - DeleteRespawnInfo(info, dbTrans); - return; - } + for (WorldObject* o : toUnload) + AddObjectToRemoveList(o); - // remove the actual respawn record first - since this deletes it, we save what we need - SpawnObjectType const type = info->type; - uint32 const gridId = info->gridId; - ObjectGuid::LowType const spawnId = info->spawnId; - DeleteRespawnInfo(info, dbTrans); - DoRespawn(type, spawnId, gridId); + return toUnload.size(); } bool Map::AddRespawnInfo(RespawnInfo const& info) { - ASSERT(info.spawnId, "Attempt to schedule respawn with zero spawnid (type %u)", uint32(info.type)); + if (!info.spawnId) + { + TC_LOG_ERROR("maps", "Attempt to insert respawn info for zero spawn id (type %u)", uint32(info.type)); + return false; + } - RespawnInfoMap& bySpawnIdMap = GetRespawnMapForType(info.type); + RespawnInfoMap* bySpawnIdMap = GetRespawnMapForType(info.type); + if (!bySpawnIdMap) + return false; - auto it = bySpawnIdMap.find(info.spawnId); - if (it != bySpawnIdMap.end()) // spawnid already has a respawn scheduled + // check if we already have the maximum possible number of respawns scheduled + if (SpawnData::TypeHasData(info.type)) { - RespawnInfo* const existing = it->second; - if (info.respawnTime < existing->respawnTime) // delete existing in this case - DeleteRespawnInfo(existing); - else - return false; + auto it = bySpawnIdMap->find(info.spawnId); + if (it != bySpawnIdMap->end()) // spawnid already has a respawn scheduled + { + RespawnInfo* const existing = it->second; + if (info.respawnTime <= existing->respawnTime) // delete existing in this case + DeleteRespawnInfo(existing); + else + return false; + } + ASSERT(bySpawnIdMap->find(info.spawnId) == bySpawnIdMap->end(), "Insertion of respawn info with id (%u," UI64FMTD ") into spawn id map failed - state desync.", uint32(info.type), info.spawnId); } + else + ASSERT(false, "Invalid respawn info for spawn id (%u," UI64FMTD ") being inserted", uint32(info.type), info.spawnId); - // if we get to this point, we should insert the respawninfo (there either was no prior entry, or it was deleted already) RespawnInfo * ri = new RespawnInfo(info); ri->handle = _respawnTimes.push(ri); - bool success = bySpawnIdMap.emplace(ri->spawnId, ri).second; - ASSERT(success, "Insertion of respawn info with id (%u," UI64FMTD ") into spawn id map failed - state desync.", uint32(ri->type), ri->spawnId); + bySpawnIdMap->emplace(ri->spawnId, ri); return true; } @@ -3279,9 +3270,11 @@ void Map::GetRespawnInfo(std::vector<RespawnInfo*>& respawnData, SpawnObjectType RespawnInfo* Map::GetRespawnInfo(SpawnObjectType type, ObjectGuid::LowType spawnId) const { - RespawnInfoMap const& map = GetRespawnMapForType(type); - auto it = map.find(spawnId); - if (it == map.end()) + RespawnInfoMap const* map = GetRespawnMapForType(type); + if (!map) + return nullptr; + auto it = map->find(spawnId); + if (it == map->end()) return nullptr; return it->second; } @@ -3301,8 +3294,14 @@ void Map::DeleteRespawnInfo(RespawnInfo* info, CharacterDatabaseTransaction dbTr ASSERT(info); // spawnid store - size_t const n = GetRespawnMapForType(info->type).erase(info->spawnId); - ASSERT(n == 1, "Respawn stores inconsistent for map %u, spawnid " UI64FMTD " (type %u)", GetId(), info->spawnId, uint32(info->type)); + auto spawnMap = GetRespawnMapForType(info->type); + if (!spawnMap) + return; + + auto range = spawnMap->equal_range(info->spawnId); + auto it = std::find_if(range.first, range.second, [info](RespawnInfoMap::value_type const& pair) { return (pair.second == info); }); + ASSERT(it != range.second, "Respawn stores inconsistent for map %u, spawnid " UI64FMTD " (type %u)", GetId(), info->spawnId, uint32(info->type)); + spawnMap->erase(it); // respawn heap _respawnTimes.erase(info->handle); @@ -3319,6 +3318,32 @@ void Map::DeleteRespawnInfo(RespawnInfo* info, CharacterDatabaseTransaction dbTr delete info; } +void Map::DoRespawn(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 gridId) +{ + if (!IsGridLoaded(gridId)) // if grid isn't loaded, this will be processed in grid load handler + return; + + switch (type) + { + case SPAWN_TYPE_CREATURE: + { + Creature* obj = new Creature(); + if (!obj->LoadFromDB(spawnId, this, true, true)) + delete obj; + break; + } + case SPAWN_TYPE_GAMEOBJECT: + { + GameObject* obj = new GameObject(); + if (!obj->LoadFromDB(spawnId, this, true)) + delete obj; + break; + } + default: + ASSERT(false, "Invalid spawn type %u (spawnid " UI64FMTD ") on map %u", uint32(type), spawnId, GetId()); + } +} + void Map::ProcessRespawns() { time_t now = GameTime::GetGameTime(); @@ -3331,14 +3356,14 @@ void Map::ProcessRespawns() { // ok, respawn _respawnTimes.pop(); - GetRespawnMapForType(next->type).erase(next->spawnId); + ASSERT_NOTNULL(GetRespawnMapForType(next->type))->erase(next->spawnId); DoRespawn(next->type, next->spawnId, next->gridId); delete next; } else if (!next->respawnTime) // just remove respawn entry without rescheduling { _respawnTimes.pop(); - GetRespawnMapForType(next->type).erase(next->spawnId); + ASSERT_NOTNULL(GetRespawnMapForType(next->type))->erase(next->spawnId); delete next; } else // value changed, update heap position @@ -3371,8 +3396,11 @@ void Map::ApplyDynamicModeRespawnScaling(WorldObject const* obj, ObjectGuid::Low return; } - SpawnData const* data = sObjectMgr->GetSpawnData(type, spawnId); - if (!data || !data->spawnGroupData || !(data->spawnGroupData->flags & SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE)) + SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(type, spawnId); + if (!data) + return; + + if (!(data->spawnGroupData->flags & SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE)) return; auto it = _zonePlayerCountMap.find(obj->GetZoneId()); @@ -3391,6 +3419,23 @@ void Map::ApplyDynamicModeRespawnScaling(WorldObject const* obj, ObjectGuid::Low respawnDelay = std::max<uint32>(ceil(respawnDelay * adjustFactor), timeMinimum); } +bool Map::ShouldBeSpawnedOnGridLoad(SpawnObjectType type, ObjectGuid::LowType spawnId) const +{ + ASSERT(SpawnData::TypeHasData(type)); + // check if the object is on its respawn timer + if (GetRespawnTime(type, spawnId)) + return false; + + SpawnMetadata const* spawnData = ASSERT_NOTNULL(sObjectMgr->GetSpawnMetadata(type, spawnId)); + // check if the object is part of a spawn group + SpawnGroupTemplateData const* spawnGroup = ASSERT_NOTNULL(spawnData->spawnGroupData); + if (!(spawnGroup->flags & SPAWNGROUP_FLAG_SYSTEM)) + if (!IsSpawnGroupActive(spawnGroup->groupId)) + return false; + + return true; +} + SpawnGroupTemplateData const* Map::GetSpawnGroupData(uint32 groupId) const { SpawnGroupTemplateData const* data = sObjectMgr->GetSpawnGroupData(groupId); @@ -3409,31 +3454,44 @@ bool Map::SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn, bool force, std::v } SetSpawnGroupActive(groupId, true); // start processing respawns for the group - for (auto& pair : sObjectMgr->GetSpawnDataForGroup(groupId)) - { - SpawnData const* data = pair.second; - ASSERT(groupData->mapId == data->spawnPoint.GetMapId()); - // Check if there's already an instance spawned - if (!force) - if (WorldObject* obj = GetWorldObjectBySpawnId(data->type, data->spawnId)) - if ((data->type != SPAWN_TYPE_CREATURE) || obj->ToCreature()->IsAlive()) - continue; - time_t respawnTime = GetRespawnTime(data->type, data->spawnId); - if (respawnTime) + std::vector<SpawnData const*> toSpawn; + for (auto& pair : sObjectMgr->GetSpawnMetadataForGroup(groupId)) + { + SpawnMetadata const* data = pair.second; + ASSERT(groupData->mapId == data->mapId); + + auto respawnMap = GetRespawnMapForType(data->type); + if (!respawnMap) + continue; + + if (force || ignoreRespawn) + RemoveRespawnTime(data->type, data->spawnId); + + uint32 nRespawnTimers = respawnMap->count(data->spawnId); + if (SpawnData::TypeHasData(data->type)) { - if (!force && !ignoreRespawn && (respawnTime > GameTime::GetGameTime())) + // has a respawn timer + if (nRespawnTimers) continue; - // we need to remove the respawn time, otherwise we'd end up double spawning - RemoveRespawnTime(data->type, data->spawnId); + // has a spawn already active + if (!force) + if (WorldObject* obj = GetWorldObjectBySpawnId(data->type, data->spawnId)) + if ((data->type != SPAWN_TYPE_CREATURE) || obj->ToCreature()->IsAlive()) + continue; + + toSpawn.push_back(ASSERT_NOTNULL(data->ToSpawnData())); } + } + for (SpawnData const* data : toSpawn) + { // don't spawn if the grid isn't loaded (will be handled in grid loader) if (!IsGridLoaded(data->spawnPoint)) continue; - // Everything OK, now do the actual (re)spawn + // now do the actual (re)spawn switch (data->type) { case SPAWN_TYPE_CREATURE: @@ -3454,6 +3512,15 @@ bool Map::SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn, bool force, std::v spawnedObjects->push_back(gameobject); break; } + case SPAWN_TYPE_AREATRIGGER: + { + AreaTrigger* areaTrigger = new AreaTrigger(); + if (!areaTrigger->LoadFromDB(data->spawnId, this, true, false)) + delete areaTrigger; + else if (spawnedObjects) + spawnedObjects->push_back(areaTrigger); + break; + } default: ASSERT(false, "Invalid spawn type %u with spawnId " UI64FMTD, uint32(data->type), data->spawnId); return false; @@ -3471,41 +3538,16 @@ bool Map::SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes, size_t* cou return false; } - std::vector<WorldObject*> toUnload; // unload after iterating, otherwise iterator invalidation - for (auto const& pair : sObjectMgr->GetSpawnDataForGroup(groupId)) + for (auto const& pair : sObjectMgr->GetSpawnMetadataForGroup(groupId)) { - SpawnData const* data = pair.second; - ASSERT(groupData->mapId == data->spawnPoint.GetMapId()); + SpawnMetadata const* data = pair.second; + ASSERT(groupData->mapId == data->mapId); if (deleteRespawnTimes) RemoveRespawnTime(data->type, data->spawnId); - switch (data->type) - { - case SPAWN_TYPE_CREATURE: - { - auto bounds = GetCreatureBySpawnIdStore().equal_range(data->spawnId); - for (auto it = bounds.first; it != bounds.second; ++it) - toUnload.emplace_back(it->second); - break; - } - case SPAWN_TYPE_GAMEOBJECT: - { - auto bounds = GetGameObjectBySpawnIdStore().equal_range(data->spawnId); - for (auto it = bounds.first; it != bounds.second; ++it) - toUnload.emplace_back(it->second); - break; - } - default: - ASSERT(false, "Invalid spawn type %u in spawn data with spawnId " UI64FMTD ".", uint32(data->type), data->spawnId); - return false; - } + size_t c = DespawnAll(data->type, data->spawnId); + if (count) + *count += c; } - - if (count) - *count = toUnload.size(); - - // now do the actual despawning - for (WorldObject* obj : toUnload) - obj->AddObjectToRemoveList(); SetSpawnGroupActive(groupId, false); // stop processing respawns for the group, too return true; } @@ -4489,6 +4531,15 @@ GameObject* Map::GetGameObjectBySpawnId(ObjectGuid::LowType spawnId) const return creatureItr != bounds.second ? creatureItr->second : bounds.first->second; } +AreaTrigger* Map::GetAreaTriggerBySpawnId(ObjectGuid::LowType spawnId) const +{ + auto const bounds = GetAreaTriggerBySpawnIdStore().equal_range(spawnId); + if (bounds.first == bounds.second) + return nullptr; + + return bounds.first->second; +} + void Map::UpdateIteratorBack(Player* player) { if (m_mapRefIter == player->GetMapRef()) @@ -4497,19 +4548,23 @@ void Map::UpdateIteratorBack(Player* player) void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, CharacterDatabaseTransaction dbTrans, bool startup) { - if (!spawnId) + SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(type, spawnId); + if (!data) + { + TC_LOG_ERROR("maps", "Map %u attempt to save respawn time for nonexistant spawnid (%u," UI64FMTD ").", GetId(), type, spawnId); return; + } if (!respawnTime) { // Delete only - RemoveRespawnTime(type, spawnId, dbTrans); + RemoveRespawnTime(data->type, data->spawnId, dbTrans); return; } RespawnInfo ri; - ri.type = type; - ri.spawnId = spawnId; + ri.type = data->type; + ri.spawnId = data->spawnId; ri.entry = entry; ri.respawnTime = respawnTime; ri.gridId = gridId; @@ -4549,7 +4604,7 @@ void Map::LoadRespawnTimes() ObjectGuid::LowType spawnId = fields[1].GetUInt64(); time_t respawnTime = fields[2].GetInt64(); - if (type < SPAWN_TYPE_MAX) + if (SpawnData::TypeHasData(type)) { if (SpawnData const* data = sObjectMgr->GetSpawnData(type, spawnId)) SaveRespawnTime(type, spawnId, data->id, time_t(respawnTime), Trinity::ComputeGridCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()).GetId(), nullptr, true); |