summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYehonal <yehonal.azeroth@gmail.com>2016-08-07 12:28:17 +0200
committerYehonal <yehonal.azeroth@gmail.com>2016-08-07 12:28:17 +0200
commit5b824569a9f80cc08c98dbae3e2c8be3b3b587fc (patch)
tree438f2cb15537a17e618a53e99fde50d6829686e5
parente5f8ecd7ecd70a413d27dab6c375647a3f6b0a12 (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--.gitignore1
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp57
-rw-r--r--src/server/game/Scripting/ScriptMgr.h181
-rw-r--r--src/server/game/World/World.cpp13
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();