diff options
author | Yehonal <yehonal.azeroth@gmail.com> | 2016-08-07 12:28:17 +0200 |
---|---|---|
committer | Yehonal <yehonal.azeroth@gmail.com> | 2016-08-07 12:28:17 +0200 |
commit | 5b824569a9f80cc08c98dbae3e2c8be3b3b587fc (patch) | |
tree | 438f2cb15537a17e618a53e99fde50d6829686e5 | |
parent | e5f8ecd7ecd70a413d27dab6c375647a3f6b0a12 (diff) |
[CORE] Rewritten ScriptMgr to be initialized before server load
Now ScriptMgr can be initialized before config allowing
to create scripts that can change the behaviour of
server before loading anything
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 57 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.h | 181 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 13 |
4 files changed, 172 insertions, 80 deletions
diff --git a/.gitignore b/.gitignore index b35017fd6b..1b16f2839e 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ CMakeLists.txt.user # exclude in all levels nbproject/ .sync.ffs_db +*.kate-swp # # Eclipse diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 3e448ae84c..80bbaa9e0c 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -163,6 +163,7 @@ class ScriptRegistry ScriptMgr::ScriptMgr() : _scriptCount(0), _scheduledScripts(0) { + } ScriptMgr::~ScriptMgr() @@ -171,18 +172,8 @@ ScriptMgr::~ScriptMgr() void ScriptMgr::Initialize() { - uint32 oldMSTime = getMSTime(); - - LoadDatabase(); - - sLog->outString("Loading C++ scripts"); - - FillSpellSummary(); AddScripts(); - CheckIfScriptsInDatabaseExist(); - - sLog->outString(">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); - sLog->outString(); + sLog->outString("Loading C++ scripts"); } void ScriptMgr::Unload() @@ -223,7 +214,32 @@ void ScriptMgr::Unload() void ScriptMgr::LoadDatabase() { + uint32 oldMSTime = getMSTime(); + sScriptSystemMgr->LoadScriptWaypoints(); + + // Add all scripts that must be loaded after db/maps + ScriptRegistry<WorldMapScript>::AddALScripts(); + ScriptRegistry<BattlegroundMapScript>::AddALScripts(); + ScriptRegistry<InstanceMapScript>::AddALScripts(); + ScriptRegistry<SpellScriptLoader>::AddALScripts(); + ScriptRegistry<ItemScript>::AddALScripts(); + ScriptRegistry<CreatureScript>::AddALScripts(); + ScriptRegistry<GameObjectScript>::AddALScripts(); + ScriptRegistry<AreaTriggerScript>::AddALScripts(); + ScriptRegistry<BattlegroundScript>::AddALScripts(); + ScriptRegistry<OutdoorPvPScript>::AddALScripts(); + ScriptRegistry<WeatherScript>::AddALScripts(); + ScriptRegistry<ConditionScript>::AddALScripts(); + ScriptRegistry<TransportScript>::AddALScripts(); + ScriptRegistry<AchievementCriteriaScript>::AddALScripts(); + + FillSpellSummary(); + + CheckIfScriptsInDatabaseExist(); + + sLog->outString(">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); + sLog->outString(); } struct TSpellSummary @@ -437,9 +453,14 @@ void ScriptMgr::OnOpenStateChange(bool open) FOREACH_SCRIPT(WorldScript)->OnOpenStateChange(open); } -void ScriptMgr::OnConfigLoad(bool reload) +void ScriptMgr::OnBeforeConfigLoad(bool reload) +{ + FOREACH_SCRIPT(WorldScript)->OnBeforeConfigLoad(reload); +} + +void ScriptMgr::OnAfterConfigLoad(bool reload) { - FOREACH_SCRIPT(WorldScript)->OnConfigLoad(reload); + FOREACH_SCRIPT(WorldScript)->OnAfterConfigLoad(reload); } void ScriptMgr::OnMotdChange(std::string& newMotd) @@ -1326,27 +1347,18 @@ FormulaScript::FormulaScript(const char* name) WorldMapScript::WorldMapScript(const char* name, uint32 mapId) : ScriptObject(name), MapScript<Map>(mapId) { - if (GetEntry() && !GetEntry()->IsWorldMap()) - sLog->outError("WorldMapScript for map %u is invalid.", mapId); - ScriptRegistry<WorldMapScript>::AddScript(this); } InstanceMapScript::InstanceMapScript(const char* name, uint32 mapId) : ScriptObject(name), MapScript<InstanceMap>(mapId) { - if (GetEntry() && !GetEntry()->IsDungeon()) - sLog->outError("InstanceMapScript for map %u is invalid.", mapId); - ScriptRegistry<InstanceMapScript>::AddScript(this); } BattlegroundMapScript::BattlegroundMapScript(const char* name, uint32 mapId) : ScriptObject(name), MapScript<BattlegroundMap>(mapId) { - if (GetEntry() && !GetEntry()->IsBattleground()) - sLog->outError("BattlegroundMapScript for map %u is invalid.", mapId); - ScriptRegistry<BattlegroundMapScript>::AddScript(this); } @@ -1454,6 +1466,7 @@ GroupScript::GroupScript(const char* name) // Instantiate static members of ScriptRegistry. template<class TScript> std::map<uint32, TScript*> ScriptRegistry<TScript>::ScriptPointerList; +template<class TScript> std::vector<TScript*> ScriptRegistry<TScript>::ALScripts; template<class TScript> uint32 ScriptRegistry<TScript>::_scriptIdCounter = 0; // Specialize for each script type class like so: diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 42784a96d6..b7dfec043f 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -159,6 +159,8 @@ class ScriptObject // Do not override this in scripts; it should be overridden by the various script type classes. It indicates // whether or not this script type must be assigned in the database. virtual bool IsDatabaseBound() const { return false; } + virtual bool isAfterLoadScript() const { return IsDatabaseBound(); } + virtual void checkValidity() { } const std::string& GetName() const { return _name; } @@ -242,7 +244,10 @@ class WorldScript : public ScriptObject virtual void OnOpenStateChange(bool /*open*/) { } // Called after the world configuration is (re)loaded. - virtual void OnConfigLoad(bool /*reload*/) { } + virtual void OnAfterConfigLoad(bool /*reload*/) { } + + // Called before the world configuration is (re)loaded. + virtual void OnBeforeConfigLoad(bool /*reload*/) { } // Called before the message of the day is changed. virtual void OnMotdChange(std::string& /*newMotd*/) { } @@ -296,17 +301,22 @@ class FormulaScript : public ScriptObject template<class TMap> class MapScript : public UpdatableScript<TMap> { MapEntry const* _mapEntry; + uint32 _mapId; protected: MapScript(uint32 mapId) - : _mapEntry(sMapStore.LookupEntry(mapId)) + : _mapId(mapId) { - if (!_mapEntry) - sLog->outError("Invalid MapScript for %u; no such map ID.", mapId); } public: + void checkMap() { + _mapEntry = sMapStore.LookupEntry(_mapId); + + if (!_mapEntry) + sLog->outError("Invalid MapScript for %u; no such map ID.", _mapId); + } // Gets the MapEntry structure associated with this script. Can return NULL. MapEntry const* GetEntry() { return _mapEntry; } @@ -338,6 +348,17 @@ class WorldMapScript : public ScriptObject, public MapScript<Map> protected: WorldMapScript(const char* name, uint32 mapId); + + public: + + bool isAfterLoadScript() const { return true; } + + void checkValidity() { + checkMap(); + + if (GetEntry() && !GetEntry()->IsWorldMap()) + sLog->outError("WorldMapScript for map %u is invalid.", GetEntry()->MapID); + } }; class InstanceMapScript : public ScriptObject, public MapScript<InstanceMap> @@ -350,6 +371,13 @@ class InstanceMapScript : public ScriptObject, public MapScript<InstanceMap> bool IsDatabaseBound() const { return true; } + void checkValidity() { + checkMap(); + + if (GetEntry() && !GetEntry()->IsDungeon()) + sLog->outError("InstanceMapScript for map %u is invalid.", GetEntry()->MapID); + } + // Gets an InstanceScript object for this instance. virtual InstanceScript* GetInstanceScript(InstanceMap* /*map*/) const { return NULL; } }; @@ -359,6 +387,17 @@ class BattlegroundMapScript : public ScriptObject, public MapScript<Battleground protected: BattlegroundMapScript(const char* name, uint32 mapId); + + public: + + bool isAfterLoadScript() const { return true; } + + void checkValidity() { + checkMap(); + + if (GetEntry() && !GetEntry()->IsBattleground()) + sLog->outError("BattlegroundMapScript for map %u is invalid.", GetEntry()->MapID); + } }; class ItemScript : public ScriptObject @@ -826,7 +865,8 @@ class ScriptMgr public: /* WorldScript */ void OnOpenStateChange(bool open); - void OnConfigLoad(bool reload); + void OnBeforeConfigLoad(bool reload); + void OnAfterConfigLoad(bool reload); void OnMotdChange(std::string& newMotd); void OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask); void OnShutdownCancel(); @@ -1024,75 +1064,92 @@ class ScriptRegistry typedef std::map<uint32, TScript*> ScriptMap; typedef typename ScriptMap::iterator ScriptMapIterator; + typedef std::vector<TScript*> ScriptVector; + typedef typename ScriptVector::iterator ScriptVectorIterator; + // The actual list of scripts. This will be accessed concurrently, so it must not be modified // after server startup. static ScriptMap ScriptPointerList; + // After database load scripts + static ScriptVector ALScripts; static void AddScript(TScript* const script) { ASSERT(script); - // See if the script is using the same memory as another script. If this happens, it means that - // someone forgot to allocate new memory for a script. - for (ScriptMapIterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) + if (!_checkMemory(script)) + return; + + if (script->isAfterLoadScript()) { - if (it->second == script) - { - sLog->outError("Script '%s' has same memory pointer as '%s'.", - script->GetName().c_str(), it->second->GetName().c_str()); + ALScripts.push_back(script); + } + else + { + script->checkValidity(); - return; - } + // We're dealing with a code-only script; just add it. + ScriptPointerList[_scriptIdCounter++] = script; + sScriptMgr->IncrementScriptCount(); } + } - if (script->IsDatabaseBound()) - { - // 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). - uint32 id = sObjectMgr->GetScriptId(script->GetName().c_str()); - if (id) - { - // Try to find an existing script. - bool existing = false; - for (ScriptMapIterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) + static void AddALScripts() { + for(ScriptVectorIterator it = ALScripts.begin(); it != ALScripts.end(); ++it) { + TScript* const script = *it; + + script->checkValidity(); + + if (script->IsDatabaseBound()) { + + if (!_checkMemory(script)) + return; + + // 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). + uint32 id = sObjectMgr->GetScriptId(script->GetName().c_str()); + if (id) { - // If the script names match... - if (it->second->GetName() == script->GetName()) + // Try to find an existing script. + bool existing = false; + for (ScriptMapIterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) { - // ... It exists. - existing = true; - break; + // If the script names match... + if (it->second->GetName() == script->GetName()) + { + // ... It exists. + existing = true; + break; + } } - } - // If the script isn't assigned -> assign it! - if (!existing) - { - ScriptPointerList[id] = script; - sScriptMgr->IncrementScriptCount(); + // If the script isn't assigned -> assign it! + if (!existing) + { + ScriptPointerList[id] = script; + sScriptMgr->IncrementScriptCount(); + } + else + { + // If the script is already assigned -> delete it! + sLog->outError("Script '%s' already assigned with the same script name, so the script can't work.", + script->GetName().c_str()); + + ASSERT(false); // Error that should be fixed ASAP. + } } else { - // If the script is already assigned -> delete it! - sLog->outError("Script '%s' already assigned with the same script name, so the script can't work.", - script->GetName().c_str()); - - ASSERT(false); // Error that should be fixed ASAP. + // The script uses a script name from database, but isn't assigned to anything. + if (script->GetName().find("Smart") == std::string::npos) + sLog->outErrorDb("Script named '%s' does not have a script name assigned in database.", + script->GetName().c_str()); } + } else { + // We're dealing with a code-only script; just add it. + ScriptPointerList[_scriptIdCounter++] = script; + sScriptMgr->IncrementScriptCount(); } - else - { - // The script uses a script name from database, but isn't assigned to anything. - if (script->GetName().find("Smart") == std::string::npos) - sLog->outErrorDb("Script named '%s' does not have a script name assigned in database.", - script->GetName().c_str()); - } - } - else - { - // We're dealing with a code-only script; just add it. - ScriptPointerList[_scriptIdCounter++] = script; - sScriptMgr->IncrementScriptCount(); } } @@ -1107,6 +1164,24 @@ class ScriptRegistry } private: + // See if the script is using the same memory as another script. If this happens, it means that + // someone forgot to allocate new memory for a script. + static bool _checkMemory(TScript* const script) { + // See if the script is using the same memory as another script. If this happens, it means that + // someone forgot to allocate new memory for a script. + for (ScriptMapIterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) + { + if (it->second == script) + { + sLog->outError("Script '%s' has same memory pointer as '%s'.", + script->GetName().c_str(), it->second->GetName().c_str()); + + return false; + } + } + + return true; + } // Counter used for code-only scripts. static uint32 _scriptIdCounter; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 201c4e38cb..6de54ff737 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -436,6 +436,8 @@ void World::LoadConfigSettings(bool reload) sLog->ReloadConfig(); // Reload log levels and filters } + sScriptMgr->OnBeforeConfigLoad(reload); + ///- Read the player limit and the Message of the day from the config file if (!reload) SetPlayerAmountLimit(sConfigMgr->GetIntDefault("PlayerLimit", 100)); @@ -1236,8 +1238,7 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_BIRTHDAY_TIME] = sConfigMgr->GetIntDefault("BirthdayTime", 1222964635); // call ScriptMgr if we're reloading the configuration - if (reload) - sScriptMgr->OnConfigLoad(reload); + sScriptMgr->OnAfterConfigLoad(reload); } extern void LoadGameObjectModelList(); @@ -1253,6 +1254,9 @@ void World::SetInitialWorldSettings() ///- Initialize detour memory management dtAllocSetCustom(dtCustomAlloc, dtCustomFree); + + sLog->outString("Initializing Scripts..."); + sScriptMgr->Initialize(); ///- Initialize config settings LoadConfigSettings(); @@ -1700,9 +1704,8 @@ void World::SetInitialWorldSettings() sLog->outString("Loading Creature Text Locales..."); sCreatureTextMgr->LoadCreatureTextLocales(); - sLog->outString("Initializing Scripts..."); - sScriptMgr->Initialize(); - sScriptMgr->OnConfigLoad(false); // must be done after the ScriptMgr has been properly initialized + sLog->outString("Loading Scripts..."); + sScriptMgr->LoadDatabase(); sLog->outString("Validating spell scripts..."); sObjectMgr->ValidateSpellScripts(); |