refactor(Core/DB): normalize creature table by extracting multi-ID spawns (#25197)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Ludwig <sudlud@users.noreply.github.com>
This commit is contained in:
Andrew
2026-06-16 01:17:38 -03:00
committed by GitHub
parent eb3cdd1d1f
commit cf0d86a9ff
22 changed files with 281 additions and 200 deletions
@@ -330,7 +330,7 @@ void SmartAIMgr::CheckIfSmartAIInDatabaseExists()
// check GUID SAI
for (auto const& pair : sObjectMgr->GetAllCreatureData())
{
if (pair.second.id1 != creatureTemplate.Entry)
if (pair.second.id != creatureTemplate.Entry)
continue;
if (mEventMap[uint32(SmartScriptType::SMART_SCRIPT_TYPE_CREATURE)].find((-1) * pair.first) != mEventMap[uint32(SmartScriptType::SMART_SCRIPT_TYPE_CREATURE)].end())
@@ -2100,7 +2100,7 @@ bool SmartAIMgr::IsTextValid(SmartScriptHolder const& e, uint32 id)
return false;
}
else
entry = data->id1;
entry = data->id;
}
else
entry = uint32(e.entryOrGuid);
+2 -2
View File
@@ -1958,7 +1958,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
return false;
}
if (data->id1 != uint32(cond->SourceEntry))
if (data->id != uint32(cond->SourceEntry))
{
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY has creature guid {} that does not match SourceEntry {}, skipped.", cond->SourceId, cond->SourceEntry);
return false;
@@ -2322,7 +2322,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
{
if (CreatureData const* creatureData = sObjectMgr->GetCreatureData(cond->ConditionValue3))
{
if (cond->ConditionValue2 && creatureData->id1 != cond->ConditionValue2)
if (cond->ConditionValue2 && creatureData->id != cond->ConditionValue2)
{
LOG_ERROR("sql.sql", "ObjectEntryGuid condition has guid {} set but does not match creature entry ({}), skipped", cond->ConditionValue3, cond->ConditionValue2);
return false;
@@ -1423,7 +1423,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
dynamicflags = 0;
}
data.id1 = GetEntry();
data.id = GetEntry();
data.mapid = mapid;
data.phaseMask = phaseMask;
data.displayid = displayId;
@@ -1469,8 +1469,6 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE);
stmt->SetData(index++, m_spawnId);
stmt->SetData(index++, GetEntry());
stmt->SetData(index++, 0);
stmt->SetData(index++, 0);
stmt->SetData(index++, uint16(mapid));
stmt->SetData(index++, spawnMask);
stmt->SetData(index++, GetPhaseMask());
@@ -1725,7 +1723,7 @@ bool Creature::LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool ad
|| !groupData || (groupData->flags & SPAWNGROUP_FLAG_COMPATIBILITY_MODE);
// Add to world
uint32 entry = GetRandomId(data->id1, data->id2, data->id3);
uint32 entry = GetRandomId(data->id, data->id2, data->id3);
if (!Create(map->GenerateLowGuid<HighGuid::Unit>(), map, data->phaseMask, entry, 0, data->posX, data->posY, data->posZ, data->orientation, data))
return false;
@@ -2041,7 +2039,7 @@ void Creature::Respawn(bool force)
if (!allowed && !force) // Will be rechecked on next Update call
return;
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(m_creatureData ? m_creatureData->id1 : GetEntry(), m_spawnId);
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(m_creatureData ? m_creatureData->id : GetEntry(), m_spawnId);
time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(GetEntry());
@@ -2061,7 +2059,7 @@ void Creature::Respawn(bool force)
// Respawn check if spawn has 2 entries
if (data->id2)
{
uint32 entry = GetRandomId(data->id1, data->id2, data->id3);
uint32 entry = GetRandomId(data->id, data->id2, data->id3);
UpdateEntry(entry, data, true); // Select Random Entry
m_defaultMovementType = MovementGeneratorType(data->movementType); // Reload Movement Type
LoadEquipment(data->equipmentId); // Reload Equipment
@@ -3169,7 +3167,7 @@ uint32 Creature::GetScriptId() const
if (CreatureData const* creatureData = GetCreatureData())
{
uint32 scriptId = creatureData->ScriptId;
if (scriptId && GetEntry() == creatureData->id1)
if (scriptId && GetEntry() == creatureData->id)
return scriptId;
}
@@ -369,9 +369,9 @@ typedef std::unordered_map<uint32, EquipmentInfoContainerInternal> EquipmentInfo
struct CreatureData : public SpawnData
{
CreatureData() : SpawnData(SPAWN_TYPE_CREATURE) {}
uint32 id1{0}; // entry in creature_template
uint32 id2{0}; // entry in creature_template
uint32 id3{0}; // entry in creature_template
uint32 id{0}; // entry in creature_template
uint32 id2{0}; // entry in creature_template (from creature_multispawn)
uint32 id3{0}; // entry in creature_template (from creature_multispawn)
uint32 displayid{0};
int8 equipmentId{0};
uint32 spawntimesecs{0};
+5 -7
View File
@@ -300,7 +300,7 @@ void GameEventMgr::LoadEventVendors()
// Get creature entry
newEntry.Entry = 0;
if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
newEntry.Entry = data->id1;
newEntry.Entry = data->id;
// Validate vendor item
if (!sObjectMgr->IsVendorItemValid(newEntry.Entry, newEntry.Item, newEntry.MaxCount, newEntry.Incrtime, newEntry.ExtendedCost, nullptr, nullptr, event_npc_flag))
@@ -614,9 +614,7 @@ void GameEventMgr::LoadEventModelEquipmentChangeData()
ObjectGuid::LowType guid = fields[0].Get<uint32>();
uint32 entry = fields[1].Get<uint32>();
uint32 entry2 = fields[2].Get<uint32>();
uint32 entry3 = fields[3].Get<uint32>();
uint16 eventId = fields[4].Get<uint8>();
uint16 eventId = fields[2].Get<uint8>();
if (eventId >= _gameEventModelEquip.size())
{
@@ -626,15 +624,15 @@ void GameEventMgr::LoadEventModelEquipmentChangeData()
ModelEquipList& equiplist = _gameEventModelEquip[eventId];
ModelEquip newModelEquipSet;
newModelEquipSet.ModelId = fields[5].Get<uint32>();
newModelEquipSet.EquipmentId = fields[6].Get<uint8>();
newModelEquipSet.ModelId = fields[3].Get<uint32>();
newModelEquipSet.EquipmentId = fields[4].Get<uint8>();
newModelEquipSet.EquipementIdPrev = 0;
newModelEquipSet.ModelIdPrev = 0;
if (newModelEquipSet.EquipmentId > 0)
{
int8 equipId = static_cast<int8>(newModelEquipSet.EquipmentId);
if ((!sObjectMgr->GetEquipmentInfo(entry, equipId)) || (entry2 && !sObjectMgr->GetEquipmentInfo(entry2, equipId)) || (entry3 && !sObjectMgr->GetEquipmentInfo(entry3, equipId)))
if (!sObjectMgr->GetEquipmentInfo(entry, equipId))
{
LOG_ERROR("sql.sql", "Table `game_event_model_equip` have creature (Guid: {}) with equipment_id {} not found in table `creature_equip_template`, set to no equipment.",
guid, newModelEquipSet.EquipmentId);
+199 -137
View File
@@ -1572,7 +1572,7 @@ void ObjectMgr::LoadCreatureMovementOverrides()
"COALESCE(cmo.InteractionPauseTimer, ctm.InteractionPauseTimer) "
"FROM creature_movement_override AS cmo "
"LEFT JOIN creature AS c ON c.guid = cmo.SpawnId "
"LEFT JOIN creature_template_movement AS ctm ON ctm.CreatureId = c.id1");
"LEFT JOIN creature_template_movement AS ctm ON ctm.CreatureId = c.id");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 creature movement overrides. DB table `creature_movement_override` is empty!");
@@ -1978,8 +1978,8 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
guid = ObjectGuid::Create<HighGuid::Unit>(slave->id1, guidLow);
linkedGuid = ObjectGuid::Create<HighGuid::Unit>(master->id1, linkedGuidLow);
guid = ObjectGuid::Create<HighGuid::Unit>(slave->id, guidLow);
linkedGuid = ObjectGuid::Create<HighGuid::Unit>(master->id, linkedGuidLow);
break;
}
case CREATURE_TO_GO:
@@ -2015,7 +2015,7 @@ void ObjectMgr::LoadLinkedRespawn()
break;
}
guid = ObjectGuid::Create<HighGuid::Unit>(slave->id1, guidLow);
guid = ObjectGuid::Create<HighGuid::Unit>(slave->id, guidLow);
linkedGuid = ObjectGuid::Create<HighGuid::GameObject>(master->id, linkedGuidLow);
break;
}
@@ -2090,7 +2090,7 @@ void ObjectMgr::LoadLinkedRespawn()
}
guid = ObjectGuid::Create<HighGuid::GameObject>(slave->id, guidLow);
linkedGuid = ObjectGuid::Create<HighGuid::Unit>(master->id1, linkedGuidLow);
linkedGuid = ObjectGuid::Create<HighGuid::Unit>(master->id, linkedGuidLow);
break;
}
}
@@ -2109,7 +2109,7 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid
return false;
CreatureData const* master = GetCreatureData(guidLow);
ObjectGuid guid = ObjectGuid::Create<HighGuid::Unit>(master->id1, guidLow);
ObjectGuid guid = ObjectGuid::Create<HighGuid::Unit>(master->id, guidLow);
if (!linkedGuidLow) // we're removing the linking
{
@@ -2140,7 +2140,7 @@ bool ObjectMgr::SetCreatureLinkedRespawn(ObjectGuid::LowType guidLow, ObjectGuid
return false;
}
ObjectGuid linkedGuid = ObjectGuid::Create<HighGuid::Unit>(slave->id1, linkedGuidLow);
ObjectGuid linkedGuid = ObjectGuid::Create<HighGuid::Unit>(slave->id, linkedGuidLow);
_linkedRespawnStore[guid] = linkedGuid;
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_REP_CREATURE_LINKED_RESPAWN);
@@ -2321,11 +2321,11 @@ void ObjectMgr::LoadCreatures()
{
uint32 oldMSTime = getMSTime();
// 0 1 2 3 4 5 6 7 8 9 10 11
QueryResult result = WorldDatabase.Query("SELECT creature.guid, id1, id2, id3, map, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, "
// 12 13 14 15 16 17 18 19 20 21 22
// 0 1 2 3 4 5 6 7 8 9
QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, "
// 10 11 12 13 14 15 16 17 18 19 20
"currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags, "
// 23
// 21
"creature.ScriptName "
"FROM creature "
"LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid "
@@ -2356,58 +2356,37 @@ void ObjectMgr::LoadCreatures()
Field* fields = result->Fetch();
ObjectGuid::LowType spawnId = fields[0].Get<uint32>();
uint32 id1 = fields[1].Get<uint32>();
uint32 id2 = fields[2].Get<uint32>();
uint32 id3 = fields[3].Get<uint32>();
uint32 creatureId = fields[1].Get<uint32>();
CreatureTemplate const* cInfo = GetCreatureTemplate(id1);
CreatureTemplate const* cInfo = GetCreatureTemplate(creatureId);
if (!cInfo)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non existing creature entry {} in id1 field, skipped.", spawnId, id1);
continue;
}
CreatureTemplate const* cInfo2 = GetCreatureTemplate(id2);
if (!cInfo2 && id2)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non existing creature entry {} in id2 field, skipped.", spawnId, id2);
continue;
}
CreatureTemplate const* cInfo3 = GetCreatureTemplate(id3);
if (!cInfo3 && id3)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non existing creature entry {} in id3 field, skipped.", spawnId, id3);
continue;
}
if (!id2 && id3)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with creature entry {} in id3 field but no entry in id2 field, skipped.", spawnId, id3);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non existing creature entry {} in `id` field, skipped.", spawnId, creatureId);
continue;
}
CreatureData& data = _creatureDataStore[spawnId];
data.spawnId = spawnId;
data.id1 = id1;
data.id2 = id2;
data.id3 = id3;
data.mapid = fields[4].Get<uint16>();
data.equipmentId = fields[5].Get<int8>();
data.posX = fields[6].Get<float>();
data.posY = fields[7].Get<float>();
data.posZ = fields[8].Get<float>();
data.orientation = fields[9].Get<float>();
data.spawntimesecs = fields[10].Get<uint32>();
data.wander_distance = fields[11].Get<float>();
data.currentwaypoint = fields[12].Get<uint32>();
data.curhealth = fields[13].Get<uint32>();
data.curmana = fields[14].Get<uint32>();
data.movementType = fields[15].Get<uint8>();
data.spawnMask = fields[16].Get<uint8>();
data.phaseMask = fields[17].Get<uint32>();
int16 gameEvent = fields[18].Get<int16>();
uint32 PoolId = fields[19].Get<uint32>();
data.npcflag = fields[20].Get<uint32>();
data.unit_flags = fields[21].Get<uint32>();
data.dynamicflags = fields[22].Get<uint32>();
data.ScriptId = GetScriptId(fields[23].Get<std::string>());
data.id = creatureId;
data.mapid = fields[2].Get<uint16>();
data.equipmentId = fields[3].Get<int8>();
data.posX = fields[4].Get<float>();
data.posY = fields[5].Get<float>();
data.posZ = fields[6].Get<float>();
data.orientation = fields[7].Get<float>();
data.spawntimesecs = fields[8].Get<uint32>();
data.wander_distance = fields[9].Get<float>();
data.currentwaypoint = fields[10].Get<uint32>();
data.curhealth = fields[11].Get<uint32>();
data.curmana = fields[12].Get<uint32>();
data.movementType = fields[13].Get<uint8>();
data.spawnMask = fields[14].Get<uint8>();
data.phaseMask = fields[15].Get<uint32>();
int16 gameEvent = fields[16].Get<int16>();
uint32 PoolId = fields[17].Get<uint32>();
data.npcflag = fields[18].Get<uint32>();
data.unit_flags = fields[19].Get<uint32>();
data.dynamicflags = fields[20].Get<uint32>();
data.ScriptId = GetScriptId(fields[21].Get<std::string>());
data.spawnGroupId = 0;
if (!data.ScriptId)
@@ -2437,10 +2416,10 @@ void ObjectMgr::LoadCreatures()
bool ok = true;
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff)
{
if ((_difficultyEntries[diff].find(data.id1) != _difficultyEntries[diff].end()) || (_difficultyEntries[diff].find(data.id2) != _difficultyEntries[diff].end()) || (_difficultyEntries[diff].find(data.id3) != _difficultyEntries[diff].end()))
if (_difficultyEntries[diff].find(data.id) != _difficultyEntries[diff].end())
{
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {}) that listed as difficulty {} template (Entries: {}, {}, {}) in `creature_template`, skipped.",
spawnId, diff + 1, data.id1, data.id2, data.id3);
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {}) that listed as difficulty {} template (Entry: {}) in `creature_template`, skipped.",
spawnId, diff + 1, data.id);
ok = false;
}
}
@@ -2450,35 +2429,35 @@ void ObjectMgr::LoadCreatures()
// -1 random, 0 no equipment,
if (data.equipmentId != 0)
{
if ((!GetEquipmentInfo(data.id1, data.equipmentId)) || (data.id2 && !GetEquipmentInfo(data.id2, data.equipmentId)) || (data.id3 && !GetEquipmentInfo(data.id3, data.equipmentId)))
if (!GetEquipmentInfo(data.id, data.equipmentId))
{
LOG_ERROR("sql.sql", "Table `creature` have creature (Entries: {}, {}, {}) one or more with equipment_id {} not found in table `creature_equip_template`, set to no equipment.",
data.id1, data.id2, data.id3, data.equipmentId);
LOG_ERROR("sql.sql", "Table `creature` have creature (Entry: {}) with equipment_id {} not found in table `creature_equip_template`, set to no equipment.",
data.id, data.equipmentId);
data.equipmentId = 0;
}
}
if (cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_INSTANCE_BIND) || (data.id2 && cInfo2->HasFlagsExtra(CREATURE_FLAG_EXTRA_INSTANCE_BIND)) || (data.id3 && cInfo3->HasFlagsExtra(CREATURE_FLAG_EXTRA_INSTANCE_BIND)))
if (cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_INSTANCE_BIND))
{
if (!mapEntry->IsDungeon())
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entries: {}, {}, {}) with a `creature_template`.`flags_extra` in one or more entries including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",
spawnId, data.id1, data.id2, data.id3);
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entry: {}) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",
spawnId, data.id);
}
if (data.movementType >= MAX_DB_MOTION_TYPE)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entries: {}, {}, {}) with wrong movement generator type ({}), ignored and set to IDLE.", spawnId, data.id1, data.id2, data.id3, data.movementType);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entry: {}) with wrong movement generator type ({}), ignored and set to IDLE.", spawnId, data.id, data.movementType);
data.movementType = IDLE_MOTION_TYPE;
}
if (data.wander_distance < 0.0f)
{
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entries: {}, {}, {}) with `wander_distance`< 0, set to 0.", spawnId, data.id1, data.id2, data.id3);
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entry: {}) with `wander_distance`< 0, set to 0.", spawnId, data.id);
data.wander_distance = 0.0f;
}
else if (data.movementType == RANDOM_MOTION_TYPE)
{
if (data.wander_distance == 0.0f)
{
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entries: {}, {}, {}) with `MovementType`=1 (random movement) but with `wander_distance`=0, replace by idle movement type (0).",
spawnId, data.id1, data.id2, data.id3);
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entry: {}) with `MovementType`=1 (random movement) but with `wander_distance`=0, replace by idle movement type (0).",
spawnId, data.id);
data.movementType = IDLE_MOTION_TYPE;
}
}
@@ -2486,14 +2465,14 @@ void ObjectMgr::LoadCreatures()
{
if (data.wander_distance != 0.0f)
{
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entries: {}, {}, {}) with `MovementType`=0 (idle) have `wander_distance`<>0, set to 0.", spawnId, data.id1, data.id2, data.id3);
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entry: {}) with `MovementType`=0 (idle) have `wander_distance`<>0, set to 0.", spawnId, data.id);
data.wander_distance = 0.0f;
}
}
if (data.phaseMask == 0)
{
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entries: {}, {}, {}) with `phaseMask`=0 (not visible for anyone), set to 1.", spawnId, data.id1, data.id2, data.id3);
LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entry: {}) with `phaseMask`=0 (not visible for anyone), set to 1.", spawnId, data.id);
data.phaseMask = 1;
}
@@ -2518,6 +2497,72 @@ void ObjectMgr::LoadCreatures()
++count;
} while (result->NextRow());
// Load alternate entries from creature_multispawn
QueryResult variantResult = WorldDatabase.Query("SELECT spawnId, entry FROM creature_multispawn ORDER BY spawnId");
if (variantResult)
{
uint32 variantCount = 0;
do
{
Field* fields = variantResult->Fetch();
ObjectGuid::LowType spawnId = fields[0].Get<uint32>();
uint32 entry = fields[1].Get<uint32>();
auto creatureDataIt = _creatureDataStore.find(spawnId);
if (creatureDataIt == _creatureDataStore.end())
{
LOG_ERROR("sql.sql", "Table `creature_multispawn` has entry for non-existing creature spawn (SpawnId: {}), skipped.", spawnId);
continue;
}
CreatureData* data = &creatureDataIt->second;
CreatureTemplate const* variantInfo = GetCreatureTemplate(entry);
if (!variantInfo)
{
LOG_ERROR("sql.sql", "Table `creature_multispawn` has creature (SpawnId: {}) with non-existing creature entry {}, skipped.", spawnId, entry);
continue;
}
// Check difficulty entries for variant
bool diffOk = true;
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && diffOk; ++diff)
{
if (_difficultyEntries[diff].find(entry) != _difficultyEntries[diff].end())
{
LOG_ERROR("sql.sql", "Table `creature_multispawn` has creature (SpawnId: {}) with entry {} listed as difficulty template in `creature_template`, skipped.",
spawnId, entry);
diffOk = false;
}
}
if (!diffOk)
continue;
// Validate equipment for variant entry
if (data->equipmentId != 0 && !GetEquipmentInfo(entry, data->equipmentId))
{
LOG_ERROR("sql.sql", "Table `creature_multispawn` has creature (SpawnId: {}) with entry {} where equipment_id {} not found in `creature_equip_template`.",
spawnId, entry, data->equipmentId);
}
// Populate id2/id3 fields
if (!data->id2)
{
data->id2 = entry;
++variantCount;
}
else if (!data->id3)
{
data->id3 = entry;
++variantCount;
}
else
LOG_ERROR("sql.sql", "Table `creature_multispawn` has more than 2 variant entries for creature (SpawnId: {}), extra entry {} skipped.", spawnId, entry);
} while (variantResult->NextRow());
LOG_INFO("server.loading", ">> Loaded {} creature spawn variants", variantCount);
}
LOG_INFO("server.loading", ">> Loaded {} Creatures in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@@ -2531,7 +2576,7 @@ CreatureData const* ObjectMgr::LoadCreatureDataFromDB(ObjectGuid::LowType spawnI
if (data)
return data;
QueryResult result = WorldDatabase.Query("SELECT creature.guid, id1, id2, id3, map, equipment_id, "
QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, equipment_id, "
"position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, "
"currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, "
"creature.npcflag, creature.unit_flags, creature.dynamicflags, creature.ScriptName "
@@ -2541,62 +2586,83 @@ CreatureData const* ObjectMgr::LoadCreatureDataFromDB(ObjectGuid::LowType spawnI
return nullptr;
Field* fields = result->Fetch();
uint32 id1 = fields[1].Get<uint32>();
uint32 id2 = fields[2].Get<uint32>();
uint32 id3 = fields[3].Get<uint32>();
uint32 creatureId = fields[1].Get<uint32>();
CreatureTemplate const* cInfo = GetCreatureTemplate(id1);
CreatureTemplate const* cInfo = GetCreatureTemplate(creatureId);
if (!cInfo)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non-existing creature entry {} in id1 field, skipped.", spawnId, id1);
return nullptr;
}
if (id2 && !GetCreatureTemplate(id2))
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non-existing creature entry {} in id2 field, skipped.", spawnId, id2);
return nullptr;
}
if (id3 && !GetCreatureTemplate(id3))
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non-existing creature entry {} in id3 field, skipped.", spawnId, id3);
return nullptr;
}
if (!id2 && id3)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with creature entry {} in id3 field but no entry in id2 field, skipped.", spawnId, id3);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) with non-existing creature entry {} in `id` field, skipped.", spawnId, creatureId);
return nullptr;
}
CreatureData& creatureData = _creatureDataStore[spawnId];
creatureData.id1 = id1;
creatureData.id2 = id2;
creatureData.id3 = id3;
creatureData.mapid = fields[4].Get<uint16>();
creatureData.equipmentId = fields[5].Get<int8>();
creatureData.posX = fields[6].Get<float>();
creatureData.posY = fields[7].Get<float>();
creatureData.posZ = fields[8].Get<float>();
creatureData.orientation = fields[9].Get<float>();
creatureData.spawntimesecs = fields[10].Get<uint32>();
creatureData.wander_distance = fields[11].Get<float>();
creatureData.currentwaypoint = fields[12].Get<uint32>();
creatureData.curhealth = fields[13].Get<uint32>();
creatureData.curmana = fields[14].Get<uint32>();
creatureData.movementType = fields[15].Get<uint8>();
creatureData.spawnMask = fields[16].Get<uint8>();
creatureData.phaseMask = fields[17].Get<uint32>();
creatureData.npcflag = fields[18].Get<uint32>();
creatureData.unit_flags = fields[19].Get<uint32>();
creatureData.dynamicflags = fields[20].Get<uint32>();
creatureData.ScriptId = GetScriptId(fields[21].Get<std::string>());
creatureData.id = creatureId;
creatureData.mapid = fields[2].Get<uint16>();
creatureData.equipmentId = fields[3].Get<int8>();
creatureData.posX = fields[4].Get<float>();
creatureData.posY = fields[5].Get<float>();
creatureData.posZ = fields[6].Get<float>();
creatureData.orientation = fields[7].Get<float>();
creatureData.spawntimesecs = fields[8].Get<uint32>();
creatureData.wander_distance = fields[9].Get<float>();
creatureData.currentwaypoint = fields[10].Get<uint32>();
creatureData.curhealth = fields[11].Get<uint32>();
creatureData.curmana = fields[12].Get<uint32>();
creatureData.movementType = fields[13].Get<uint8>();
creatureData.spawnMask = fields[14].Get<uint8>();
creatureData.phaseMask = fields[15].Get<uint32>();
creatureData.npcflag = fields[16].Get<uint32>();
creatureData.unit_flags = fields[17].Get<uint32>();
creatureData.dynamicflags = fields[18].Get<uint32>();
creatureData.ScriptId = GetScriptId(fields[19].Get<std::string>());
creatureData.spawnGroupId = 0;
if (!creatureData.ScriptId)
creatureData.ScriptId = cInfo->ScriptID;
// Load alternate entries from creature_multispawn
QueryResult variantResult = WorldDatabase.Query("SELECT entry FROM creature_multispawn WHERE spawnId = {} ORDER BY entry", spawnId);
if (variantResult)
{
do
{
uint32 variantEntry = variantResult->Fetch()[0].Get<uint32>();
if (!GetCreatureTemplate(variantEntry))
{
LOG_ERROR("sql.sql", "Table `creature_multispawn` has creature (SpawnId: {}) with non-existing entry {}, skipped.", spawnId, variantEntry);
continue;
}
// Check difficulty entries for variant
bool diffOk = true;
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && diffOk; ++diff)
{
if (_difficultyEntries[diff].find(variantEntry) != _difficultyEntries[diff].end())
{
LOG_ERROR("sql.sql", "Table `creature_multispawn` has creature (SpawnId: {}) with entry {} listed as difficulty template in `creature_template`, skipped.",
spawnId, variantEntry);
diffOk = false;
}
}
if (!diffOk)
continue;
// Validate equipment for variant entry
if (creatureData.equipmentId != 0 && !GetEquipmentInfo(variantEntry, creatureData.equipmentId))
{
LOG_ERROR("sql.sql", "Table `creature_multispawn` has creature (SpawnId: {}) with entry {} where equipment_id {} not found in `creature_equip_template`.",
spawnId, variantEntry, creatureData.equipmentId);
}
if (!creatureData.id2)
creatureData.id2 = variantEntry;
else if (!creatureData.id3)
creatureData.id3 = variantEntry;
else
LOG_ERROR("sql.sql", "Table `creature_multispawn` has more than 2 variant entries for creature (SpawnId: {}), extra entry {} skipped.", spawnId, variantEntry);
} while (variantResult->NextRow());
}
MapEntry const* mapEntry = sMapStore.LookupEntry(creatureData.mapid);
if (!mapEntry)
{
@@ -2611,12 +2677,10 @@ CreatureData const* ObjectMgr::LoadCreatureDataFromDB(ObjectGuid::LowType spawnI
bool ok = true;
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff)
{
if (_difficultyEntries[diff].find(id1) != _difficultyEntries[diff].end() ||
_difficultyEntries[diff].find(id2) != _difficultyEntries[diff].end() ||
_difficultyEntries[diff].find(id3) != _difficultyEntries[diff].end())
if (_difficultyEntries[diff].find(creatureId) != _difficultyEntries[diff].end())
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) that is listed as difficulty {} template (Entries: {}, {}, {}) in `creature_template`, skipped.",
spawnId, diff + 1, id1, id2, id3);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {}) that is listed as difficulty {} template (Entry: {}) in `creature_template`, skipped.",
spawnId, diff + 1, creatureId);
ok = false;
}
}
@@ -2629,35 +2693,33 @@ CreatureData const* ObjectMgr::LoadCreatureDataFromDB(ObjectGuid::LowType spawnI
if (creatureData.equipmentId != 0)
{
if (!GetEquipmentInfo(id1, creatureData.equipmentId) ||
(id2 && !GetEquipmentInfo(id2, creatureData.equipmentId)) ||
(id3 && !GetEquipmentInfo(id3, creatureData.equipmentId)))
if (!GetEquipmentInfo(creatureId, creatureData.equipmentId))
{
LOG_ERROR("sql.sql", "Table `creature` has creature (Entries: {}, {}, {}) with equipment_id {} not found in table `creature_equip_template`, set to no equipment.",
id1, id2, id3, creatureData.equipmentId);
LOG_ERROR("sql.sql", "Table `creature` has creature (Entry: {}) with equipment_id {} not found in table `creature_equip_template`, set to no equipment.",
creatureId, creatureData.equipmentId);
creatureData.equipmentId = 0;
}
}
if (creatureData.movementType >= MAX_DB_MOTION_TYPE)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entries: {}, {}, {}) with wrong movement generator type ({}), set to IDLE.",
spawnId, id1, id2, id3, creatureData.movementType);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entry: {}) with wrong movement generator type ({}), set to IDLE.",
spawnId, creatureId, creatureData.movementType);
creatureData.movementType = IDLE_MOTION_TYPE;
}
if (creatureData.wander_distance < 0.0f)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entries: {}, {}, {}) with `wander_distance`< 0, set to 0.",
spawnId, id1, id2, id3);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entry: {}) with `wander_distance`< 0, set to 0.",
spawnId, creatureId);
creatureData.wander_distance = 0.0f;
}
else if (creatureData.movementType == RANDOM_MOTION_TYPE)
{
if (creatureData.wander_distance == 0.0f)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entries: {}, {}, {}) with `MovementType`=1 (random movement) but with `wander_distance`=0, replace by idle movement type (0).",
spawnId, id1, id2, id3);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entry: {}) with `MovementType`=1 (random movement) but with `wander_distance`=0, replace by idle movement type (0).",
spawnId, creatureId);
creatureData.movementType = IDLE_MOTION_TYPE;
}
}
@@ -2665,16 +2727,16 @@ CreatureData const* ObjectMgr::LoadCreatureDataFromDB(ObjectGuid::LowType spawnI
{
if (creatureData.wander_distance != 0.0f)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entries: {}, {}, {}) with `MovementType`=0 (idle) have `wander_distance`<>0, set to 0.",
spawnId, id1, id2, id3);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entry: {}) with `MovementType`=0 (idle) have `wander_distance`<>0, set to 0.",
spawnId, creatureId);
creatureData.wander_distance = 0.0f;
}
}
if (creatureData.phaseMask == 0)
{
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entries: {}, {}, {}) with `phaseMask`=0 (not visible for anyone), set to 1.",
spawnId, id1, id2, id3);
LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entry: {}) with `phaseMask`=0 (not visible for anyone), set to 1.",
spawnId, creatureId);
creatureData.phaseMask = 1;
}
@@ -2814,7 +2876,7 @@ ObjectGuid::LowType ObjectMgr::AddCreData(uint32 entry, uint32 mapId, float x, f
CreatureData& data = NewOrExistCreatureData(spawnId);
data.spawnId = spawnId;
data.spawnMask = spawnId;
data.id1 = entry;
data.id = entry;
data.id2 = 0;
data.id3 = 0;
data.mapid = mapId;
@@ -279,7 +279,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
return;
}
CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id1);
CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id);
if (!auctioneerInfo)
{
LOG_ERROR("network.opcode", "Non existing auctioneer ({})", auctioneer.ToString());
+1 -1
View File
@@ -28,7 +28,7 @@ public:
ZoneScript() {}
virtual ~ZoneScript() {}
virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidlow*/, CreatureData const* data) { return data->id1; }
virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidlow*/, CreatureData const* data) { return data->id; }
virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidlow*/, uint32 entry) { return entry; }
virtual void OnCreatureCreate(Creature*) { }
+1 -1
View File
@@ -96,7 +96,7 @@ void OPvPCapturePoint::AddCre(uint32 type, ObjectGuid::LowType guid, uint32 entr
return;
}
entry = data->id1;
entry = data->id;
}
_creatures[type] = guid;