aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Globals/ObjectMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Globals/ObjectMgr.cpp')
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp453
1 files changed, 359 insertions, 94 deletions
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index c6cb3c06b78..451cd847213 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1123,7 +1123,7 @@ void ObjectMgr::LoadGameObjectAddons()
ObjectGuid::LowType guid = fields[0].GetUInt32();
- GameObjectData const* goData = GetGOData(guid);
+ GameObjectData const* goData = GetGameObjectData(guid);
if (!goData)
{
TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) does not exist but has a record in `gameobject_addon`", guid);
@@ -1461,8 +1461,8 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
- MapEntry const* const map = sMapStore.LookupEntry(master->mapid);
- if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
+ MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId());
+ if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId()))
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '%u' linking to Creature '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1490,7 +1490,7 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
- GameObjectData const* master = GetGOData(linkedGuidLow);
+ GameObjectData const* master = GetGameObjectData(linkedGuidLow);
if (!master)
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject (linkedGuid) '%u' not found in gameobject table", linkedGuidLow);
@@ -1498,8 +1498,8 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
- MapEntry const* const map = sMapStore.LookupEntry(master->mapid);
- if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
+ MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId());
+ if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId()))
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '%u' linking to Gameobject '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1519,7 +1519,7 @@ void ObjectMgr::LoadLinkedRespawn()
}
case GO_TO_GO:
{
- GameObjectData const* slave = GetGOData(guidLow);
+ GameObjectData const* slave = GetGameObjectData(guidLow);
if (!slave)
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject (guid) '%u' not found in gameobject table", guidLow);
@@ -1527,7 +1527,7 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
- GameObjectData const* master = GetGOData(linkedGuidLow);
+ GameObjectData const* master = GetGameObjectData(linkedGuidLow);
if (!master)
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject (linkedGuid) '%u' not found in gameobject table", linkedGuidLow);
@@ -1535,8 +1535,8 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
- MapEntry const* const map = sMapStore.LookupEntry(master->mapid);
- if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
+ MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId());
+ if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId()))
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject '%u' linking to Gameobject '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1556,7 +1556,7 @@ void ObjectMgr::LoadLinkedRespawn()
}
case GO_TO_CREATURE:
{
- GameObjectData const* slave = GetGOData(guidLow);
+ GameObjectData const* slave = GetGameObjectData(guidLow);
if (!slave)
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject (guid) '%u' not found in gameobject table", guidLow);
@@ -1572,8 +1572,8 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
- MapEntry const* const map = sMapStore.LookupEntry(master->mapid);
- if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
+ MapEntry const* const map = sMapStore.LookupEntry(master->spawnPoint.GetMapId());
+ if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId()))
{
TC_LOG_ERROR("sql.sql", "LinkedRespawn: Gameobject '%u' linking to Creature '%u' on an unpermitted map.", guidLow, linkedGuidLow);
error = true;
@@ -1626,8 +1626,8 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid
return false;
}
- MapEntry const* map = sMapStore.LookupEntry(master->mapid);
- if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
+ MapEntry const* map = sMapStore.LookupEntry(master->spawnPoint.GetMapId());
+ if (!map || !map->Instanceable() || (master->spawnPoint.GetMapId() != slave->spawnPoint.GetMapId()))
{
TC_LOG_ERROR("sql.sql", "Creature '%u' linking to '%u' on an unpermitted map.", guidLow, linkedGuidLow);
return false;
@@ -1741,8 +1741,8 @@ void ObjectMgr::LoadCreatures()
{
uint32 oldMSTime = getMSTime();
- // 0 1 2 3 4 5 6 7 8 9 10
- QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, "
+ // 0 1 2 3 4 5 6 7 8 9 10
+ QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, position_x, position_y, position_z, orientation, modelid, equipment_id, spawntimesecs, spawndist, "
// 11 12 13 14 15 16 17 18 19 20 21
"currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags, "
// 22
@@ -1782,14 +1782,11 @@ void ObjectMgr::LoadCreatures()
}
CreatureData& data = _creatureDataStore[guid];
+ data.spawnId = guid;
data.id = entry;
- data.mapid = fields[2].GetUInt16();
- data.displayid = fields[3].GetUInt32();
- data.equipmentId = fields[4].GetInt8();
- data.posX = fields[5].GetFloat();
- data.posY = fields[6].GetFloat();
- data.posZ = fields[7].GetFloat();
- data.orientation = fields[8].GetFloat();
+ data.spawnPoint.WorldRelocate(fields[2].GetUInt16(), 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();
data.spawndist = fields[10].GetFloat();
data.currentwaypoint= fields[11].GetUInt32();
@@ -1803,18 +1800,19 @@ void ObjectMgr::LoadCreatures()
data.npcflag = fields[19].GetUInt32();
data.unit_flags = fields[20].GetUInt32();
data.dynamicflags = fields[21].GetUInt32();
- data.ScriptId = GetScriptId(fields[22].GetString());
+ data.scriptId = GetScriptId(fields[22].GetString());
+ data.spawnGroupData = &_spawnGroupDataStore[0];
- MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid);
+ MapEntry const* mapEntry = sMapStore.LookupEntry(data.spawnPoint.GetMapId());
if (!mapEntry)
{
- TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u) that spawned at nonexistent map (Id: %u), skipped.", guid, data.mapid);
+ TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u) that spawned at nonexistent map (Id: %u), skipped.", guid, data.spawnPoint.GetMapId());
continue;
}
// Skip spawnMask check for transport maps
- if (!IsTransportMap(data.mapid) && 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);
+ if (!IsTransportMap(data.spawnPoint.GetMapId()) && 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());
bool ok = true;
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff)
@@ -1879,17 +1877,11 @@ void ObjectMgr::LoadCreatures()
data.phaseMask = 1;
}
- if (std::abs(data.orientation) > 2 * float(M_PI))
- {
- TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u Entry: %u) with abs(`orientation`) > 2*PI (orientation is expressed in radians), normalized.", guid, data.id);
- data.orientation = Position::NormalizeOrientation(data.orientation);
- }
-
if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA))
{
uint32 zoneId = 0;
uint32 areaId = 0;
- sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.mapid, data.posX, data.posY, data.posZ);
+ sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.spawnPoint);
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA);
@@ -1916,8 +1908,8 @@ void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const*
{
if (mask & 1)
{
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->posX, data->posY);
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
+ CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
cell_guids.creatures.insert(guid);
}
}
@@ -1930,14 +1922,14 @@ void ObjectMgr::RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData co
{
if (mask & 1)
{
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->posX, data->posY);
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
+ CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
cell_guids.creatures.erase(guid);
}
}
}
-ObjectGuid::LowType ObjectMgr::AddGOData(uint32 entry, uint32 mapId, Position const& pos, QuaternionData const& rot, uint32 spawntimedelay /*= 0*/)
+ObjectGuid::LowType ObjectMgr::AddGameObjectData(uint32 entry, uint32 mapId, Position const& pos, QuaternionData const& rot, uint32 spawntimedelay /*= 0*/)
{
GameObjectTemplate const* goinfo = GetGameObjectTemplate(entry);
if (!goinfo)
@@ -1947,41 +1939,40 @@ ObjectGuid::LowType ObjectMgr::AddGOData(uint32 entry, uint32 mapId, Position co
if (!map)
return 0;
- ObjectGuid::LowType guid = GenerateGameObjectSpawnId();
+ ObjectGuid::LowType spawnId = GenerateGameObjectSpawnId();
- GameObjectData& data = NewGOData(guid);
+ GameObjectData& data = NewOrExistGameObjectData(spawnId);
+ data.spawnId = spawnId;
data.id = entry;
- data.mapid = mapId;
-
- pos.GetPosition(data.posX, data.posY, data.posZ, data.orientation);
-
+ data.spawnPoint.WorldRelocate(mapId,pos);
data.rotation = rot;
data.spawntimesecs = spawntimedelay;
data.animprogress = 100;
data.spawnMask = 1;
- data.go_state = GO_STATE_READY;
+ data.goState = GO_STATE_READY;
data.phaseMask = PHASEMASK_NORMAL;
data.artKit = goinfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT ? 21 : 0;
- data.dbData = false;
+ data.dbData = false;
+ data.spawnGroupData = GetLegacySpawnGroup();
- AddGameobjectToGrid(guid, &data);
+ AddGameobjectToGrid(spawnId, &data);
// Spawn if necessary (loaded grids only)
// We use spawn coords to spawn
- if (!map->Instanceable() && map->IsGridLoaded(data.posX, data.posY))
+ if (!map->Instanceable() && map->IsGridLoaded(data.spawnPoint))
{
GameObject* go = new GameObject;
- if (!go->LoadGameObjectFromDB(guid, map))
+ if (!go->LoadFromDB(spawnId, map, true))
{
- TC_LOG_ERROR("misc", "AddGOData: cannot add gameobject entry %u to map", entry);
+ TC_LOG_ERROR("misc", "AddGameObjectData: cannot add gameobject entry %u to map", entry);
delete go;
return 0;
}
}
- TC_LOG_DEBUG("maps", "AddGOData: dbguid %u entry %u map %u x %f y %f z %f o %f", guid, entry, mapId, data.posX, data.posY, data.posZ, data.orientation);
+ TC_LOG_DEBUG("maps", "AddGameObjectData: dbguid %u entry %u map %u pos %s", spawnId, entry, mapId, data.spawnPoint.ToString().c_str());
- return guid;
+ return spawnId;
}
@@ -1997,15 +1988,13 @@ ObjectGuid::LowType ObjectMgr::AddCreatureData(uint32 entry, uint32 mapId, Posit
if (!map)
return 0;
- ObjectGuid::LowType guid = GenerateCreatureSpawnId();
- CreatureData& data = NewOrExistCreatureData(guid);
+ ObjectGuid::LowType spawnId = GenerateCreatureSpawnId();
+ CreatureData& data = NewOrExistCreatureData(spawnId);
+ data.spawnId = spawnId;
data.id = entry;
- data.mapid = mapId;
+ data.spawnPoint.WorldRelocate(mapId, pos);
data.displayid = 0;
data.equipmentId = 0;
-
- pos.GetPosition(data.posX, data.posY, data.posZ, data.orientation);
-
data.spawntimesecs = spawntimedelay;
data.spawndist = 0;
data.currentwaypoint = 0;
@@ -2018,14 +2007,15 @@ ObjectGuid::LowType ObjectMgr::AddCreatureData(uint32 entry, uint32 mapId, Posit
data.npcflag = cInfo->npcflag;
data.unit_flags = cInfo->unit_flags;
data.dynamicflags = cInfo->dynamicflags;
+ data.spawnGroupData = GetLegacySpawnGroup();
- AddCreatureToGrid(guid, &data);
+ AddCreatureToGrid(spawnId, &data);
// We use spawn coords to spawn
- if (!map->Instanceable() && !map->IsRemovalGrid(data.posX, data.posY))
+ if (!map->Instanceable() && !map->IsRemovalGrid(data.spawnPoint))
{
Creature* creature = new Creature();
- if (!creature->LoadCreatureFromDB(guid, map))
+ if (!creature->LoadFromDB(spawnId, map, true, true))
{
TC_LOG_ERROR("misc", "AddCreature: Cannot add creature entry %u to map", entry);
delete creature;
@@ -2033,10 +2023,10 @@ ObjectGuid::LowType ObjectMgr::AddCreatureData(uint32 entry, uint32 mapId, Posit
}
}
- return guid;
+ return spawnId;
}
-void ObjectMgr::LoadGameobjects()
+void ObjectMgr::LoadGameObjects()
{
uint32 oldMSTime = getMSTime();
@@ -2100,22 +2090,20 @@ void ObjectMgr::LoadGameobjects()
GameObjectData& data = _gameObjectDataStore[guid];
+ data.spawnId = guid;
data.id = entry;
- data.mapid = fields[2].GetUInt16();
- data.posX = fields[3].GetFloat();
- data.posY = fields[4].GetFloat();
- data.posZ = fields[5].GetFloat();
- data.orientation = fields[6].GetFloat();
+ data.spawnPoint.WorldRelocate(fields[2].GetUInt16(), 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];
- MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid);
+ MapEntry const* mapEntry = sMapStore.LookupEntry(data.spawnPoint.GetMapId());
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.mapid);
+ 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());
continue;
}
@@ -2133,24 +2121,18 @@ void ObjectMgr::LoadGameobjects()
TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip", guid, data.id, go_state);
continue;
}
- data.go_state = GOState(go_state);
+ data.goState = GOState(go_state);
data.spawnMask = fields[14].GetUInt8();
- if (!IsTransportMap(data.mapid) && 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);
+ if (!IsTransportMap(data.spawnPoint.GetMapId()) && 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());
data.phaseMask = fields[15].GetUInt32();
int16 gameEvent = fields[16].GetInt8();
uint32 PoolId = fields[17].GetUInt32();
- data.ScriptId = GetScriptId(fields[18].GetString());
-
- if (std::abs(data.orientation) > 2 * float(M_PI))
- {
- TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with abs(`orientation`) > 2*PI (orientation is expressed in radians), normalized.", guid, data.id);
- data.orientation = Position::NormalizeOrientation(data.orientation);
- }
+ data.scriptId = GetScriptId(fields[18].GetString());
if (data.rotation.x < -1.0f || data.rotation.x > 1.0f)
{
@@ -2176,7 +2158,7 @@ void ObjectMgr::LoadGameobjects()
continue;
}
- if (!MapManager::IsValidMapCoord(data.mapid, data.posX, data.posY, data.posZ, data.orientation))
+ if (!MapManager::IsValidMapCoord(data.spawnPoint))
{
TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid coordinates, skip", guid, data.id);
continue;
@@ -2192,7 +2174,7 @@ void ObjectMgr::LoadGameobjects()
{
uint32 zoneId = 0;
uint32 areaId = 0;
- sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.mapid, data.posX, data.posY, data.posZ);
+ sMapMgr->GetZoneAndAreaId(zoneId, areaId, data.spawnPoint);
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA);
@@ -2211,6 +2193,153 @@ void ObjectMgr::LoadGameobjects()
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " gameobjects in %u ms", _gameObjectDataStore.size(), GetMSTimeDiffToNow(oldMSTime));
}
+void ObjectMgr::LoadSpawnGroupTemplates()
+{
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2
+ QueryResult result = WorldDatabase.Query("SELECT groupId, groupName, groupFlags FROM spawn_group_template");
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 groupId = fields[0].GetUInt32();
+ SpawnGroupTemplateData& group = _spawnGroupDataStore[groupId];
+ group.groupId = groupId;
+ group.name = fields[1].GetString();
+ group.mapId = SPAWNGROUP_MAP_UNSET;
+ uint32 flags = fields[2].GetUInt32();
+ if (flags & ~SPAWNGROUP_FLAGS_ALL)
+ {
+ flags &= SPAWNGROUP_FLAGS_ALL;
+ TC_LOG_ERROR("server.loading", "Invalid spawn group flag %u on group ID %u (%s), reduced to valid flag %u.", flags, groupId, group.name.c_str(), uint32(group.flags));
+ }
+ if (flags & SPAWNGROUP_FLAG_SYSTEM && flags & SPAWNGROUP_FLAG_MANUAL_SPAWN)
+ {
+ flags &= ~SPAWNGROUP_FLAG_MANUAL_SPAWN;
+ TC_LOG_ERROR("server.loading", "System spawn group %u (%s) has invalid manual spawn flag. Ignored.", groupId, group.name.c_str());
+ }
+ group.flags = SpawnGroupFlags(flags);
+ group.isActive = !(group.flags & SPAWNGROUP_FLAG_MANUAL_SPAWN);
+ } while (result->NextRow());
+ }
+
+ if (_spawnGroupDataStore.find(0) == _spawnGroupDataStore.end())
+ {
+ TC_LOG_ERROR("server.loading", "Default spawn group (index 0) is missing from DB! Manually inserted.");
+ SpawnGroupTemplateData& data = _spawnGroupDataStore[0];
+ data.groupId = 0;
+ data.name = "Default Group";
+ data.mapId = 0;
+ data.flags = SPAWNGROUP_FLAG_SYSTEM;
+ data.isActive = true;
+ }
+ if (_spawnGroupDataStore.find(1) == _spawnGroupDataStore.end())
+ {
+ TC_LOG_ERROR("server.loading", "Default legacy spawn group (index 1) is missing from DB! Manually inserted.");
+ SpawnGroupTemplateData&data = _spawnGroupDataStore[1];
+ data.groupId = 1;
+ data.name = "Legacy Group";
+ data.mapId = 0;
+ data.flags = SpawnGroupFlags(SPAWNGROUP_FLAG_SYSTEM | SPAWNGROUP_FLAG_COMPATIBILITY_MODE);
+ data.isActive = true;
+ }
+
+ if (result)
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " spawn group templates in %u ms", _spawnGroupDataStore.size(), GetMSTimeDiffToNow(oldMSTime));
+ else
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 spawn group templates. DB table `spawn_group_template` is empty.");
+
+ return;
+}
+
+void ObjectMgr::LoadSpawnGroups()
+{
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2
+ QueryResult result = WorldDatabase.Query("SELECT groupId, spawnType, spawnId FROM spawn_group");
+
+ if (!result)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 spawn group members. DB table `spawn_group` is empty.");
+ return;
+ }
+
+ uint32 numMembers = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 groupId = fields[0].GetUInt32();
+ SpawnObjectType spawnType;
+ {
+ uint32 type = fields[1].GetUInt8();
+ if (type >= SPAWN_TYPE_MAX)
+ {
+ TC_LOG_ERROR("server.loading", "Spawn data with invalid type %u listed for spawn group %u. Skipped.", type, groupId);
+ continue;
+ }
+ spawnType = SpawnObjectType(type);
+ }
+ ObjectGuid::LowType spawnId = fields[2].GetUInt32();
+
+ SpawnData const* data = GetSpawnData(spawnType, spawnId);
+ if (!data)
+ {
+ TC_LOG_ERROR("server.loading", "Spawn data with ID (%u,%u) not found, but is listed as a member of spawn group %u!", uint32(spawnType), spawnId, groupId);
+ continue;
+ }
+ else if (data->spawnGroupData->groupId)
+ {
+ TC_LOG_ERROR("server.loading", "Spawn with ID (%u,%u) is listed as a member of spawn group %u, but is already a member of spawn group %u. Skipping.", uint32(spawnType), spawnId, groupId, data->spawnGroupData->groupId);
+ continue;
+ }
+ auto it = _spawnGroupDataStore.find(groupId);
+ if (it == _spawnGroupDataStore.end())
+ {
+ TC_LOG_ERROR("server.loading", "Spawn group %u assigned to spawn ID (%u,%u), but group is found!", 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))
+ {
+ TC_LOG_ERROR("server.loading", "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());
+ continue;
+ }
+ const_cast<SpawnData*>(data)->spawnGroupData = &groupTemplate;
+ if (!(groupTemplate.flags & SPAWNGROUP_FLAG_SYSTEM))
+ _spawnGroupMapStore.emplace(groupId, data);
+ ++numMembers;
+ }
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u spawn group members in %u ms", numMembers, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void ObjectMgr::OnDeleteSpawnData(SpawnData const* data)
+{
+ auto templateIt = _spawnGroupDataStore.find(data->spawnGroupData->groupId);
+ ASSERT(templateIt != _spawnGroupDataStore.end(), "Creature data for (%u,%u) is being deleted and has invalid spawn group index %u!", uint32(data->type), data->spawnId, data->spawnGroupData->groupId);
+ if (templateIt->second.flags & SPAWNGROUP_FLAG_SYSTEM) // system groups don't store their members in the map
+ return;
+
+ auto pair = _spawnGroupMapStore.equal_range(data->spawnGroupData->groupId);
+ for (auto it = pair.first; it != pair.second; ++it)
+ {
+ if (it->second != data)
+ continue;
+ _spawnGroupMapStore.erase(it);
+ return;
+ }
+ ASSERT(false, "Spawn data (%u,%u) being removed is member of spawn group %u, but not actually listed in the lookup table for that group!", uint32(data->type), data->spawnId, data->spawnGroupData->groupId);
+}
+
void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData const* data)
{
uint8 mask = data->spawnMask;
@@ -2218,8 +2347,8 @@ void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData con
{
if (mask & 1)
{
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->posX, data->posY);
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
+ CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
cell_guids.gameobjects.insert(guid);
}
}
@@ -2232,8 +2361,8 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat
{
if (mask & 1)
{
- CellCoord cellCoord = Trinity::ComputeCellCoord(data->posX, data->posY);
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
+ CellCoord cellCoord = Trinity::ComputeCellCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY());
+ CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->spawnPoint.GetMapId(), i)][cellCoord.GetId()];
cell_guids.gameobjects.erase(guid);
}
}
@@ -4881,7 +5010,7 @@ void ObjectMgr::LoadScripts(ScriptsType type)
case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
{
- GameObjectData const* data = GetGOData(tmp.RespawnGameobject.GOGuid);
+ GameObjectData const* data = GetGameObjectData(tmp.RespawnGameobject.GOGuid);
if (!data)
{
TC_LOG_ERROR("sql.sql", "Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",
@@ -4931,7 +5060,7 @@ void ObjectMgr::LoadScripts(ScriptsType type)
case SCRIPT_COMMAND_OPEN_DOOR:
case SCRIPT_COMMAND_CLOSE_DOOR:
{
- GameObjectData const* data = GetGOData(tmp.ToggleDoor.GOGuid);
+ GameObjectData const* data = GetGameObjectData(tmp.ToggleDoor.GOGuid);
if (!data)
{
TC_LOG_ERROR("sql.sql", "Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",
@@ -6586,12 +6715,142 @@ uint32 ObjectMgr::GenerateGameObjectSpawnId()
{
if (_gameObjectSpawnId >= uint32(0xFFFFFF))
{
- TC_LOG_ERROR("misc", "Creature spawn id overflow!! Can't continue, shutting down server. Search on forum for TCE00007 for more info. ");
+ TC_LOG_ERROR("misc", "GameObject spawn id overflow!! Can't continue, shutting down server. Search on forum for TCE00007 for more info. ");
World::StopNow(ERROR_EXIT_CODE);
}
return _gameObjectSpawnId++;
}
+bool ObjectMgr::SpawnGroupSpawn(uint32 groupId, Map* map, bool ignoreRespawn, bool force, std::vector<WorldObject*>* spawnedObjects)
+{
+ auto itr = _spawnGroupDataStore.find(groupId);
+ if (itr == _spawnGroupDataStore.end() || itr->second.flags & SPAWNGROUP_FLAG_SYSTEM)
+ {
+ TC_LOG_ERROR("maps", "Tried to despawn non-existing (or system) spawn group %u. Blocked.", groupId);
+ return false;
+ }
+
+ if (!map)
+ {
+ TC_LOG_ERROR("maps", "Tried to despawn creature group %u, but no map was supplied. Blocked.", groupId);
+ return false;
+ }
+
+ if (itr->second.mapId != map->GetId())
+ {
+ TC_LOG_ERROR("maps", "Tried to despawn creature group %u, but supplied map is %u, creature group has map %u. Blocked.", groupId, map->GetId(), itr->second.mapId);
+ return false;
+ }
+
+ for (auto& pair : GetSpawnDataForGroup(groupId))
+ {
+ SpawnData const* data = pair.second;
+ ASSERT(itr->second.mapId == data->spawnPoint.GetMapId());
+ // Check if there's already an instance spawned
+ if (!force)
+ if (WorldObject* obj = map->GetWorldObjectBySpawnId(data->type, data->spawnId))
+ if ((data->type != SPAWN_TYPE_CREATURE) || obj->ToCreature()->IsAlive())
+ continue;
+
+ time_t respawnTime = map->GetRespawnTime(data->type, data->spawnId);
+ if (respawnTime && respawnTime > time(NULL))
+ {
+ if (!force && !ignoreRespawn)
+ continue;
+
+ // we need to remove the respawn time, otherwise we'd end up double spawning
+ map->RemoveRespawnTime(data->type, data->spawnId, false);
+ }
+
+ // don't spawn if the grid isn't loaded (will be handled in grid loader)
+ if (!map->IsGridLoaded(data->spawnPoint))
+ continue;
+
+ // Everything OK, now do the actual (re)spawn
+ switch (data->type)
+ {
+ case SPAWN_TYPE_CREATURE:
+ {
+ Creature* creature = new Creature();
+ if (!creature->LoadFromDB(data->spawnId, map, true, force))
+ delete creature;
+ else if (spawnedObjects)
+ spawnedObjects->push_back(creature);
+ break;
+ }
+ case SPAWN_TYPE_GAMEOBJECT:
+ {
+ GameObject* gameobject = new GameObject();
+ if (!gameobject->LoadFromDB(data->spawnId, map, true))
+ delete gameobject;
+ else if (spawnedObjects)
+ spawnedObjects->push_back(gameobject);
+ break;
+ }
+ default:
+ ASSERT(false, "Invalid spawn type %u with spawnId %u", uint32(data->type), data->spawnId);
+ return false;
+ }
+ }
+ itr->second.isActive = true; // start processing respawns for the group
+ return true;
+}
+
+bool ObjectMgr::SpawnGroupDespawn(uint32 groupId, Map* map, bool deleteRespawnTimes)
+{
+ auto itr = _spawnGroupDataStore.find(groupId);
+ if (itr == _spawnGroupDataStore.end() || itr->second.flags & SPAWNGROUP_FLAG_SYSTEM)
+ {
+ TC_LOG_ERROR("maps", "Tried to despawn non-existing (or system) spawn group %u. Blocked.", groupId);
+ return false;
+ }
+
+ if (!map)
+ {
+ TC_LOG_ERROR("maps", "Tried to despawn creature group %u, but no map was supplied. Blocked.", groupId);
+ return false;
+ }
+
+ if (itr->second.mapId != map->GetId())
+ {
+ TC_LOG_ERROR("maps", "Tried to despawn creature group %u, but supplied map is %u, creature group has map %u. Blocked.", groupId, map->GetId(), itr->second.mapId);
+ return false;
+ }
+
+ std::vector<WorldObject*> toUnload; // unload after iterating, otherwise iterator invalidation
+ for (auto const& pair : GetSpawnDataForGroup(groupId))
+ {
+ SpawnData const* data = pair.second;
+ if (deleteRespawnTimes)
+ map->RemoveRespawnTime(data->type, data->spawnId);
+ switch (data->type)
+ {
+ case SPAWN_TYPE_CREATURE:
+ {
+ auto bounds = map->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 = map->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;
+ }
+ }
+ // now do the actual despawning
+ for (WorldObject* obj : toUnload)
+ obj->AddObjectToRemoveList();
+ itr->second.isActive = false; // stop processing respawns for the group, too
+ return true;
+}
+
void ObjectMgr::LoadGameObjectLocales()
{
uint32 oldMSTime = getMSTime();
@@ -7497,17 +7756,23 @@ void ObjectMgr::DeleteCreatureData(ObjectGuid::LowType guid)
// remove mapid*cellid -> guid_set map
CreatureData const* data = GetCreatureData(guid);
if (data)
+ {
RemoveCreatureFromGrid(guid, data);
+ OnDeleteSpawnData(data);
+ }
_creatureDataStore.erase(guid);
}
-void ObjectMgr::DeleteGOData(ObjectGuid::LowType guid)
+void ObjectMgr::DeleteGameObjectData(ObjectGuid::LowType guid)
{
// remove mapid*cellid -> guid_set map
- GameObjectData const* data = GetGOData(guid);
+ GameObjectData const* data = GetGameObjectData(guid);
if (data)
+ {
RemoveGameobjectFromGrid(guid, data);
+ OnDeleteSpawnData(data);
+ }
_gameObjectDataStore.erase(guid);
}