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 | |
| 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')
| -rw-r--r-- | src/server/game/Maps/Map.cpp | 229 | ||||
| -rw-r--r-- | src/server/game/Maps/Map.h | 11 | ||||
| -rw-r--r-- | src/server/game/Maps/MapManager.h | 7 | ||||
| -rw-r--r-- | src/server/game/Maps/SpawnData.h | 46 |
4 files changed, 179 insertions, 114 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); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 56a95ee96b1..ce876623d61 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -589,6 +589,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> void SaveRespawnInfoDB(RespawnInfo const& info, SQLTransaction dbTrans = nullptr); void LoadRespawnTimes(); void DeleteRespawnTimes() { UnloadAllRespawnInfos(); DeleteRespawnTimesInDB(GetId(), GetInstanceId()); } + static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId); void LoadCorpseData(); void DeleteCorpseData(); @@ -597,8 +598,6 @@ class TC_GAME_API Map : public GridRefManager<NGridType> Corpse* ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia = false); void RemoveOldCorpses(); - static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId); - void SendInitTransports(Player* player); void SendRemoveTransports(Player* player); void SendZoneDynamicInfo(uint32 zoneId, Player* player) const; @@ -762,7 +761,6 @@ class TC_GAME_API Map : public GridRefManager<NGridType> // if return value is false and info->respawnTime is nonzero, it is guaranteed to be greater than time(NULL) bool CheckRespawn(RespawnInfo* info); void DoRespawn(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 gridId); - void Respawn(RespawnInfo* info, SQLTransaction dbTrans = nullptr); bool AddRespawnInfo(RespawnInfo const& info); void UnloadAllRespawnInfos(); void DeleteRespawnInfo(RespawnInfo* info, SQLTransaction dbTrans = nullptr); @@ -775,11 +773,16 @@ class TC_GAME_API Map : public GridRefManager<NGridType> if (RespawnInfo* info = GetRespawnInfo(type, spawnId)) Respawn(info, dbTrans); } - void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId,SQLTransaction dbTrans = nullptr) + void Respawn(RespawnInfo* info, SQLTransaction dbTrans = nullptr); + void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, SQLTransaction dbTrans = nullptr) { if (RespawnInfo* info = GetRespawnInfo(type, spawnId)) DeleteRespawnInfo(info, dbTrans); } + size_t DespawnAll(SpawnObjectType type, ObjectGuid::LowType spawnId); + + bool ShouldBeSpawnedOnGridLoad(SpawnObjectType type, ObjectGuid::LowType spawnId) const; + template <typename T> bool ShouldBeSpawnedOnGridLoad(ObjectGuid::LowType spawnId) const { return ShouldBeSpawnedOnGridLoad(SpawnData::TypeFor<T>, spawnId); } SpawnGroupTemplateData const* GetSpawnGroupData(uint32 groupId) const; diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 04811de991e..9d3b1a1746b 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -101,9 +101,14 @@ class TC_GAME_API MapManager return IsValidMAP(mapid, false) && Trinity::IsValidMapCoord(x, y, z, o); } + static bool IsValidMapCoord(uint32 mapid, Position const& pos) + { + return IsValidMapCoord(mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); + } + static bool IsValidMapCoord(WorldLocation const& loc) { - return IsValidMapCoord(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation()); + return IsValidMapCoord(loc.GetMapId(), loc); } void DoDelayedMovesAndRemoves(); diff --git a/src/server/game/Maps/SpawnData.h b/src/server/game/Maps/SpawnData.h index 594377f4d7e..863fa13f4bc 100644 --- a/src/server/game/Maps/SpawnData.h +++ b/src/server/game/Maps/SpawnData.h @@ -20,13 +20,18 @@ #include "Position.h" +class Creature; +class GameObject; +class Pool; +struct PoolTemplate; + // EnumUtils: DESCRIBE THIS enum SpawnObjectType { SPAWN_TYPE_CREATURE = 0, // TITLE Creature SPAWN_TYPE_GAMEOBJECT = 1, // TITLE Gameobject - - SPAWN_TYPE_MAX // SKIP + NUM_SPAWN_TYPES_WITH_DATA, // SKIP + NUM_SPAWN_TYPES = NUM_SPAWN_TYPES_WITH_DATA // SKIP }; enum SpawnObjectTypeMask @@ -34,7 +39,8 @@ enum SpawnObjectTypeMask SPAWN_TYPEMASK_CREATURE = (1 << SPAWN_TYPE_CREATURE), SPAWN_TYPEMASK_GAMEOBJECT = (1 << SPAWN_TYPE_GAMEOBJECT), - SPAWN_TYPEMASK_ALL = (1 << SPAWN_TYPE_MAX)-1 + SPAWN_TYPEMASK_WITH_DATA = (1 << NUM_SPAWN_TYPES_WITH_DATA)-1, + SPAWN_TYPEMASK_ALL = (1 << NUM_SPAWN_TYPES)-1 }; enum SpawnGroupFlags @@ -57,21 +63,45 @@ struct SpawnGroupTemplateData SpawnGroupFlags flags; }; -struct SpawnData +namespace Trinity { namespace Impl { + template <typename T> + struct SpawnObjectTypeForImpl { static_assert(!std::is_same<T,T>::value, "This type does not have an associated spawn type!"); }; + template <> struct SpawnObjectTypeForImpl<Creature> { static constexpr SpawnObjectType value = SPAWN_TYPE_CREATURE; }; + template <> struct SpawnObjectTypeForImpl<GameObject> { static constexpr SpawnObjectType value = SPAWN_TYPE_GAMEOBJECT; }; +}} + +struct SpawnData; +struct SpawnMetadata { + static constexpr bool TypeInMask(SpawnObjectType type, SpawnObjectTypeMask mask) { return ((1 << type) & mask); } + static constexpr bool TypeHasData(SpawnObjectType type) { return (type < NUM_SPAWN_TYPES_WITH_DATA); } + static constexpr bool TypeIsValid(SpawnObjectType type) { return (type < NUM_SPAWN_TYPES); } + template <typename T> + static constexpr SpawnObjectType TypeFor = Trinity::Impl::SpawnObjectTypeForImpl<T>::value; + + SpawnData const* ToSpawnData() const { return TypeHasData(type) ? reinterpret_cast<SpawnData const*>(this) : nullptr; } + SpawnObjectType const type; uint32 spawnId = 0; + uint32 mapId = MAPID_INVALID; + bool dbData = true; + SpawnGroupTemplateData const* spawnGroupData = nullptr; + + protected: + SpawnMetadata(SpawnObjectType t) : type(t) {} +}; + +struct SpawnData : public SpawnMetadata +{ uint32 id = 0; // entry in respective _template table - WorldLocation spawnPoint; + Position spawnPoint; uint32 phaseMask = 0; int32 spawntimesecs = 0; uint8 spawnMask = 0; - SpawnGroupTemplateData const* spawnGroupData = nullptr; uint32 scriptId = 0; - bool dbData = true; protected: - SpawnData(SpawnObjectType t) : type(t) {} + SpawnData(SpawnObjectType t) : SpawnMetadata(t) {} }; enum LinkedRespawnType |
