diff options
Diffstat (limited to 'src/server/game/Scripting/ScriptMgr.cpp')
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 215 |
1 files changed, 154 insertions, 61 deletions
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index f77b93c0d5e..b5e587eb149 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -23,6 +23,7 @@ #include "Creature.h" #include "CreatureAI.h" #include "CreatureAIImpl.h" +#include "CreatureAISelector.h" #include "DB2Stores.h" #include "Errors.h" #include "GameObject.h" @@ -153,6 +154,9 @@ public: /// Unloads the script registry. virtual void Unload() = 0; + + /// Updates the scripts to reflect the current id + virtual void SyncScriptNames() = 0; }; template<class> @@ -241,6 +245,12 @@ public: registry->Unload(); } + void SyncScriptNames() final override + { + for (auto const registry : _registries) + registry->SyncScriptNames(); + } + template<typename T> void QueueForDelayedDelete(T&& any) { @@ -330,6 +340,9 @@ public: /// Called before Unload virtual void BeforeUnload() { } + + /// Called manually to sync scriptnames + virtual void OnScriptNamesSync() { }; }; template<typename ScriptType, typename Base> @@ -518,38 +531,84 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks return map->GetAreaTrigger(guid); } - template<typename T> - static void VisitObjectsToSwapOnMap(Map* map, std::unordered_set<uint32> const& idsToRemove, T visitor) + static auto VisitObjectsToSwapOnMap(std::unordered_set<uint32> const& idsToRemove) { - auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects) + return [&idsToRemove](Map* map, auto&& visitor) { - for (auto object : objects) + auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects) { - // When the script Id of the script isn't removed in this - // context change, do nothing. - if (idsToRemove.find(object.second->GetScriptId()) != idsToRemove.end()) - visitor(object.second); - } + for (auto object : objects) + { + // When the script Id of the script isn't removed in this + // context change, do nothing. + uint32 aiId = object.second->AI() ? object.second->AI()->GetId() : 0; + if (idsToRemove.find(aiId) != idsToRemove.end()) + visitor(object.second); + } + }; + + AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator)); + TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> containerVisitor(worker); + + containerVisitor.Visit(map->GetObjectsStore()); }; + } - AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator)); - TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> containerVisitor(worker); + static auto VisitObjectsWhereIdWasUpdated() + { + return [](Map* map, auto&& visitor) + { + auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects) + { + for (auto object : objects) + { + if (object.second->AI()) + { + ASSERT(object.second->AI()->GetId()); + + uint32 aiId = object.second->AI()->GetId(); + uint32 scriptId = FactorySelector::GetSelectedAIId(object.second); + + ASSERT(scriptId); + + if (aiId == scriptId) + { + // Skip if the ai id matches + continue; + } + + if (!sObjectMgr->IsScriptDatabaseBound(scriptId) + && !sObjectMgr->IsScriptDatabaseBound(aiId)) + { + // Skip if we are dealing with two selectable AI scripts + continue; + } + + visitor(object.second); + } + else + visitor(object.second); + } + }; - containerVisitor.Visit(map->GetObjectsStore()); + AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator)); + TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> containerVisitor(worker); + + containerVisitor.Visit(map->GetObjectsStore()); + }; } - static void DestroyScriptIdsFromSet(std::unordered_set<uint32> const& idsToRemove) + template<typename T> + static void DestroyScriptIdsWithVisitor(T&& visitor) { // First reset all swapped scripts safe by guid - // Skip creatures and gameobjects with an empty guid - // (that were not added to the world as of now) sMapMgr->DoForAllMaps([&](Map* map) { std::vector<ObjectGuid> guidsToReset; - VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object) + visitor(map, [&](ObjectType* object) { - if (object->AI() && !object->GetGUID().IsEmpty()) + if (object->AI()) guidsToReset.push_back(object->GetGUID()); }); @@ -559,7 +618,7 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks UnloadResetScript(entity); } - VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object) + visitor(map, [&](ObjectType* object) { // Destroy the scripts instantly UnloadDestroyScript(object); @@ -567,15 +626,16 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks }); } - static void InitializeScriptIdsFromSet(std::unordered_set<uint32> const& idsToRemove) + template<typename T> + static void InitializeScriptIdsWithVisitor(T&& visitor) { sMapMgr->DoForAllMaps([&](Map* map) { std::vector<ObjectGuid> guidsToReset; - VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object) + visitor(map, [&](ObjectType* object) { - if (!object->AI() && !object->GetGUID().IsEmpty()) + if (!object->AI()) { // Initialize the script LoadInitializeScript(object); @@ -601,7 +661,7 @@ public: void BeforeReleaseContext(std::string const& context) final override { auto idsToRemove = static_cast<Base*>(this)->GetScriptIDsToRemove(context); - DestroyScriptIdsFromSet(idsToRemove); + DestroyScriptIdsWithVisitor(VisitObjectsToSwapOnMap(idsToRemove)); // Add the new ids which are removed to the global ids to remove set ids_removed_.insert(idsToRemove.begin(), idsToRemove.end()); @@ -618,8 +678,9 @@ public: ids_removed_.insert(static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().begin(), static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().end()); - DestroyScriptIdsFromSet(ids_removed_); - InitializeScriptIdsFromSet(ids_removed_); + auto const visitor = VisitObjectsToSwapOnMap(ids_removed_); + DestroyScriptIdsWithVisitor(visitor); + InitializeScriptIdsWithVisitor(visitor); ids_removed_.clear(); } @@ -629,6 +690,13 @@ public: ASSERT(ids_removed_.empty()); } + void OnScriptNamesSync() final override + { + auto const visitor = VisitObjectsWhereIdWasUpdated(); + DestroyScriptIdsWithVisitor(visitor); + InitializeScriptIdsWithVisitor(visitor); + } + private: std::unordered_set<uint32> ids_removed_; }; @@ -876,6 +944,11 @@ public: _ids_of_contexts.clear(); } + void SyncScriptNames() final override + { + this->OnScriptNamesSync(); + } + // Adds a database bound script void AddScript(ScriptType* script) { @@ -886,46 +959,33 @@ public: std::unique_ptr<ScriptType> script_ptr(script); - // Get an ID for the script. An ID only exists if it's a script that is assigned in the database - // through a script name (or similar). - if (uint32 const id = sObjectMgr->GetScriptId(script->GetName())) + // Get an ID for the script. + uint32 const id = sObjectMgr->GetScriptId(script->GetName()); + + // Try to find an existing script. + for (auto const& stored_script : _scripts) { - // Try to find an existing script. - for (auto const& stored_script : _scripts) + // If the script names match... + if (stored_script.second->GetName() == script->GetName()) { - // If the script names match... - if (stored_script.second->GetName() == script->GetName()) - { - // If the script is already assigned -> delete it! - TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, " - "so the script can't work.", script->GetName().c_str()); - - // Error that should be fixed ASAP. - sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr)); - ABORT(); - return; - } - } - - // If the script isn't assigned -> assign it! - _scripts.insert(std::make_pair(id, std::move(script_ptr))); - _ids_of_contexts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), id)); - _recently_added_ids.insert(id); + // If the script is already assigned -> delete it! + TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, " + "so the script can't work.", script->GetName().c_str()); - sScriptRegistryCompositum->SetScriptNameInContext(script->GetName(), - sScriptMgr->GetCurrentScriptContext()); + // Error that should be fixed ASAP. + sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr)); + ABORT(); + return; + } } - else - { - // The script uses a script name from database, but isn't assigned to anything. - TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.", - script->GetName().c_str()); - // Avoid calling "delete script;" because we are currently in the script constructor - // In a valid scenario this will not happen because every script has a name assigned in the database - sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr)); - return; - } + // If the script isn't assigned -> assign it! + _scripts.insert(std::make_pair(id, std::move(script_ptr))); + _ids_of_contexts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), id)); + _recently_added_ids.insert(id); + + sScriptRegistryCompositum->SetScriptNameInContext(script->GetName(), + sScriptMgr->GetCurrentScriptContext()); } // Gets a script by its ID (assigned by ObjectMgr). @@ -1034,6 +1094,10 @@ public: _scripts.clear(); } + void SyncScriptNames() final override + { + } + // Adds a non database bound script void AddScript(ScriptType* script) { @@ -1117,7 +1181,7 @@ ScriptObject::~ScriptObject() } ScriptMgr::ScriptMgr() - : _scriptCount(0), _script_loader_callback(nullptr) + : _scriptCount(0), _scriptIdUpdated(false), _script_loader_callback(nullptr) { } @@ -1165,7 +1229,7 @@ void ScriptMgr::Initialize() sScriptMgr->SwapScriptContext(true); // Print unused script names. - std::unordered_set<std::string> unusedScriptNames = sObjectMgr->GetAllScriptNames(); + std::unordered_set<std::string> unusedScriptNames = sObjectMgr->GetAllDBScriptNames(); // Remove the used scripts from the given container. sScriptRegistryCompositum->RemoveUsedScriptsFromContainer(unusedScriptNames); @@ -1185,6 +1249,20 @@ void ScriptMgr::Initialize() GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); } +void ScriptMgr::NotifyScriptIDUpdate() +{ + _scriptIdUpdated = true; +} + +void ScriptMgr::SyncScripts() +{ + if (_scriptIdUpdated) + { + _scriptIdUpdated = false; + sScriptRegistryCompositum->SyncScriptNames(); + } +} + void ScriptMgr::SetScriptContext(std::string const& context) { _currentContext = context; @@ -1598,6 +1676,11 @@ bool ScriptMgr::OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo co return tmpscript->OnCastItemCombatSpell(player, victim, spellInfo, item); } +bool ScriptMgr::CanCreateCreatureAI(uint32 scriptId) const +{ + return !!ScriptRegistry<CreatureScript>::Instance()->GetScriptById(scriptId); +} + CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature) { ASSERT(creature); @@ -1606,6 +1689,11 @@ CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature) return tmpscript->GetAI(creature); } +bool ScriptMgr::CanCreateGameObjectAI(uint32 scriptId) const +{ + return !!ScriptRegistry<GameObjectScript>::Instance()->GetScriptById(scriptId); +} + GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject) { ASSERT(gameobject); @@ -1614,6 +1702,11 @@ GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject) return tmpscript->GetAI(gameobject); } +bool ScriptMgr::CanCreateAreaTriggerAI(uint32 scriptId) const +{ + return !!ScriptRegistry<AreaTriggerEntityScript>::Instance()->GetScriptById(scriptId); +} + AreaTriggerAI* ScriptMgr::GetAreaTriggerAI(AreaTrigger* areatrigger) { ASSERT(areatrigger); |