diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index ca07350a2..de26f39fa 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -591,7 +591,7 @@ void ObjectMgr::LoadCreatureTemplates() "ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, ExperienceModifier, " // 64 65 66 67 68 69 70 "RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName " - "FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId;"); + "FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId ORDER BY entry DESC;"); if (!result) { @@ -600,6 +600,7 @@ void ObjectMgr::LoadCreatureTemplates() } _creatureTemplateStore.rehash(result->GetRowCount()); + _creatureTemplateStoreFast.clear(); uint32 count = 0; do @@ -609,20 +610,7 @@ void ObjectMgr::LoadCreatureTemplates() ++count; } while (result->NextRow()); - // pussywizard: - { - uint32 max = 0; - for (CreatureTemplateContainer::const_iterator itr = _creatureTemplateStore.begin(); itr != _creatureTemplateStore.end(); ++itr) - if (itr->first > max) - max = itr->first; - if (max) - { - _creatureTemplateStoreFast.clear(); - _creatureTemplateStoreFast.resize(max + 1, nullptr); - for (CreatureTemplateContainer::iterator itr = _creatureTemplateStore.begin(); itr != _creatureTemplateStore.end(); ++itr) - _creatureTemplateStoreFast[itr->first] = &(itr->second); - } - } + sScriptMgr->OnAfterDatabaseLoadCreatureTemplates(_creatureTemplateStoreFast); LoadCreatureTemplateResistances(); LoadCreatureTemplateSpells(); @@ -638,12 +626,28 @@ void ObjectMgr::LoadCreatureTemplates() LOG_INFO("server.loading", " "); } -void ObjectMgr::LoadCreatureTemplate(Field* fields) +/** +* @brief Loads a creature template from a database result +* +* @param fields Database result +* @param triggerHook If true, will trigger the OnAfterDatabaseLoadCreatureTemplates hook. Useful if you are not calling the hook yourself. +*/ +void ObjectMgr::LoadCreatureTemplate(Field* fields, bool triggerHook) { uint32 entry = fields[0].Get(); CreatureTemplate& creatureTemplate = _creatureTemplateStore[entry]; + // enlarge the fast cache as necessary + if (_creatureTemplateStoreFast.size() < entry + 1) + { + _creatureTemplateStoreFast.resize(entry + 1, nullptr); + } + + // load a pointer to this creatureTemplate into the fast cache + _creatureTemplateStoreFast[entry] = &creatureTemplate; + + // build the creatureTemplate creatureTemplate.Entry = entry; for (uint8 i = 0; i < MAX_DIFFICULTY - 1; ++i) @@ -750,6 +754,13 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.SpellSchoolImmuneMask = fields[68].Get(); creatureTemplate.flags_extra = fields[69].Get(); creatureTemplate.ScriptID = GetScriptId(fields[70].Get()); + + // useful if the creature template load is being triggered from outside this class + if (triggerHook) + { + sScriptMgr->OnAfterDatabaseLoadCreatureTemplates(_creatureTemplateStoreFast); + } + } void ObjectMgr::LoadCreatureTemplateResistances() diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 999ad14f0..33ef56adf 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1020,7 +1020,7 @@ public: void LoadCreatureClassLevelStats(); void LoadCreatureLocales(); void LoadCreatureTemplates(); - void LoadCreatureTemplate(Field* fields); + void LoadCreatureTemplate(Field* fields, bool triggerHook = false); void LoadCreatureTemplateAddons(); void LoadCreatureTemplateResistances(); void LoadCreatureTemplateSpells(); diff --git a/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp b/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp index b4debdf2f..2bc860e0b 100644 --- a/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp @@ -25,3 +25,11 @@ void ScriptMgr::OnAfterDatabasesLoaded(uint32 updateFlags) script->OnAfterDatabasesLoaded(updateFlags); }); } + +void ScriptMgr::OnAfterDatabaseLoadCreatureTemplates(std::vector creatureTemplates) +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnAfterDatabaseLoadCreatureTemplates(creatureTemplates); + }); +} diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 221aaf364..113b3b877 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -2024,7 +2024,20 @@ public: [[nodiscard]] bool IsDatabaseBound() const override { return false; } + /** + * @brief Called after all databases are loaded + * + * @param updateFlags Update flags from the loader + */ virtual void OnAfterDatabasesLoaded(uint32 /*updateFlags*/) { } + + /** + * @brief Called after all creature template data has been loaded from the database. This hook could be called multiple times, not just at server startup. + * + * @param creatureTemplates Pointer to a modifiable vector of creature templates. Indexed by Entry ID. + */ + virtual void OnAfterDatabaseLoadCreatureTemplates(std::vector /*creatureTemplates*/) { } + }; class WorldObjectScript : public ScriptObject @@ -2671,6 +2684,7 @@ public: /* CommandSC */ public: /* DatabaseScript */ void OnAfterDatabasesLoaded(uint32 updateFlags); + void OnAfterDatabaseLoadCreatureTemplates(std::vector creatureTemplateStore); public: /* WorldObjectScript */ diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 639c9c91f..17f312327 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -476,7 +476,7 @@ public: Field* fields = result->Fetch(); - sObjectMgr->LoadCreatureTemplate(fields); + sObjectMgr->LoadCreatureTemplate(fields, true); sObjectMgr->CheckCreatureTemplate(cInfo); }