diff options
author | Treeston <treeston.mmoc@gmail.com> | 2020-02-08 20:22:37 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-08 20:22:37 +0100 |
commit | 9304e496cbf6ab6c028671fb8526c732ae5d799f (patch) | |
tree | 997040bf14477bbd30b9b175aac93fa287de03e1 /src/server/game/Maps/Map.cpp | |
parent | 726d5e91b55d4742dcbd6b0a82d84788dbb117b7 (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>
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r-- | src/server/game/Maps/Map.cpp | 229 |
1 files changed, 128 insertions, 101 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 8001aa66412..9569b587112 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3026,75 +3026,64 @@ bool Map::CheckRespawn(RespawnInfo* info) return true; } -void Map::DoRespawn(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 gridId) +void Map::Respawn(RespawnInfo* info, SQLTransaction 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 %u) on map %u", uint32(type), spawnId, GetId()); + break; } -} -void Map::Respawn(RespawnInfo* info, SQLTransaction 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); - 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,%u) into spawn id map failed - state desync.", uint32(info.type), info.spawnId); } + else + ASSERT(false, "Invalid respawn info for spawn id (%u,%u) 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,%u) into spawn id map failed - state desync.", uint32(ri->type), ri->spawnId); + bySpawnIdMap.emplace(ri->spawnId, ri); return true; } @@ -3137,8 +3126,11 @@ void Map::DeleteRespawnInfo(RespawnInfo* info, SQLTransaction dbTrans) ASSERT(info); // spawnid store - size_t const n = GetRespawnMapForType(info->type).erase(info->spawnId); - ASSERT(n == 1, "Respawn stores inconsistent for map %u, spawnid %u (type %u)", GetId(), info->spawnId, uint32(info->type)); + auto& spawnMap = GetRespawnMapForType(info->type); + 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 %u (type %u)", GetId(), info->spawnId, uint32(info->type)); + spawnMap.erase(it); // respawn heap _respawnTimes.erase(info->handle); @@ -3155,6 +3147,32 @@ void Map::DeleteRespawnInfo(RespawnInfo* info, SQLTransaction dbTrans) 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 %u) on map %u", uint32(type), spawnId, GetId()); + } +} + void Map::ProcessRespawns() { time_t now = GameTime::GetGameTime(); @@ -3207,8 +3225,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()); @@ -3227,6 +3248,24 @@ 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); @@ -3245,31 +3284,40 @@ 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); + + if (force || ignoreRespawn) + RemoveRespawnTime(data->type, data->spawnId); + + uint32 nRespawnTimers = GetRespawnMapForType(data->type).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: @@ -3307,41 +3355,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 %u.", 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; } @@ -4282,19 +4305,23 @@ void Map::UpdateIteratorBack(Player* player) void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, SQLTransaction 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,%u).", 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; @@ -4334,7 +4361,7 @@ void Map::LoadRespawnTimes() ObjectGuid::LowType spawnId = fields[1].GetUInt32(); uint64 respawnTime = fields[2].GetUInt64(); - 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); |