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 | |
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)
21 files changed, 436 insertions, 342 deletions
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 705ad1a0444..627e716137a 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -668,25 +668,6 @@ enum DifficultyFlags DIFFICULTY_FLAG_DISPLAY_MYTHIC = 0x80 // Controls icon displayed on minimap when inside the instance }; -enum SpawnMask -{ - SPAWNMASK_CONTINENT = (1 << DIFFICULTY_NONE), // any maps without spawn modes - - SPAWNMASK_DUNGEON_NORMAL = (1 << DIFFICULTY_NORMAL), - SPAWNMASK_DUNGEON_HEROIC = (1 << DIFFICULTY_HEROIC), - SPAWNMASK_DUNGEON_ALL = (SPAWNMASK_DUNGEON_NORMAL | SPAWNMASK_DUNGEON_HEROIC), - - SPAWNMASK_RAID_10MAN_NORMAL = (1 << DIFFICULTY_10_N), - SPAWNMASK_RAID_25MAN_NORMAL = (1 << DIFFICULTY_25_N), - SPAWNMASK_RAID_NORMAL_ALL = (SPAWNMASK_RAID_10MAN_NORMAL | SPAWNMASK_RAID_25MAN_NORMAL), - - SPAWNMASK_RAID_10MAN_HEROIC = (1 << DIFFICULTY_10_HC), - SPAWNMASK_RAID_25MAN_HEROIC = (1 << DIFFICULTY_25_HC), - SPAWNMASK_RAID_HEROIC_ALL = (SPAWNMASK_RAID_10MAN_HEROIC | SPAWNMASK_RAID_25MAN_HEROIC), - - SPAWNMASK_RAID_ALL = (SPAWNMASK_RAID_NORMAL_ALL | SPAWNMASK_RAID_HEROIC_ALL) -}; - enum class ExpectedStatType : uint8 { CreatureHealth = 0, diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index c52f9cbbadf..6fe0243d662 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -61,6 +61,9 @@ void AreaTrigger::AddToWorld() if (!IsInWorld()) { GetMap()->GetObjectsStore().Insert<AreaTrigger>(GetGUID(), this); + if (_spawnId) + GetMap()->GetAreaTriggerBySpawnIdStore().insert(std::make_pair(_spawnId, this)); + WorldObject::AddToWorld(); } } @@ -81,6 +84,9 @@ void AreaTrigger::RemoveFromWorld() _ai->OnRemove(); WorldObject::RemoveFromWorld(); + + if (_spawnId) + Trinity::Containers::MultimapErasePair(GetMap()->GetAreaTriggerBySpawnIdStore(), _spawnId, this); GetMap()->GetObjectsStore().Remove<AreaTrigger>(GetGUID()); } } @@ -248,7 +254,7 @@ bool AreaTrigger::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool /*addTo bool AreaTrigger::CreateServer(Map* map, AreaTriggerTemplate const* areaTriggerTemplate, AreaTriggerSpawn const& position) { SetMap(map); - Relocate(position.Location); + Relocate(position.spawnPoint); if (!IsPositionValid()) { TC_LOG_ERROR("entities.areatrigger", "AreaTriggerServer (id %u) not created. Invalid coordinates (X: %f Y: %f)", @@ -267,8 +273,8 @@ bool AreaTrigger::CreateServer(Map* map, AreaTriggerTemplate const* areaTriggerT _shape = position.Shape; _maxSearchRadius = _shape.GetMaxSearchRadius(); - if (position.PhaseUseFlags || position.PhaseId || position.PhaseGroup) - PhasingHandler::InitDbPhaseShift(GetPhaseShift(), position.PhaseUseFlags, position.PhaseId, position.PhaseGroup); + if (position.phaseUseFlags || position.phaseId || position.phaseGroup) + PhasingHandler::InitDbPhaseShift(GetPhaseShift(), position.phaseUseFlags, position.phaseId, position.phaseGroup); UpdateShape(); @@ -520,7 +526,7 @@ AreaTriggerTemplate const* AreaTrigger::GetTemplate() const uint32 AreaTrigger::GetScriptId() const { if (_spawnId) - return ASSERT_NOTNULL(sAreaTriggerDataStore->GetAreaTriggerSpawn(_spawnId))->ScriptId; + return ASSERT_NOTNULL(sAreaTriggerDataStore->GetAreaTriggerSpawn(_spawnId))->scriptId; if (GetCreateProperties()) return GetCreateProperties()->ScriptId; diff --git a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h index 8630075ac42..0eb87f833d1 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h +++ b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h @@ -21,7 +21,7 @@ #include "Define.h" #include "ObjectGuid.h" #include "Optional.h" -#include "Position.h" +#include "SpawnData.h" #include <vector> #define MAX_AREATRIGGER_ENTITY_DATA 6 @@ -234,18 +234,13 @@ public: uint32 ScriptId; }; -struct AreaTriggerSpawn +struct AreaTriggerSpawn : SpawnData { - ObjectGuid::LowType SpawnId = 0; + AreaTriggerSpawn() : SpawnData(SPAWN_TYPE_AREATRIGGER) { } + AreaTriggerId Id; - WorldLocation Location; - uint32 PhaseId = 0; - uint32 PhaseGroup = 0; - uint8 PhaseUseFlags = 0; AreaTriggerShapeInfo Shape; - - uint32 ScriptId = 0; }; #endif diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index bc2963bb477..c2faf7070ae 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1411,9 +1411,15 @@ void Creature::SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDiffic data.displayid = displayId; data.equipmentId = GetCurrentEquipmentId(); if (!GetTransport()) - data.spawnPoint.WorldRelocate(this); + { + data.mapId = GetMapId(); + data.spawnPoint.Relocate(this); + } else - data.spawnPoint.WorldRelocate(mapid, GetTransOffsetX(), GetTransOffsetY(), GetTransOffsetZ(), GetTransOffsetO()); + { + data.mapId = mapid; + data.spawnPoint.Relocate(GetTransOffsetX(), GetTransOffsetY(), GetTransOffsetZ(), GetTransOffsetO()); + } data.spawntimesecs = m_respawnDelay; // prevent add data integrity problems data.spawndist = GetDefaultMovementType() == IDLE_MOTION_TYPE ? 0.0f : m_respawnradius; @@ -1879,7 +1885,7 @@ bool Creature::hasInvolvedQuest(uint32 quest_id) const CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction(); - sMapMgr->DoForAllMapsWithMapId(data->spawnPoint.GetMapId(), + sMapMgr->DoForAllMapsWithMapId(data->mapId, [spawnId, charTrans](Map* map) -> void { // despawn all active creatures, and remove their respawns diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index a3fc0223bb4..544f4464fd2 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -96,7 +96,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma void Update(uint32 time) override; // overwrited Unit::Update void GetRespawnPosition(float &x, float &y, float &z, float* ori = nullptr, float* dist = nullptr) const; - bool IsSpawnedOnTransport() const { return m_creatureData && m_creatureData->spawnPoint.GetMapId() != GetMapId(); } + bool IsSpawnedOnTransport() const { return m_creatureData && m_creatureData->mapId != GetMapId(); } void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } uint32 GetCorpseDelay() const { return m_corpseDelay; } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 131f1eb1783..2481de2880f 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1128,7 +1128,8 @@ void GameObject::SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDiff data.spawnId = m_spawnId; ASSERT(data.spawnId == m_spawnId); data.id = GetEntry(); - data.spawnPoint.WorldRelocate(this); + data.mapId = GetMapId(); + data.spawnPoint.Relocate(this); data.rotation = m_localRotation; data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime; data.animprogress = GetGoAnimProgress(); @@ -1262,7 +1263,7 @@ bool GameObject::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction(); - sMapMgr->DoForAllMapsWithMapId(data->spawnPoint.GetMapId(), + sMapMgr->DoForAllMapsWithMapId(data->mapId, [spawnId, charTrans](Map* map) -> void { // despawn all active objects, and remove their respawns diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 4a09390301e..7e22c76f2f5 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -1167,7 +1167,7 @@ void GameEventMgr::UpdateEventNPCFlags(uint16 event_id) for (NPCFlagList::iterator itr = mGameEventNPCFlags[event_id].begin(); itr != mGameEventNPCFlags[event_id].end(); ++itr) // get the creature data from the low guid to get the entry, to be able to find out the whole guid if (CreatureData const* data = sObjectMgr->GetCreatureData(itr->first)) - creaturesByMap[data->spawnPoint.GetMapId()].insert(itr->first); + creaturesByMap[data->mapId].insert(itr->first); for (auto const& p : creaturesByMap) { @@ -1234,7 +1234,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) sObjectMgr->AddCreatureToGrid(*itr, data); // Spawn if necessary (loaded grids only) - Map* map = sMapMgr->CreateBaseMap(data->spawnPoint.GetMapId()); + Map* map = sMapMgr->CreateBaseMap(data->mapId); map->RemoveRespawnTime(SPAWN_TYPE_CREATURE, *itr); // We use spawn coords to spawn if (map && !map->Instanceable() && map->IsGridLoaded(data->spawnPoint)) @@ -1257,7 +1257,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) sObjectMgr->AddGameobjectToGrid(*itr, data); // Spawn if necessary (loaded grids only) // this base map checked as non-instanced and then only existed - Map* map = sMapMgr->CreateBaseMap(data->spawnPoint.GetMapId()); + Map* map = sMapMgr->CreateBaseMap(data->mapId); map->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, *itr); // We use current coords to unspawn, not spawn coords since creature can have changed grid if (map && !map->Instanceable() && map->IsGridLoaded(data->spawnPoint)) @@ -1307,7 +1307,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) { sObjectMgr->RemoveCreatureFromGrid(*itr, data); - sMapMgr->DoForAllMapsWithMapId(data->spawnPoint.GetMapId(), [&itr](Map* map) + sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr](Map* map) { map->RemoveRespawnTime(SPAWN_TYPE_CREATURE, *itr); auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(*itr); @@ -1338,7 +1338,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) { sObjectMgr->RemoveGameobjectFromGrid(*itr, data); - sMapMgr->DoForAllMapsWithMapId(data->spawnPoint.GetMapId(), [&itr](Map* map) + sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr](Map* map) { map->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, *itr); auto gameobjectBounds = map->GetGameObjectBySpawnIdStore().equal_range(*itr); @@ -1374,7 +1374,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate) continue; // Update if spawned - sMapMgr->DoForAllMapsWithMapId(data->spawnPoint.GetMapId(), [&itr, activate](Map* map) + sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr, activate](Map* map) { auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(itr->first); for (auto itr2 = creatureBounds.first; itr2 != creatureBounds.second; ++itr2) diff --git a/src/server/game/Globals/AreaTriggerDataStore.cpp b/src/server/game/Globals/AreaTriggerDataStore.cpp index 817f59d1284..5cfee1028b9 100644 --- a/src/server/game/Globals/AreaTriggerDataStore.cpp +++ b/src/server/game/Globals/AreaTriggerDataStore.cpp @@ -340,27 +340,26 @@ void AreaTriggerDataStore::LoadAreaTriggerSpawns() continue; } - AreaTriggerSpawn spawn; - spawn.SpawnId = spawnId; + AreaTriggerSpawn& spawn = _areaTriggerSpawnsBySpawnId[spawnId]; + spawn.spawnId = spawnId; + spawn.mapId = location.GetMapId(); spawn.Id = areaTriggerid; - spawn.Location.WorldRelocate(location); + spawn.spawnPoint.Relocate(location); - spawn.PhaseUseFlags = fields[8].GetUInt8(); - spawn.PhaseId = fields[9].GetUInt32(); - spawn.PhaseGroup = fields[10].GetUInt32(); + spawn.phaseUseFlags = fields[8].GetUInt8(); + spawn.phaseId = fields[9].GetUInt32(); + spawn.phaseGroup = fields[10].GetUInt32(); spawn.Shape.Type = static_cast<AreaTriggerTypes>(shape); for (uint8 i = 0; i < MAX_AREATRIGGER_ENTITY_DATA; ++i) spawn.Shape.DefaultDatas.Data[i] = fields[12 + i].GetFloat(); - spawn.ScriptId = sObjectMgr->GetScriptId(fields[18].GetString()); + spawn.scriptId = sObjectMgr->GetScriptId(fields[18].GetString()); + spawn.spawnGroupData = sObjectMgr->GetLegacySpawnGroup(); // Add the trigger to a map::cell map, which is later used by GridLoader to query - CellCoord cellCoord = Trinity::ComputeCellCoord(spawn.Location.GetPositionX(), spawn.Location.GetPositionY()); - _areaTriggerSpawnsByLocation[{ spawn.Location.GetMapId(), cellCoord.GetId() }].insert(spawnId); - - // add the position to the map - _areaTriggerSpawnsBySpawnId[spawnId] = spawn; + CellCoord cellCoord = Trinity::ComputeCellCoord(spawn.spawnPoint.GetPositionX(), spawn.spawnPoint.GetPositionY()); + _areaTriggerSpawnsByLocation[{ spawn.mapId, cellCoord.GetId() }].insert(spawnId); } while (templates->NextRow()); } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 032573ed81a..f9e20a9a420 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1757,8 +1757,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId()); - if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId())) + MapEntry const* const map = sMapStore.LookupEntry(master->mapId); + if (!map || !map->Instanceable() || (master->mapId != slave->mapId)) { TC_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '" UI64FMTD "' linking to Creature '" UI64FMTD "' on an unpermitted map.", guidLow, linkedGuidLow); error = true; @@ -1773,8 +1773,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - guid = ObjectGuid::Create<HighGuid::Creature>(slave->spawnPoint.GetMapId(), slave->id, guidLow); - linkedGuid = ObjectGuid::Create<HighGuid::Creature>(master->spawnPoint.GetMapId(), master->id, linkedGuidLow); + guid = ObjectGuid::Create<HighGuid::Creature>(slave->mapId, slave->id, guidLow); + linkedGuid = ObjectGuid::Create<HighGuid::Creature>(master->mapId, master->id, linkedGuidLow); break; } case LINKED_RESPAWN_CREATURE_TO_GO: @@ -1795,8 +1795,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId()); - if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId())) + MapEntry const* const map = sMapStore.LookupEntry(master->mapId); + if (!map || !map->Instanceable() || (master->mapId != slave->mapId)) { TC_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '" UI64FMTD "' linking to Gameobject '" UI64FMTD "' on an unpermitted map.", guidLow, linkedGuidLow); error = true; @@ -1811,8 +1811,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - guid = ObjectGuid::Create<HighGuid::Creature>(slave->spawnPoint.GetMapId(), slave->id, guidLow); - linkedGuid = ObjectGuid::Create<HighGuid::GameObject>(master->spawnPoint.GetMapId(), master->id, linkedGuidLow); + guid = ObjectGuid::Create<HighGuid::Creature>(slave->mapId, slave->id, guidLow); + linkedGuid = ObjectGuid::Create<HighGuid::GameObject>(master->mapId, master->id, linkedGuidLow); break; } case LINKED_RESPAWN_GO_TO_GO: @@ -1833,8 +1833,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId()); - if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId())) + MapEntry const* const map = sMapStore.LookupEntry(master->mapId); + if (!map || !map->Instanceable() || (master->mapId != slave->mapId)) { TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject '" UI64FMTD "' linking to Gameobject '" UI64FMTD "' on an unpermitted map.", guidLow, linkedGuidLow); error = true; @@ -1849,8 +1849,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - guid = ObjectGuid::Create<HighGuid::GameObject>(slave->spawnPoint.GetMapId(), slave->id, guidLow); - linkedGuid = ObjectGuid::Create<HighGuid::GameObject>(master->spawnPoint.GetMapId(), master->id, linkedGuidLow); + guid = ObjectGuid::Create<HighGuid::GameObject>(slave->mapId, slave->id, guidLow); + linkedGuid = ObjectGuid::Create<HighGuid::GameObject>(master->mapId, master->id, linkedGuidLow); break; } case LINKED_RESPAWN_GO_TO_CREATURE: @@ -1871,8 +1871,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId()); - if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId())) + MapEntry const* const map = sMapStore.LookupEntry(master->mapId); + if (!map || !map->Instanceable() || (master->mapId != slave->mapId)) { TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject '" UI64FMTD "' linking to Creature '" UI64FMTD "' on an unpermitted map.", guidLow, linkedGuidLow); error = true; @@ -1887,8 +1887,8 @@ void ObjectMgr::LoadLinkedRespawn() break; } - guid = ObjectGuid::Create<HighGuid::GameObject>(slave->spawnPoint.GetMapId(), slave->id, guidLow); - linkedGuid = ObjectGuid::Create<HighGuid::Creature>(master->spawnPoint.GetMapId(), master->id, linkedGuidLow); + guid = ObjectGuid::Create<HighGuid::GameObject>(slave->mapId, slave->id, guidLow); + linkedGuid = ObjectGuid::Create<HighGuid::Creature>(master->mapId, master->id, linkedGuidLow); break; } } @@ -1908,7 +1908,7 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid CreatureData const* master = GetCreatureData(guidLow); ASSERT(master); - ObjectGuid guid = ObjectGuid::Create<HighGuid::Creature>(master->spawnPoint.GetMapId(), master->id, guidLow); + ObjectGuid guid = ObjectGuid::Create<HighGuid::Creature>(master->mapId, master->id, guidLow); if (!linkedGuidLow) // we're removing the linking { @@ -1927,8 +1927,8 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid return false; } - MapEntry const* map = sMapStore.LookupEntry(master->spawnPoint.GetMapId()); - if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId())) + MapEntry const* map = sMapStore.LookupEntry(master->mapId); + if (!map || !map->Instanceable() || (master->mapId != slave->mapId)) { TC_LOG_ERROR("sql.sql", "Creature '" UI64FMTD "' linking to '" UI64FMTD "' on an unpermitted map.", guidLow, linkedGuidLow); return false; @@ -1941,7 +1941,7 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid return false; } - ObjectGuid linkedGuid = ObjectGuid::Create<HighGuid::Creature>(slave->spawnPoint.GetMapId(), slave->id, linkedGuidLow); + ObjectGuid linkedGuid = ObjectGuid::Create<HighGuid::Creature>(slave->mapId, slave->id, linkedGuidLow); _linkedRespawnStore[guid] = linkedGuid; WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_REP_LINKED_RESPAWN); @@ -2117,7 +2117,8 @@ void ObjectMgr::LoadCreatures() CreatureData& data = _creatureDataStore[guid]; data.spawnId = guid; data.id = entry; - data.spawnPoint.WorldRelocate(fields[2].GetUInt16(), fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat(), fields[6].GetFloat()); + data.mapId = fields[2].GetUInt16(); + data.spawnPoint.Relocate(fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat(), fields[6].GetFloat()); data.displayid = fields[7].GetUInt32(); data.equipmentId = fields[8].GetInt8(); data.spawntimesecs = fields[9].GetUInt32(); @@ -2126,7 +2127,7 @@ void ObjectMgr::LoadCreatures() data.curhealth = fields[12].GetUInt32(); data.curmana = fields[13].GetUInt32(); data.movementType = fields[14].GetUInt8(); - data.spawnDifficulties = ParseSpawnDifficulties(fields[15].GetString(), "creature", guid, data.spawnPoint.GetMapId(), spawnMasks[data.spawnPoint.GetMapId()]); + data.spawnDifficulties = ParseSpawnDifficulties(fields[15].GetString(), "creature", guid, data.mapId, spawnMasks[data.mapId]); int16 gameEvent = fields[16].GetInt8(); uint32 PoolId = fields[17].GetUInt32(); data.npcflag = fields[18].GetUInt64(); @@ -2139,12 +2140,12 @@ void ObjectMgr::LoadCreatures() data.phaseGroup = fields[25].GetUInt32(); data.terrainSwapMap = fields[26].GetInt32(); data.scriptId = GetScriptId(fields[27].GetString()); - data.spawnGroupData = &_spawnGroupDataStore[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0]; // transport spawns default to compatibility group + data.spawnGroupData = IsTransportMap(data.mapId) ? GetLegacySpawnGroup() : GetDefaultSpawnGroup(); // transport spawns default to compatibility group - MapEntry const* mapEntry = sMapStore.LookupEntry(data.spawnPoint.GetMapId()); + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapId); if (!mapEntry) { - TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD ") that spawned at nonexistent map (Id: %u), skipped.", guid, data.spawnPoint.GetMapId()); + TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD ") that spawned at nonexistent map (Id: %u), skipped.", guid, data.mapId); continue; } @@ -2152,16 +2153,16 @@ void ObjectMgr::LoadCreatures() { if (VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager()) { - if (vmgr->isMapLoadingEnabled() && !IsTransportMap(data.spawnPoint.GetMapId())) + if (vmgr->isMapLoadingEnabled() && !IsTransportMap(data.mapId)) { GridCoord gridCoord = Trinity::ComputeGridCoord(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY()); int gx = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.x_coord; int gy = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.y_coord; - VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.spawnPoint.GetMapId(), gx, gy); + VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.mapId, gx, gy); if (result != VMAP::LoadResult::Success) TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD " Entry: %u MapID: %u) spawned on a possible invalid position (%s)", - guid, data.id, data.spawnPoint.GetMapId(), data.spawnPoint.ToString().c_str()); + guid, data.id, data.mapId, data.spawnPoint.ToString().c_str()); } } } @@ -2274,7 +2275,7 @@ void ObjectMgr::LoadCreatures() TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u does not exist, set to -1", guid, data.id, data.terrainSwapMap); data.terrainSwapMap = -1; } - else if (terrainSwapEntry->ParentMapID != int16(data.spawnPoint.GetMapId())) + else if (terrainSwapEntry->ParentMapID != int16(data.mapId)) { TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u which cannot be used on spawn map, set to -1", guid, data.id, data.terrainSwapMap); data.terrainSwapMap = -1; @@ -2286,7 +2287,7 @@ void ObjectMgr::LoadCreatures() uint32 zoneId = 0; uint32 areaId = 0; PhasingHandler::InitDbVisibleMapId(phaseShift, data.terrainSwapMap); - sMapMgr->GetZoneAndAreaId(phaseShift, zoneId, areaId, data.spawnPoint); + sMapMgr->GetZoneAndAreaId(phaseShift, zoneId, areaId, data.mapId, data.spawnPoint); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA); @@ -2311,7 +2312,7 @@ void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const* for (Difficulty difficulty : data->spawnDifficulties) { CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), difficulty)][cellCoord.GetId()]; + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, difficulty)][cellCoord.GetId()]; cell_guids.creatures.insert(guid); } } @@ -2321,7 +2322,7 @@ void ObjectMgr::RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData co for (Difficulty difficulty : data->spawnDifficulties) { CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), difficulty)][cellCoord.GetId()]; + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, difficulty)][cellCoord.GetId()]; cell_guids.creatures.erase(guid); } } @@ -2340,7 +2341,8 @@ ObjectGuid::LowType ObjectMgr::AddGameObjectData(uint32 entry, uint32 mapId, Pos GameObjectData& data = NewOrExistGameObjectData(spawnId); data.spawnId = spawnId; data.id = entry; - data.spawnPoint.WorldRelocate(mapId,pos); + data.mapId = mapId; + data.spawnPoint.Relocate(pos); data.rotation = rot; data.spawntimesecs = spawntimedelay; data.animprogress = 100; @@ -2388,7 +2390,8 @@ ObjectGuid::LowType ObjectMgr::AddCreatureData(uint32 entry, uint32 mapId, Posit CreatureData& data = NewOrExistCreatureData(spawnId); data.spawnId = spawnId; data.id = entry; - data.spawnPoint.WorldRelocate(mapId, pos); + data.mapId = mapId; + data.spawnPoint.Relocate(pos); data.displayid = 0; data.equipmentId = 0; data.spawntimesecs = spawntimedelay; @@ -2486,18 +2489,19 @@ void ObjectMgr::LoadGameObjects() data.spawnId = guid; data.id = entry; - data.spawnPoint.WorldRelocate(fields[2].GetUInt16(), fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat(), fields[6].GetFloat()); + data.mapId = fields[2].GetUInt16(); + data.spawnPoint.Relocate(fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat(), fields[6].GetFloat()); data.rotation.x = fields[7].GetFloat(); data.rotation.y = fields[8].GetFloat(); data.rotation.z = fields[9].GetFloat(); data.rotation.w = fields[10].GetFloat(); data.spawntimesecs = fields[11].GetInt32(); - data.spawnGroupData = &_spawnGroupDataStore[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0]; // transport spawns default to compatibility group + data.spawnGroupData = IsTransportMap(data.mapId) ? GetLegacySpawnGroup() : GetDefaultSpawnGroup(); // transport spawns default to compatibility group - MapEntry const* mapEntry = sMapStore.LookupEntry(data.spawnPoint.GetMapId()); + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapId); if (!mapEntry) { - TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u) spawned on a non-existed map (Id: %u), skip", guid, data.id, data.spawnPoint.GetMapId()); + TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u) spawned on a non-existed map (Id: %u), skip", guid, data.id, data.mapId); continue; } @@ -2505,16 +2509,16 @@ void ObjectMgr::LoadGameObjects() { if (VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager()) { - if (vmgr->isMapLoadingEnabled() && !IsTransportMap(data.spawnPoint.GetMapId())) + if (vmgr->isMapLoadingEnabled() && !IsTransportMap(data.mapId)) { GridCoord gridCoord = Trinity::ComputeGridCoord(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY()); int gx = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.x_coord; int gy = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.y_coord; - VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.spawnPoint.GetMapId(), gx, gy); + VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.mapId, gx, gy); if (result != VMAP::LoadResult::Success) TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u MapID: %u) spawned on a possible invalid position (%s)", - guid, data.id, data.spawnPoint.GetMapId(), data.spawnPoint.ToString().c_str()); + guid, data.id, data.mapId, data.spawnPoint.ToString().c_str()); } } } @@ -2538,7 +2542,7 @@ void ObjectMgr::LoadGameObjects() } data.goState = GOState(go_state); - data.spawnDifficulties = ParseSpawnDifficulties(fields[14].GetString(), "gameobject", guid, data.spawnPoint.GetMapId(), spawnMasks[data.spawnPoint.GetMapId()]); + data.spawnDifficulties = ParseSpawnDifficulties(fields[14].GetString(), "gameobject", guid, data.mapId, spawnMasks[data.mapId]); if (data.spawnDifficulties.empty()) { TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD ") that is not spawned in any difficulty, skipped.", guid); @@ -2597,7 +2601,7 @@ void ObjectMgr::LoadGameObjects() TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u does not exist, set to -1", guid, data.id, data.terrainSwapMap); data.terrainSwapMap = -1; } - else if (terrainSwapEntry->ParentMapID != int16(data.spawnPoint.GetMapId())) + else if (terrainSwapEntry->ParentMapID != int16(data.mapId)) { TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u which cannot be used on spawn map, set to -1", guid, data.id, data.terrainSwapMap); data.terrainSwapMap = -1; @@ -2630,7 +2634,7 @@ void ObjectMgr::LoadGameObjects() continue; } - if (!MapManager::IsValidMapCoord(data.spawnPoint)) + if (!MapManager::IsValidMapCoord(data.mapId, data.spawnPoint)) { TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u) with invalid coordinates, skip", guid, data.id); continue; @@ -2647,7 +2651,7 @@ void ObjectMgr::LoadGameObjects() uint32 zoneId = 0; uint32 areaId = 0; PhasingHandler::InitDbVisibleMapId(phaseShift, data.terrainSwapMap); - sMapMgr->GetZoneAndAreaId(phaseShift, zoneId, areaId, data.spawnPoint); + sMapMgr->GetZoneAndAreaId(phaseShift, zoneId, areaId, data.mapId, data.spawnPoint); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA); @@ -2743,19 +2747,15 @@ void ObjectMgr::LoadSpawnGroups() { Field* fields = result->Fetch(); uint32 groupId = fields[0].GetUInt32(); - SpawnObjectType spawnType; + SpawnObjectType spawnType = SpawnObjectType(fields[1].GetUInt8()); + if (!SpawnData::TypeIsValid(spawnType)) { - uint32 type = fields[1].GetUInt8(); - if (type >= SPAWN_TYPE_MAX) - { - TC_LOG_ERROR("sql.sql", "Spawn data with invalid type %u listed for spawn group %u. Skipped.", type, groupId); - continue; - } - spawnType = SpawnObjectType(type); + TC_LOG_ERROR("sql.sql", "Spawn data with invalid type %u listed for spawn group %u. Skipped.", uint32(spawnType), groupId); + continue; } ObjectGuid::LowType spawnId = fields[2].GetUInt64(); - SpawnData const* data = GetSpawnData(spawnType, spawnId); + SpawnMetadata const* data = GetSpawnMetadata(spawnType, spawnId); if (!data) { TC_LOG_ERROR("sql.sql", "Spawn data with ID (%u," UI64FMTD ") not found, but is listed as a member of spawn group %u!", uint32(spawnType), spawnId, groupId); @@ -2776,13 +2776,13 @@ void ObjectMgr::LoadSpawnGroups() { SpawnGroupTemplateData& groupTemplate = it->second; if (groupTemplate.mapId == SPAWNGROUP_MAP_UNSET) - groupTemplate.mapId = data->spawnPoint.GetMapId(); - else if (groupTemplate.mapId != data->spawnPoint.GetMapId() && !(groupTemplate.flags & SPAWNGROUP_FLAG_SYSTEM)) + groupTemplate.mapId = data->mapId; + else if (groupTemplate.mapId != data->mapId && !(groupTemplate.flags & SPAWNGROUP_FLAG_SYSTEM)) { - TC_LOG_ERROR("sql.sql", "Spawn group %u has map ID %u, but spawn (%u," UI64FMTD ") has map id %u - spawn NOT added to group!", groupId, groupTemplate.mapId, uint32(spawnType), spawnId, data->spawnPoint.GetMapId()); + TC_LOG_ERROR("sql.sql", "Spawn group %u has map ID %u, but spawn (%u," UI64FMTD ") has map id %u - spawn NOT added to group!", groupId, groupTemplate.mapId, uint32(spawnType), spawnId, data->mapId); continue; } - const_cast<SpawnData*>(data)->spawnGroupData = &groupTemplate; + const_cast<SpawnMetadata*>(data)->spawnGroupData = &groupTemplate; if (!(groupTemplate.flags & SPAWNGROUP_FLAG_SYSTEM)) _spawnGroupMapStore.emplace(groupId, data); ++numMembers; @@ -2849,6 +2849,24 @@ void ObjectMgr::LoadInstanceSpawnGroups() TC_LOG_INFO("server.loading", ">> Loaded %u instance spawn groups in %u ms", n, GetMSTimeDiffToNow(oldMSTime)); } +SpawnData const* ObjectMgr::GetSpawnData(SpawnObjectType type, ObjectGuid::LowType spawnId) const +{ + if (!SpawnData::TypeHasData(type)) + return nullptr; + switch (type) + { + case SPAWN_TYPE_CREATURE: + return GetCreatureData(spawnId); + case SPAWN_TYPE_GAMEOBJECT: + return GetGameObjectData(spawnId); + case SPAWN_TYPE_AREATRIGGER: + return sAreaTriggerDataStore->GetAreaTriggerSpawn(spawnId); + default: + ASSERT(false, "Invalid spawn object type %u", uint32(type)); + return nullptr; + } +} + void ObjectMgr::OnDeleteSpawnData(SpawnData const* data) { auto templateIt = _spawnGroupDataStore.find(data->spawnGroupData->groupId); @@ -2872,7 +2890,7 @@ void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData con for (Difficulty difficulty : data->spawnDifficulties) { CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), difficulty)][cellCoord.GetId()]; + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, difficulty)][cellCoord.GetId()]; cell_guids.gameobjects.insert(guid); } } @@ -2882,7 +2900,7 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat for (Difficulty difficulty : data->spawnDifficulties) { CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), difficulty)][cellCoord.GetId()]; + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, difficulty)][cellCoord.GetId()]; cell_guids.gameobjects.erase(guid); } } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index db973b2fd56..0002cea5292 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -510,7 +510,7 @@ typedef std::unordered_map<ObjectGuid::LowType, GameObjectData> GameObjectDataCo typedef std::unordered_map<ObjectGuid::LowType, GameObjectAddon> GameObjectAddonContainer; typedef std::unordered_map<uint32, std::vector<uint32>> GameObjectQuestItemMap; typedef std::unordered_map<uint32, SpawnGroupTemplateData> SpawnGroupDataContainer; -typedef std::multimap<uint32, SpawnData const*> SpawnGroupLinkContainer; +typedef std::multimap<uint32, SpawnMetadata const*> SpawnGroupLinkContainer; typedef std::unordered_map<uint16, std::vector<InstanceSpawnGroupInfo>> InstanceSpawnGroupContainer; typedef std::map<TempSummonGroupKey, std::vector<TempSummonData>> TempSummonDataContainer; typedef std::unordered_map<uint32, CreatureLocale> CreatureLocaleContainer; @@ -1430,9 +1430,10 @@ class TC_GAME_API ObjectMgr ObjectGuid::LowType GenerateGameObjectSpawnId(); SpawnGroupTemplateData const* GetSpawnGroupData(uint32 groupId) const { auto it = _spawnGroupDataStore.find(groupId); return it != _spawnGroupDataStore.end() ? &it->second : nullptr; } + SpawnGroupTemplateData const* GetSpawnGroupData(SpawnObjectType type, ObjectGuid::LowType spawnId) const { SpawnMetadata const* data = GetSpawnMetadata(type, spawnId); return data ? data->spawnGroupData : nullptr; } SpawnGroupTemplateData const* GetDefaultSpawnGroup() const { return &_spawnGroupDataStore.at(0); } SpawnGroupTemplateData const* GetLegacySpawnGroup() const { return &_spawnGroupDataStore.at(1); } - Trinity::IteratorPair<SpawnGroupLinkContainer::const_iterator> GetSpawnDataForGroup(uint32 groupId) const { return Trinity::Containers::MapEqualRange(_spawnGroupMapStore, groupId); } + Trinity::IteratorPair<SpawnGroupLinkContainer::const_iterator> GetSpawnMetadataForGroup(uint32 groupId) const { return Trinity::Containers::MapEqualRange(_spawnGroupMapStore, groupId); } std::vector<InstanceSpawnGroupInfo> const* GetSpawnGroupsForInstance(uint32 instanceId) const { auto it = _instanceSpawnGroupStore.find(instanceId); return it != _instanceSpawnGroupStore.end() ? &it->second : nullptr; } MailLevelReward const* GetMailLevelReward(uint8 level, uint8 race) const @@ -1476,29 +1477,28 @@ class TC_GAME_API ObjectMgr return nullptr; } - SpawnData const* GetSpawnData(SpawnObjectType type, ObjectGuid::LowType guid) + SpawnMetadata const* GetSpawnMetadata(SpawnObjectType type, ObjectGuid::LowType spawnId) const { - if (type == SPAWN_TYPE_CREATURE) - return GetCreatureData(guid); - else if (type == SPAWN_TYPE_GAMEOBJECT) - return GetGameObjectData(guid); + if (SpawnData::TypeHasData(type)) + return GetSpawnData(type, spawnId); else - ASSERT(false, "Invalid spawn object type %u", uint32(type)); - return nullptr; + return nullptr; } + + SpawnData const* GetSpawnData(SpawnObjectType type, ObjectGuid::LowType spawnId) const; void OnDeleteSpawnData(SpawnData const* data); CreatureDataContainer const& GetAllCreatureData() const { return _creatureDataStore; } - CreatureData const* GetCreatureData(ObjectGuid::LowType guid) const + CreatureData const* GetCreatureData(ObjectGuid::LowType spawnId) const { - CreatureDataContainer::const_iterator itr = _creatureDataStore.find(guid); + CreatureDataContainer::const_iterator itr = _creatureDataStore.find(spawnId); if (itr == _creatureDataStore.end()) return nullptr; return &itr->second; } - CreatureData& NewOrExistCreatureData(ObjectGuid::LowType guid) { return _creatureDataStore[guid]; } - void DeleteCreatureData(ObjectGuid::LowType guid); - ObjectGuid GetLinkedRespawnGuid(ObjectGuid guid) const + CreatureData& NewOrExistCreatureData(ObjectGuid::LowType spawnId) { return _creatureDataStore[spawnId]; } + void DeleteCreatureData(ObjectGuid::LowType spawnId); + ObjectGuid GetLinkedRespawnGuid(ObjectGuid spawnId) const { - LinkedRespawnContainer::const_iterator itr = _linkedRespawnStore.find(guid); + LinkedRespawnContainer::const_iterator itr = _linkedRespawnStore.find(spawnId); if (itr == _linkedRespawnStore.end()) return ObjectGuid::Empty; return itr->second; } @@ -1509,14 +1509,14 @@ class TC_GAME_API ObjectMgr return &itr->second; } GameObjectDataContainer const& GetAllGameObjectData() const { return _gameObjectDataStore; } - GameObjectData const* GetGameObjectData(ObjectGuid::LowType guid) const + GameObjectData const* GetGameObjectData(ObjectGuid::LowType spawnId) const { - GameObjectDataContainer::const_iterator itr = _gameObjectDataStore.find(guid); + GameObjectDataContainer::const_iterator itr = _gameObjectDataStore.find(spawnId); if (itr == _gameObjectDataStore.end()) return nullptr; return &itr->second; } - GameObjectData& NewOrExistGameObjectData(ObjectGuid::LowType guid) { return _gameObjectDataStore[guid]; } - void DeleteGameObjectData(ObjectGuid::LowType guid); + GameObjectData& NewOrExistGameObjectData(ObjectGuid::LowType spawnId) { return _gameObjectDataStore[spawnId]; } + void DeleteGameObjectData(ObjectGuid::LowType spawnId); GameObjectLocale const* GetGameObjectLocale(uint32 entry) const { GameObjectLocaleContainer::const_iterator itr = _gameObjectLocaleStore.find(entry); diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp index 00d590467a1..a718f455dab 100644 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ b/src/server/game/Grids/ObjectGridLoader.cpp @@ -124,51 +124,19 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord &cell, GridRefManager<T> { for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid) { - T* obj = new T; + // Don't spawn at all if there's a respawn timer + ObjectGuid::LowType guid = *i_guid; + if (!map->ShouldBeSpawnedOnGridLoad<T>(guid)) + continue; - // Don't spawn at all if there's a respawn time - if ((obj->GetTypeId() == TYPEID_UNIT && !map->GetCreatureRespawnTime(*i_guid)) || - (obj->GetTypeId() == TYPEID_GAMEOBJECT && !map->GetGORespawnTime(*i_guid)) || - (obj->GetTypeId() == TYPEID_AREATRIGGER)) + T* obj = new T; + //TC_LOG_INFO("misc", "DEBUG: LoadHelper from table: %s for (guid: " UI64FMTD ") Loading", table, guid); + if (!obj->LoadFromDB(guid, map, false, false)) { - ObjectGuid::LowType guid = *i_guid; - //TC_LOG_INFO("misc", "DEBUG: LoadHelper from table: %s for (guid: %u) Loading", table, guid); - - if (obj->GetTypeId() == TYPEID_UNIT) - { - CreatureData const* cdata = sObjectMgr->GetCreatureData(guid); - ASSERT(cdata, "Tried to load creature with spawnId " UI64FMTD ", but no such creature exists.", guid); - SpawnGroupTemplateData const* const group = cdata->spawnGroupData; - // If creature in manual spawn group, don't spawn here, unless group is already active. - if (!(group->flags & SPAWNGROUP_FLAG_SYSTEM)) - if (!map->IsSpawnGroupActive(group->groupId)) - { - delete obj; - continue; - } - } - else if (obj->GetTypeId() == TYPEID_GAMEOBJECT) - { - // If gameobject in manual spawn group, don't spawn here, unless group is already active. - GameObjectData const* godata = sObjectMgr->GetGameObjectData(guid); - ASSERT(godata, "Tried to load gameobject with spawnId " UI64FMTD ", but no such object exists.", guid); - if (!(godata->spawnGroupData->flags & SPAWNGROUP_FLAG_SYSTEM)) - if (!map->IsSpawnGroupActive(godata->spawnGroupData->groupId)) - { - delete obj; - continue; - } - } - - if (!obj->LoadFromDB(guid, map, false, false)) - { - delete obj; - continue; - } - AddObjectHelper(cell, m, count, map, obj); - } - else delete obj; + continue; + } + AddObjectHelper(cell, m, count, map, obj); } } 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); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 96bb6c29aeb..4966358b2ee 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -453,6 +453,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> Transport* GetTransport(ObjectGuid const& guid); Creature* GetCreatureBySpawnId(ObjectGuid::LowType spawnId) const; GameObject* GetGameObjectBySpawnId(ObjectGuid::LowType spawnId) const; + AreaTrigger* GetAreaTriggerBySpawnId(ObjectGuid::LowType spawnId) const; WorldObject* GetWorldObjectBySpawnId(SpawnObjectType type, ObjectGuid::LowType spawnId) const { switch (type) @@ -461,6 +462,8 @@ class TC_GAME_API Map : public GridRefManager<NGridType> return reinterpret_cast<WorldObject*>(GetCreatureBySpawnId(spawnId)); case SPAWN_TYPE_GAMEOBJECT: return reinterpret_cast<WorldObject*>(GetGameObjectBySpawnId(spawnId)); + case SPAWN_TYPE_AREATRIGGER: + return reinterpret_cast<WorldObject*>(GetAreaTriggerBySpawnId(spawnId)); default: return nullptr; } @@ -476,6 +479,10 @@ class TC_GAME_API Map : public GridRefManager<NGridType> GameObjectBySpawnIdContainer& GetGameObjectBySpawnIdStore() { return _gameobjectBySpawnIdStore; } GameObjectBySpawnIdContainer const& GetGameObjectBySpawnIdStore() const { return _gameobjectBySpawnIdStore; } + typedef std::unordered_multimap<ObjectGuid::LowType, AreaTrigger*> AreaTriggerBySpawnIdContainer; + AreaTriggerBySpawnIdContainer& GetAreaTriggerBySpawnIdStore() { return _areaTriggerBySpawnIdStore; } + AreaTriggerBySpawnIdContainer const& GetAreaTriggerBySpawnIdStore() const { return _areaTriggerBySpawnIdStore; } + std::unordered_set<Corpse*> const* GetCorpsesInCell(uint32 cellId) const { auto itr = _corpsesByCell.find(cellId); @@ -528,9 +535,12 @@ class TC_GAME_API Map : public GridRefManager<NGridType> time_t GetLinkedRespawnTime(ObjectGuid guid) const; time_t GetRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId) const { - auto const& map = GetRespawnMapForType(type); - auto it = map.find(spawnId); - return (it == map.end()) ? 0 : it->second->respawnTime; + if (auto map = GetRespawnMapForType(type)) + { + auto it = map->find(spawnId); + return (it == map->end()) ? 0 : it->second->respawnTime; + } + return 0; } time_t GetCreatureRespawnTime(ObjectGuid::LowType spawnId) const { return GetRespawnTime(SPAWN_TYPE_CREATURE, spawnId); } time_t GetGORespawnTime(ObjectGuid::LowType spawnId) const { return GetRespawnTime(SPAWN_TYPE_GAMEOBJECT, spawnId); } @@ -541,6 +551,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> void SaveRespawnInfoDB(RespawnInfo const& info, CharacterDatabaseTransaction dbTrans = nullptr); void LoadRespawnTimes(); void DeleteRespawnTimes() { UnloadAllRespawnInfos(); DeleteRespawnTimesInDB(GetId(), GetInstanceId()); } + static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId); void LoadCorpseData(); void DeleteCorpseData(); @@ -549,8 +560,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 SendUpdateTransportVisibility(Player* player); @@ -732,7 +741,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, CharacterDatabaseTransaction dbTrans = nullptr); bool AddRespawnInfo(RespawnInfo const& info); void UnloadAllRespawnInfos(); void DeleteRespawnInfo(RespawnInfo* info, CharacterDatabaseTransaction dbTrans = nullptr); @@ -745,11 +753,16 @@ class TC_GAME_API Map : public GridRefManager<NGridType> if (RespawnInfo* info = GetRespawnInfo(type, spawnId)) Respawn(info, dbTrans); } + void Respawn(RespawnInfo* info, CharacterDatabaseTransaction dbTrans = nullptr); void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction 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; @@ -801,28 +814,32 @@ class TC_GAME_API Map : public GridRefManager<NGridType> RespawnListContainer _respawnTimes; RespawnInfoMap _creatureRespawnTimesBySpawnId; RespawnInfoMap _gameObjectRespawnTimesBySpawnId; - RespawnInfoMap& GetRespawnMapForType(SpawnObjectType type) + RespawnInfoMap* GetRespawnMapForType(SpawnObjectType type) { switch (type) { default: ASSERT(false); case SPAWN_TYPE_CREATURE: - return _creatureRespawnTimesBySpawnId; + return &_creatureRespawnTimesBySpawnId; case SPAWN_TYPE_GAMEOBJECT: - return _gameObjectRespawnTimesBySpawnId; + return &_gameObjectRespawnTimesBySpawnId; + case SPAWN_TYPE_AREATRIGGER: + return nullptr; } } - RespawnInfoMap const& GetRespawnMapForType(SpawnObjectType type) const + RespawnInfoMap const* GetRespawnMapForType(SpawnObjectType type) const { switch (type) { default: ASSERT(false); case SPAWN_TYPE_CREATURE: - return _creatureRespawnTimesBySpawnId; + return &_creatureRespawnTimesBySpawnId; case SPAWN_TYPE_GAMEOBJECT: - return _gameObjectRespawnTimesBySpawnId; + return &_gameObjectRespawnTimesBySpawnId; + case SPAWN_TYPE_AREATRIGGER: + return nullptr; } } @@ -850,6 +867,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> MapStoredObjectTypesContainer _objectsStore; CreatureBySpawnIdContainer _creatureBySpawnIdStore; GameObjectBySpawnIdContainer _gameobjectBySpawnIdStore; + AreaTriggerBySpawnIdContainer _areaTriggerBySpawnIdStore; std::unordered_map<uint32/*cellId*/, std::unordered_set<Corpse*>> _corpsesByCell; std::unordered_map<ObjectGuid, Corpse*> _corpsesByPlayer; std::unordered_set<Corpse*> _corpseBones; diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index d74e87dd32c..04774ae0865 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -103,9 +103,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 d1023ffbeb2..1b96a70ecc1 100644 --- a/src/server/game/Maps/SpawnData.h +++ b/src/server/game/Maps/SpawnData.h @@ -22,21 +22,30 @@ #include "Position.h" #include <vector> +class AreaTrigger; +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 + SPAWN_TYPE_AREATRIGGER = 2,// TITLE AreaTrigger + NUM_SPAWN_TYPES_WITH_DATA, // SKIP + NUM_SPAWN_TYPES = NUM_SPAWN_TYPES_WITH_DATA // SKIP }; enum SpawnObjectTypeMask { SPAWN_TYPEMASK_CREATURE = (1 << SPAWN_TYPE_CREATURE), SPAWN_TYPEMASK_GAMEOBJECT = (1 << SPAWN_TYPE_GAMEOBJECT), + SPAWN_TYPEMASK_AREATRIGGER = (1 << SPAWN_TYPE_AREATRIGGER), - 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 @@ -59,24 +68,49 @@ 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; }; + template <> struct SpawnObjectTypeForImpl<AreaTrigger> { static constexpr SpawnObjectType value = SPAWN_TYPE_AREATRIGGER; }; +}} + +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; uint64 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; uint8 phaseUseFlags = 0; uint32 phaseId = 0; uint32 phaseGroup = 0; int32 terrainSwapMap = -1; int32 spawntimesecs = 0; std::vector<Difficulty> spawnDifficulties; - SpawnGroupTemplateData const* spawnGroupData = nullptr; uint32 scriptId = 0; - bool dbData = true; protected: - SpawnData(SpawnObjectType t) : type(t) {} + SpawnData(SpawnObjectType t) : SpawnMetadata(t) {} }; enum LinkedRespawnType diff --git a/src/server/game/Maps/enuminfo_SpawnData.cpp b/src/server/game/Maps/enuminfo_SpawnData.cpp index 92226f25572..a4ff6770ed0 100644 --- a/src/server/game/Maps/enuminfo_SpawnData.cpp +++ b/src/server/game/Maps/enuminfo_SpawnData.cpp @@ -35,6 +35,7 @@ TC_API_EXPORT EnumText EnumUtils<SpawnObjectType>::ToString(SpawnObjectType valu { case SPAWN_TYPE_CREATURE: return { "SPAWN_TYPE_CREATURE", "Creature", "" }; case SPAWN_TYPE_GAMEOBJECT: return { "SPAWN_TYPE_GAMEOBJECT", "Gameobject", "" }; + case SPAWN_TYPE_AREATRIGGER: return { "SPAWN_TYPE_AREATRIGGER", "AreaTrigger", "" }; default: throw std::out_of_range("value"); } } @@ -49,6 +50,7 @@ TC_API_EXPORT SpawnObjectType EnumUtils<SpawnObjectType>::FromIndex(size_t index { case 0: return SPAWN_TYPE_CREATURE; case 1: return SPAWN_TYPE_GAMEOBJECT; + case 2: return SPAWN_TYPE_AREATRIGGER; default: throw std::out_of_range("index"); } } diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp index 10af28c306d..d9402f7797a 100644 --- a/src/server/game/Pools/PoolMgr.cpp +++ b/src/server/game/Pools/PoolMgr.cpp @@ -177,7 +177,7 @@ void PoolGroup<Creature>::Despawn1Object(uint64 guid) { sObjectMgr->RemoveCreatureFromGrid(guid, data); - Map* map = sMapMgr->FindMap(data->spawnPoint.GetMapId(), 0); + Map* map = sMapMgr->FindMap(data->mapId, 0); if (map && !map->Instanceable()) { auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(guid); @@ -202,7 +202,7 @@ void PoolGroup<GameObject>::Despawn1Object(uint64 guid) { sObjectMgr->RemoveGameobjectFromGrid(guid, data); - Map* map = sMapMgr->FindMap(data->spawnPoint.GetMapId(), 0); + Map* map = sMapMgr->FindMap(data->mapId, 0); if (map && !map->Instanceable()) { auto gameobjectBounds = map->GetGameObjectBySpawnIdStore().equal_range(guid); @@ -323,7 +323,7 @@ void PoolGroup<Creature>::Spawn1Object(PoolObject* obj) sObjectMgr->AddCreatureToGrid(obj->guid, data); // Spawn if necessary (loaded grids only) - Map* map = sMapMgr->FindMap(data->spawnPoint.GetMapId(), 0); + Map* map = sMapMgr->FindMap(data->mapId, 0); // We use spawn coords to spawn if (map && !map->Instanceable() && map->IsGridLoaded(data->spawnPoint)) Creature::CreateCreatureFromDB(obj->guid, map); @@ -339,7 +339,7 @@ void PoolGroup<GameObject>::Spawn1Object(PoolObject* obj) sObjectMgr->AddGameobjectToGrid(obj->guid, data); // Spawn if necessary (loaded grids only) // this base map checked as non-instanced and then only existed - Map* map = sMapMgr->FindMap(data->spawnPoint.GetMapId(), 0); + Map* map = sMapMgr->FindMap(data->mapId, 0); // We use current coords to unspawn, not spawn coords since creature can have changed grid if (map && !map->Instanceable() && map->IsGridLoaded(data->spawnPoint)) { @@ -760,6 +760,8 @@ uint32 PoolMgr::IsPartOfAPool(SpawnObjectType type, ObjectGuid::LowType spawnId) return IsPartOfAPool<Creature>(spawnId); case SPAWN_TYPE_GAMEOBJECT: return IsPartOfAPool<GameObject>(spawnId); + case SPAWN_TYPE_AREATRIGGER: + return 0; default: ASSERT(false, "Invalid spawn type %u passed to PoolMgr::IsPartOfPool (with spawnId " UI64FMTD ")", uint32(type), spawnId); return 0; diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 98d599e2720..47e1c737849 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -85,13 +85,15 @@ public: return commandTable; } - static bool DoTeleport(ChatHandler* handler, WorldLocation loc) + static bool DoTeleport(ChatHandler* handler, Position pos, uint32 mapId = MAPID_INVALID) { Player* player = handler->GetSession()->GetPlayer(); - if (!MapManager::IsValidMapCoord(loc) || sObjectMgr->IsTransportMap(loc.GetMapId())) + if (mapId == MAPID_INVALID) + mapId = player->GetMapId(); + if (!MapManager::IsValidMapCoord(mapId, pos) || sObjectMgr->IsTransportMap(mapId)) { - handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, loc.GetPositionX(), loc.GetPositionY(), loc.GetMapId()); + handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, pos.GetPositionX(), pos.GetPositionY(), mapId); handler->SetSentErrorMessage(true); return false; } @@ -102,7 +104,7 @@ public: else player->SaveRecallPosition(); // save only in non-flight case - player->TeleportTo(loc); + player->TeleportTo({ mapId, pos }); return true; } @@ -116,7 +118,7 @@ public: return false; } - return DoTeleport(handler, spawnpoint->spawnPoint); + return DoTeleport(handler, spawnpoint->spawnPoint, spawnpoint->mapId); } static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant<Hyperlink<creature_entry>, uint32> cId) @@ -143,7 +145,7 @@ public: return false; } - return DoTeleport(handler, spawnpoint->spawnPoint); + return DoTeleport(handler, spawnpoint->spawnPoint, spawnpoint->mapId); } static bool HandleGoGameObjectSpawnIdCommand(ChatHandler* handler, uint32 spawnId) @@ -156,7 +158,7 @@ public: return false; } - return DoTeleport(handler, spawnpoint->spawnPoint); + return DoTeleport(handler, spawnpoint->spawnPoint, spawnpoint->mapId); } static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId) @@ -183,7 +185,7 @@ public: return false; } - return DoTeleport(handler, spawnpoint->spawnPoint); + return DoTeleport(handler, spawnpoint->spawnPoint, spawnpoint->mapId); } static bool HandleGoGraveyardCommand(ChatHandler* handler, uint32 gyId) @@ -315,7 +317,7 @@ public: handler->SetSentErrorMessage(true); return false; } - return DoTeleport(handler, { node->ContinentID, { node->Pos.X, node->Pos.Y, node->Pos.Z } }); + return DoTeleport(handler, { node->Pos.X, node->Pos.Y, node->Pos.Z }, node->ContinentID); } static bool HandleGoAreaTriggerCommand(ChatHandler* handler, Variant<Hyperlink<areatrigger>, uint32> areaTriggerId) @@ -327,7 +329,7 @@ public: handler->SetSentErrorMessage(true); return false; } - return DoTeleport(handler, { uint32(at->ContinentID), { at->Pos.X, at->Pos.Y, at->Pos.Z } }); + return DoTeleport(handler, { at->Pos.X, at->Pos.Y, at->Pos.Z }, at->ContinentID); } //teleport at coordinates @@ -428,7 +430,7 @@ public: z = std::max(map->GetStaticHeight(PhasingHandler::GetEmptyPhaseShift(), x, y, MAX_HEIGHT), map->GetWaterLevel(PhasingHandler::GetEmptyPhaseShift(), x, y)); } - return DoTeleport(handler, { mapId, { x, y, *z, o.get_value_or(0.0f) } }); + return DoTeleport(handler, { x, y, *z, o.get_value_or(0.0f) }, mapId); } template<typename T> @@ -455,7 +457,7 @@ public: static bool HandleGoOffsetCommand(ChatHandler* handler, float dX, Optional<float> dY, Optional<float> dZ, Optional<float> dO) { - WorldLocation loc = handler->GetSession()->GetPlayer()->GetWorldLocation(); + Position loc = handler->GetSession()->GetPlayer()->GetPosition(); loc.RelocateOffset({ dX, dY.get_value_or(0.0f), dZ.get_value_or(0.0f), dO.get_value_or(0.0f) }); return DoTeleport(handler, loc); @@ -620,9 +622,9 @@ public: handler->PSendSysMessage(LANG_COMMAND_BOSS_MULTIPLE_SPAWNS, boss->Name.c_str(), boss->Entry); for (CreatureData const* spawn : spawns) { - uint32 const mapId = spawn->spawnPoint.GetMapId(); + uint32 const mapId = spawn->mapId; MapEntry const* const map = ASSERT_NOTNULL(sMapStore.LookupEntry(mapId)); - handler->PSendSysMessage(LANG_COMMAND_BOSS_MULTIPLE_SPAWN_ETY, spawn->spawnId, mapId, map->MapName[handler->GetSessionDbcLocale()], spawn->spawnPoint.GetPosition().ToString().c_str()); + handler->PSendSysMessage(LANG_COMMAND_BOSS_MULTIPLE_SPAWN_ETY, spawn->spawnId, mapId, map->MapName[handler->GetSessionDbcLocale()], spawn->spawnPoint.ToString().c_str()); } handler->SetSentErrorMessage(true); return false; @@ -635,8 +637,8 @@ public: player->SaveRecallPosition(); CreatureData const* const spawn = spawns.front(); - uint32 const mapId = spawn->spawnPoint.GetMapId(); - if (!player->TeleportTo(spawn->spawnPoint)) + uint32 const mapId = spawn->mapId; + if (!player->TeleportTo({ mapId, spawn->spawnPoint })) { char const* const mapName = ASSERT_NOTNULL(sMapStore.LookupEntry(mapId))->MapName[handler->GetSessionDbcLocale()]; handler->PSendSysMessage(LANG_COMMAND_GO_BOSS_FAILED, spawn->spawnId, boss->Name.c_str(), boss->Entry, mapName); diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp index b0fdcd613d2..f0856c9a028 100644 --- a/src/server/scripts/Commands/cs_list.cpp +++ b/src/server/scripts/Commands/cs_list.cpp @@ -658,7 +658,7 @@ public: for (auto const& pair : sObjectMgr->GetAllCreatureData()) { SpawnData const& data = pair.second; - if (data.spawnPoint.GetMapId() != mapId) + if (data.mapId != mapId) continue; CreatureTemplate const* cTemp = sObjectMgr->GetCreatureTemplate(data.id); if (!cTemp) @@ -669,7 +669,7 @@ public: for (auto const& pair : sObjectMgr->GetAllGameObjectData()) { SpawnData const& data = pair.second; - if (data.spawnPoint.GetMapId() != mapId) + if (data.mapId != mapId) continue; GameObjectTemplate const* goTemp = sObjectMgr->GetGameObjectTemplate(data.id); if (!goTemp) @@ -711,25 +711,27 @@ public: map->GetRespawnInfo(respawns, SpawnObjectTypeMask(1 << type)); for (RespawnInfo const* ri : respawns) { - SpawnData const* data = sObjectMgr->GetSpawnData(ri->type, ri->spawnId); + SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(ri->type, ri->spawnId); if (!data) continue; - uint32 respawnZoneId = map->GetZoneId(PhasingHandler::GetEmptyPhaseShift(), data->spawnPoint); - if (range) + uint32 respawnZoneId = 0; + if (SpawnData const* edata = data->ToSpawnData()) { - if (!player->IsInDist(data->spawnPoint, range)) - continue; - } - else - { - if (zoneId != respawnZoneId) - continue; + respawnZoneId = map->GetZoneId(PhasingHandler::GetEmptyPhaseShift(), edata->spawnPoint); + if (range) + { + if (!player->IsInDist(edata->spawnPoint, range)) + continue; + } + else + { + if (zoneId != respawnZoneId) + continue; + } } - uint32 gridY = ri->gridId / MAX_NUMBER_OF_GRIDS; uint32 gridX = ri->gridId % MAX_NUMBER_OF_GRIDS; - std::string respawnTime = ri->respawnTime > GameTime::GetGameTime() ? secsToTimeString(uint64(ri->respawnTime - GameTime::GetGameTime()), true) : stringOverdue; handler->PSendSysMessage(UI64FMTD " | %u | [%02u,%02u] | %s (%u) | %s%s", ri->spawnId, ri->entry, gridX, gridY, GetZoneName(respawnZoneId, locale), respawnZoneId, respawnTime.c_str(), map->IsSpawnGroupActive(data->spawnGroupData->groupId) ? "" : " (inactive)"); } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 6530652fe71..db5531c9eef 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -804,7 +804,7 @@ public: return false; } - if (player->GetMapId() != data->spawnPoint.GetMapId()) + if (player->GetMapId() != data->mapId) { handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, std::to_string(lowguid).c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index f4a2e8b6adb..e109a1e793e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -380,8 +380,8 @@ class instance_icecrown_citadel : public InstanceMapScript break; case NPC_ZAFOD_BOOMBOX: if (GameObjectTemplate const* go = sObjectMgr->GetGameObjectTemplate(GO_THE_SKYBREAKER_A)) - if ((TeamInInstance == ALLIANCE && int32(data->spawnPoint.GetMapId()) == go->moTransport.SpawnMap) || - (TeamInInstance == HORDE && int32(data->spawnPoint.GetMapId()) != go->moTransport.SpawnMap)) + if ((TeamInInstance == ALLIANCE && int32(data->mapId) == go->moTransport.SpawnMap) || + (TeamInInstance == HORDE && int32(data->mapId) != go->moTransport.SpawnMap)) return entry; return 0; case NPC_IGB_MURADIN_BRONZEBEARD: |