diff options
Diffstat (limited to 'src/server/game/Globals/ObjectMgr.cpp')
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 453 |
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); } |