aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp12
-rw-r--r--src/server/game/Entities/Creature/Creature.h2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp5
-rw-r--r--src/server/game/Events/GameEventMgr.cpp12
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp98
-rw-r--r--src/server/game/Globals/ObjectMgr.h52
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp50
-rw-r--r--src/server/game/Maps/Map.cpp229
-rw-r--r--src/server/game/Maps/Map.h11
-rw-r--r--src/server/game/Maps/MapManager.h7
-rw-r--r--src/server/game/Maps/SpawnData.h46
-rw-r--r--src/server/game/Pools/PoolMgr.cpp8
-rw-r--r--src/server/scripts/Commands/cs_go.cpp34
-rw-r--r--src/server/scripts/Commands/cs_list.cpp30
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp4
16 files changed, 331 insertions, 271 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 0e76a98d8a0..0cc0c86eca1 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1324,9 +1324,15 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
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;
@@ -1733,7 +1739,7 @@ bool Creature::hasInvolvedQuest(uint32 quest_id) const
SQLTransaction trans = CharacterDatabase.BeginTransaction();
- sMapMgr->DoForAllMapsWithMapId(data->spawnPoint.GetMapId(),
+ sMapMgr->DoForAllMapsWithMapId(data->mapId,
[spawnId, trans](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 5d485774f20..84aea18e5b3 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -82,7 +82,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 c5f41bae2e6..610c1730964 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -998,7 +998,8 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
data.spawnId = m_spawnId;
ASSERT(data.spawnId == m_spawnId);
data.id = GetEntry();
- data.spawnPoint.WorldRelocate(this);
+ data.mapId = GetMapId();
+ data.spawnPoint.Relocate(this);
data.phaseMask = phaseMask;
data.rotation = m_localRotation;
data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
@@ -1115,7 +1116,7 @@ bool GameObject::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap
SQLTransaction trans = CharacterDatabase.BeginTransaction();
- sMapMgr->DoForAllMapsWithMapId(data->spawnPoint.GetMapId(),
+ sMapMgr->DoForAllMapsWithMapId(data->mapId,
[spawnId, trans](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 910f740341a..544e8f9bf5f 100644
--- a/src/server/game/Events/GameEventMgr.cpp
+++ b/src/server/game/Events/GameEventMgr.cpp
@@ -1205,7 +1205,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)
{
@@ -1268,7 +1268,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->Instanceable() && map->IsGridLoaded(data->spawnPoint))
@@ -1296,7 +1296,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->Instanceable() && map->IsGridLoaded(data->spawnPoint))
@@ -1347,7 +1347,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);
@@ -1378,7 +1378,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);
@@ -1413,7 +1413,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);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 3ba31cda2cb..5ce5e3bb12f 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1787,8 +1787,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 '%u' linking to Creature '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1824,8 +1824,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 '%u' linking to Gameobject '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1861,8 +1861,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 '%u' linking to Gameobject '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1898,8 +1898,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 '%u' linking to Creature '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1953,8 +1953,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 '%u' linking to '%u' on an unpermitted map.", guidLow, linkedGuidLow);
return false;
@@ -2112,7 +2112,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();
@@ -2129,23 +2130,23 @@ void ObjectMgr::LoadCreatures()
data.unit_flags = fields[20].GetUInt32();
data.dynamicflags = fields[21].GetUInt32();
data.scriptId = GetScriptId(fields[22].GetString());
- data.spawnGroupData = &_spawnGroupDataStore[0];
+ data.spawnGroupData = GetDefaultSpawnGroup();
- 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: %u) that spawned at nonexistent map (Id: %u), skipped.", guid, data.spawnPoint.GetMapId());
+ TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u) that spawned at nonexistent map (Id: %u), skipped.", guid, data.mapId);
continue;
}
// Skip spawnMask check for transport maps
- if (!IsTransportMap(data.spawnPoint.GetMapId()))
+ if (!IsTransportMap(data.mapId))
{
- if (data.spawnMask & ~spawnMasks[data.spawnPoint.GetMapId()])
- TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u) that have wrong spawn mask %u including unsupported difficulty modes for map (Id: %u).", guid, data.spawnMask, data.spawnPoint.GetMapId());
+ if (data.spawnMask & ~spawnMasks[data.mapId])
+ TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u) that have wrong spawn mask %u including unsupported difficulty modes for map (Id: %u).", guid, data.spawnMask, data.mapId);
}
else
- data.spawnGroupData = &_spawnGroupDataStore[1]; // force compatibility group for transport spawns
+ data.spawnGroupData = GetLegacySpawnGroup(); // force compatibility group for transport spawns
bool ok = true;
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff)
@@ -2214,7 +2215,7 @@ void ObjectMgr::LoadCreatures()
{
uint32 zoneId = 0;
uint32 areaId = 0;
- sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.spawnPoint);
+ sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.mapId, data.spawnPoint);
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA);
@@ -2242,7 +2243,7 @@ void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const*
if (mask & 1)
{
CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, i)][cellCoord.GetId()];
cell_guids.creatures.insert(guid);
}
}
@@ -2256,7 +2257,7 @@ void ObjectMgr::RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData co
if (mask & 1)
{
CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, i)][cellCoord.GetId()];
cell_guids.creatures.erase(guid);
}
}
@@ -2277,7 +2278,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;
@@ -2325,7 +2327,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;
@@ -2425,18 +2428,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[0];
+ data.spawnGroupData = GetDefaultSpawnGroup();
- 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: %u 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: %u Entry: %u) spawned on a non-existed map (Id: %u), skip", guid, data.id, data.mapId);
continue;
}
@@ -2458,13 +2462,13 @@ void ObjectMgr::LoadGameObjects()
data.spawnMask = fields[14].GetUInt8();
- if (!IsTransportMap(data.spawnPoint.GetMapId()))
+ if (!IsTransportMap(data.mapId))
{
- if (data.spawnMask & ~spawnMasks[data.spawnPoint.GetMapId()])
- TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) that has wrong spawn mask %u including unsupported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.spawnPoint.GetMapId());
+ if (data.spawnMask & ~spawnMasks[data.mapId])
+ TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) that has wrong spawn mask %u including unsupported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapId);
}
else
- data.spawnGroupData = &_spawnGroupDataStore[1]; // force compatibility group for transport spawns
+ data.spawnGroupData = GetLegacySpawnGroup(); // force compatibility group for transport spawns
data.phaseMask = fields[15].GetUInt32();
int16 gameEvent = fields[16].GetInt8();
@@ -2496,7 +2500,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: %u Entry: %u) with invalid coordinates, skip", guid, data.id);
continue;
@@ -2518,7 +2522,7 @@ void ObjectMgr::LoadGameObjects()
{
uint32 zoneId = 0;
uint32 areaId = 0;
- sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.spawnPoint);
+ sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.mapId, data.spawnPoint);
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA);
@@ -2614,19 +2618,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].GetUInt32();
- SpawnData const* data = GetSpawnData(spawnType, spawnId);
+ SpawnMetadata const* data = GetSpawnMetadata(spawnType, spawnId);
if (!data)
{
TC_LOG_ERROR("sql.sql", "Spawn data with ID (%u,%u) not found, but is listed as a member of spawn group %u!", uint32(spawnType), spawnId, groupId);
@@ -2640,20 +2640,20 @@ void ObjectMgr::LoadSpawnGroups()
auto it = _spawnGroupDataStore.find(groupId);
if (it == _spawnGroupDataStore.end())
{
- TC_LOG_ERROR("sql.sql", "Spawn group %u assigned to spawn ID (%u,%u), but group is found!", groupId, uint32(spawnType), spawnId);
+ TC_LOG_ERROR("sql.sql", "Spawn group %u assigned to spawn ID (%u,%u), but group does not exist!", groupId, uint32(spawnType), spawnId);
continue;
}
else
{
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,%u) 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,%u) 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;
@@ -2746,7 +2746,7 @@ void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData con
if (mask & 1)
{
CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, i)][cellCoord.GetId()];
cell_guids.gameobjects.insert(guid);
}
}
@@ -2760,7 +2760,7 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat
if (mask & 1)
{
CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapId, i)][cellCoord.GetId()];
cell_guids.gameobjects.erase(guid);
}
}
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 01b8ec4ece9..8f8c33962a2 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -551,7 +551,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;
@@ -1267,9 +1267,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(uint32 level, uint32 raceMask) const
@@ -1321,29 +1322,42 @@ 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
+ {
+ if (!SpawnData::TypeHasData(type))
+ return nullptr;
+ switch (type)
+ {
+ case SPAWN_TYPE_CREATURE:
+ return GetCreatureData(spawnId);
+ case SPAWN_TYPE_GAMEOBJECT:
+ return GetGameObjectData(spawnId);
+ default:
+ ASSERT(false, "Invalid spawn object type %u", uint32(type));
+ return nullptr;
+ }
}
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;
}
@@ -1354,14 +1368,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 15a3f427ccd..63326d8ab84 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -119,49 +119,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)))
+ T* obj = new T;
+ //TC_LOG_INFO("misc", "DEBUG: LoadHelper from table: %s for (guid: %u) 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 %u, 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 %u, 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 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
diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp
index 83be9b7990b..45407c4c5aa 100644
--- a/src/server/game/Pools/PoolMgr.cpp
+++ b/src/server/game/Pools/PoolMgr.cpp
@@ -170,7 +170,7 @@ void PoolGroup<Creature>::Despawn1Object(ObjectGuid::LowType guid)
{
sObjectMgr->RemoveCreatureFromGrid(guid, data);
- Map* map = sMapMgr->CreateBaseMap(data->spawnPoint.GetMapId());
+ Map* map = sMapMgr->CreateBaseMap(data->mapId);
if (!map->Instanceable())
{
auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(guid);
@@ -195,7 +195,7 @@ void PoolGroup<GameObject>::Despawn1Object(ObjectGuid::LowType guid)
{
sObjectMgr->RemoveGameobjectFromGrid(guid, data);
- Map* map = sMapMgr->CreateBaseMap(data->spawnPoint.GetMapId());
+ Map* map = sMapMgr->CreateBaseMap(data->mapId);
if (!map->Instanceable())
{
auto gameobjectBounds = map->GetGameObjectBySpawnIdStore().equal_range(guid);
@@ -316,7 +316,7 @@ void PoolGroup<Creature>::Spawn1Object(PoolObject* obj)
sObjectMgr->AddCreatureToGrid(obj->guid, data);
// Spawn if necessary (loaded grids only)
- Map* map = sMapMgr->CreateBaseMap(data->spawnPoint.GetMapId());
+ Map* map = sMapMgr->CreateBaseMap(data->mapId);
// We use spawn coords to spawn
if (!map->Instanceable() && map->IsGridLoaded(data->spawnPoint))
{
@@ -340,7 +340,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->CreateBaseMap(data->spawnPoint.GetMapId());
+ Map* map = sMapMgr->CreateBaseMap(data->mapId);
// We use current coords to unspawn, not spawn coords since creature can have changed grid
if (!map->Instanceable() && map->IsGridLoaded(data->spawnPoint))
{
diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp
index 9122099ff92..171185428cb 100644
--- a/src/server/scripts/Commands/cs_go.cpp
+++ b/src/server/scripts/Commands/cs_go.cpp
@@ -79,13 +79,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;
}
@@ -96,7 +98,7 @@ public:
else
player->SaveRecallPosition(); // save only in non-flight case
- player->TeleportTo(loc);
+ player->TeleportTo({ mapId, pos });
return true;
}
@@ -110,7 +112,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)
@@ -137,7 +139,7 @@ public:
return false;
}
- return DoTeleport(handler, spawnpoint->spawnPoint);
+ return DoTeleport(handler, spawnpoint->spawnPoint, spawnpoint->mapId);
}
static bool HandleGoGameObjectSpawnIdCommand(ChatHandler* handler, uint32 spawnId)
@@ -150,7 +152,7 @@ public:
return false;
}
- return DoTeleport(handler, spawnpoint->spawnPoint);
+ return DoTeleport(handler, spawnpoint->spawnPoint, spawnpoint->mapId);
}
static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId)
@@ -177,7 +179,7 @@ public:
return false;
}
- return DoTeleport(handler, spawnpoint->spawnPoint);
+ return DoTeleport(handler, spawnpoint->spawnPoint, spawnpoint->mapId);
}
static bool HandleGoGraveyardCommand(ChatHandler* handler, uint32 gyId)
@@ -247,7 +249,7 @@ public:
handler->SetSentErrorMessage(true);
return false;
}
- return DoTeleport(handler, { node->map_id, { node->x, node->y, node->z } });
+ return DoTeleport(handler, { node->x, node->y, node->z }, node->map_id);
}
static bool HandleGoAreaTriggerCommand(ChatHandler* handler, Variant<Hyperlink<areatrigger>, uint32> areaTriggerId)
@@ -259,7 +261,7 @@ public:
handler->SetSentErrorMessage(true);
return false;
}
- return DoTeleport(handler, { at->mapid, { at->x, at->y, at->z } });
+ return DoTeleport(handler, { at->x, at->y, at->z }, at->mapid);
}
//teleport at coordinates
@@ -357,7 +359,7 @@ public:
z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(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);
}
static bool HandleGoTicketCommand(ChatHandler* handler, uint32 ticketId)
@@ -383,7 +385,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);
@@ -548,9 +550,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->name[handler->GetSessionDbcLocale()], spawn->spawnPoint.GetPosition().ToString().c_str());
+ handler->PSendSysMessage(LANG_COMMAND_BOSS_MULTIPLE_SPAWN_ETY, spawn->spawnId, mapId, map->name[handler->GetSessionDbcLocale()], spawn->spawnPoint.ToString().c_str());
}
handler->SetSentErrorMessage(true);
return false;
@@ -563,8 +565,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))->name[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 e264e7153c3..430a496b418 100644
--- a/src/server/scripts/Commands/cs_list.cpp
+++ b/src/server/scripts/Commands/cs_list.cpp
@@ -656,7 +656,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)
@@ -667,7 +667,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)
@@ -709,25 +709,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(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(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("%u | %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 358be467e39..f60a0225b97 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -763,7 +763,7 @@ public:
return false;
}
- if (player->GetMapId() != data->spawnPoint.GetMapId())
+ if (player->GetMapId() != data->mapId)
{
handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
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 1b39a2eb476..abcce451423 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 && data->spawnPoint.GetMapId() == go->moTransport.mapID) ||
- (TeamInInstance == HORDE && data->spawnPoint.GetMapId() != go->moTransport.mapID))
+ if ((TeamInInstance == ALLIANCE && data->mapId == go->moTransport.mapID) ||
+ (TeamInInstance == HORDE && data->mapId != go->moTransport.mapID))
return entry;
return 0;
case NPC_IGB_MURADIN_BRONZEBEARD: