Core/Game: Add a dynamic script reloader which reloads scripts modules on changes.

* is responsible for registering plain modules.
* requires compilation with the `WITH_DYNAMIC_LINKING` flag.
* requires further support of the ScriptMgr.
This commit is contained in:
Aokromes
2016-08-10 03:29:20 +02:00
parent 3d25c14e74
commit e8e164e28f
8 changed files with 1669 additions and 6 deletions

View File

@@ -263,12 +263,19 @@ void ScriptMgr::Initialize()
FillSpellSummary();
// Load core script systems
// SmartAI
BeginScriptContext("core scripts");
AddSC_SmartScripts();
FinishScriptContext();
// Load all static linked scripts through the script loader function.
BeginScriptContext("static scripts");
ASSERT(_script_loader_callback,
"Script loader callback wasn't registered!");
_script_loader_callback();
FinishScriptContext();
#ifdef SCRIPTS
for (std::string const& scriptName : UnusedScriptNames)
@@ -280,6 +287,21 @@ void ScriptMgr::Initialize()
TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime));
}
void ScriptMgr::BeginScriptContext(std::string const& context)
{
_currentContext = context;
}
void ScriptMgr::FinishScriptContext()
{
_currentContext.clear();
}
void ScriptMgr::ReleaseScriptContext(std::string const& /*context*/)
{
// ToDo
}
void ScriptMgr::Unload()
{
#define SCR_CLEAR(T) \

View File

@@ -837,9 +837,6 @@ class TC_GAME_API GroupScript : public ScriptObject
virtual void OnDisband(Group* /*group*/) { }
};
// Placed here due to ScriptRegistry::AddScript dependency.
#define sScriptMgr ScriptMgr::instance()
// namespace
// {
typedef std::list<std::string> UnusedScriptNamesContainer;
@@ -855,12 +852,13 @@ class TC_GAME_API ScriptMgr
ScriptMgr();
virtual ~ScriptMgr();
void FillSpellSummary();
void LoadDatabase();
public: /* Initialization */
static ScriptMgr* instance();
void Initialize();
void LoadDatabase();
void FillSpellSummary();
const char* ScriptsVersion() const { return "Integrated Trinity Scripts"; }
@@ -876,6 +874,12 @@ class TC_GAME_API ScriptMgr
_script_loader_callback = script_loader_callback;
}
public: /* Script contexts */
void BeginScriptContext(std::string const& context);
void FinishScriptContext();
void ReleaseScriptContext(std::string const& context);
public: /* Unloading */
void Unload();
@@ -1106,13 +1110,16 @@ class TC_GAME_API ScriptMgr
bool IsScriptScheduled() const { return _scheduledScripts > 0; }
private:
uint32 _scriptCount;
//atomic op counter for active scripts amount
std::atomic<uint32> _scheduledScripts;
ScriptLoaderCallbackType _script_loader_callback;
std::string _currentContext;
};
#define sScriptMgr ScriptMgr::instance()
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCRIPT_RELOADER_H
#define SCRIPT_RELOADER_H
#include <memory>
#include <string>
#include "Define.h"
#include <boost/filesystem/path.hpp>
/// Represents a strong reference to a dynamic library which
/// provides C++ scripts. As long as one reference to the library exists
/// the library is kept loaded in the server, which makes it possible to lazy
/// unload several script types on demand (like SpellScripts), and to
/// provide multiple versions of the same script to the script factories.
///
/// Acquire a new reference through using:
/// `ScriptReloadMgr::AcquireModuleReferenceOfContext`
class ModuleReference
{
public:
virtual ~ModuleReference() { }
/// Returns the git revision hash of the referenced script module
virtual char const* GetScriptModuleRevisionHash() const = 0;
/// Returns the name of the referenced script module
virtual char const* GetScriptModule() const = 0;
/// Returns the path to the script module
virtual boost::filesystem::path const& GetModulePath() const = 0;
};
/// Provides the whole physical dynamic library unloading capability.
/// Loads, Reloads and Unloads dynamic libraries on changes and
/// informs the ScriptMgr about changes which were made.
/// The ScriptReloadMgr is also responsible for watching the source directory
/// and to invoke a build on changes.
class TC_GAME_API ScriptReloadMgr
{
protected:
ScriptReloadMgr() { }
public:
virtual ~ScriptReloadMgr() { }
/// Initializes the ScriptReloadMgr
virtual void Initialize() { }
/// Needs to be called periodically to check for updates on script modules.
/// Expects to be invoked in a thread safe way which means it's required that
/// the current thread is the only one which accesses the world data.
virtual void Update() { }
/// Unloads the ScriptReloadMgr
virtual void Unload() { }
/// Returns an owning reference to the current module of the given context
static std::shared_ptr<ModuleReference> AcquireModuleReferenceOfContext(
std::string const& context);
/// Returns the unique ScriptReloadMgr singleton instance
static ScriptReloadMgr* instance();
};
#define sScriptReloadMgr ScriptReloadMgr::instance()
#endif // SCRIPT_RELOADER_H

View File

@@ -54,6 +54,7 @@
#include "PoolMgr.h"
#include "GitRevision.h"
#include "ScriptMgr.h"
#include "ScriptReloadMgr.h"
#include "SkillDiscovery.h"
#include "SkillExtraItems.h"
#include "SmartAI.h"
@@ -1385,9 +1386,18 @@ void World::LoadConfigSettings(bool reload)
m_bool_configs[CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA] = sConfigMgr->GetBoolDefault("Calculate.Creature.Zone.Area.Data", false);
m_bool_configs[CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA] = sConfigMgr->GetBoolDefault("Calculate.Gameoject.Zone.Area.Data", false);
// prevent character rename on character customization
m_bool_configs[CONFIG_PREVENT_RENAME_CUSTOMIZATION] = sConfigMgr->GetBoolDefault("PreventRenameCharacterOnCustomization", false);
// HotSwap
m_bool_configs[CONFIG_HOTSWAP_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.Enabled", true);
m_bool_configs[CONFIG_HOTSWAP_RECOMPILER_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableReCompiler", true);
m_bool_configs[CONFIG_HOTSWAP_EARLY_TERMINATION_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableEarlyTermination", true);
m_bool_configs[CONFIG_HOTSWAP_BUILD_FILE_RECREATION_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableBuildFileRecreation", true);
m_bool_configs[CONFIG_HOTSWAP_INSTALL_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnableInstall", true);
m_bool_configs[CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED] = sConfigMgr->GetBoolDefault("HotSwap.EnablePrefixCorrection", true);
// call ScriptMgr if we're reloading the configuration
if (reload)
sScriptMgr->OnConfigLoad(reload);
@@ -1891,6 +1901,7 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Initializing Scripts...");
sScriptMgr->Initialize();
sScriptMgr->OnConfigLoad(false); // must be done after the ScriptMgr has been properly initialized
sScriptReloadMgr->Initialize();
TC_LOG_INFO("server.loading", "Validating spell scripts...");
sObjectMgr->ValidateSpellScripts();
@@ -1926,6 +1937,8 @@ void World::SetInitialWorldSettings()
m_timers[WUPDATE_PINGDB].SetInterval(getIntConfig(CONFIG_DB_PING_INTERVAL)*MINUTE*IN_MILLISECONDS); // Mysql ping time in minutes
m_timers[WUPDATE_CHECK_FILECHANGES].SetInterval(500);
m_timers[WUPDATE_GUILDSAVE].SetInterval(getIntConfig(CONFIG_GUILD_SAVE_INTERVAL) * MINUTE * IN_MILLISECONDS);
//to set mailtimer to return mails every day between 4 and 5 am
@@ -2182,6 +2195,13 @@ void World::Update(uint32 diff)
m_timers[WUPDATE_AHBOT].Reset();
}
/// <li> Handle file changes
if (m_timers[WUPDATE_CHECK_FILECHANGES].Passed())
{
sScriptReloadMgr->Update();
m_timers[WUPDATE_CHECK_FILECHANGES].Reset();
}
/// <li> Handle session updates when the timer has passed
ResetTimeDiffRecord();
UpdateSessions(diff);

View File

@@ -91,6 +91,7 @@ enum WorldTimers
WUPDATE_AHBOT,
WUPDATE_PINGDB,
WUPDATE_GUILDSAVE,
WUPDATE_CHECK_FILECHANGES,
WUPDATE_COUNT
};
@@ -178,6 +179,12 @@ enum WorldBoolConfigs
CONFIG_BASEMAP_LOAD_GRIDS,
CONFIG_INSTANCEMAP_LOAD_GRIDS,
CONFIG_PREVENT_RENAME_CUSTOMIZATION,
CONFIG_HOTSWAP_ENABLED,
CONFIG_HOTSWAP_RECOMPILER_ENABLED,
CONFIG_HOTSWAP_EARLY_TERMINATION_ENABLED,
CONFIG_HOTSWAP_BUILD_FILE_RECREATION_ENABLED,
CONFIG_HOTSWAP_INSTALL_ENABLED,
CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED,
BOOL_CONFIG_VALUE_COUNT
};

View File

@@ -35,6 +35,7 @@
#include "InstanceSaveMgr.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "ScriptReloadMgr.h"
#include "ScriptLoader.h"
#include "OutdoorPvP/OutdoorPvPMgr.h"
#include "BattlegroundMgr.h"
@@ -280,6 +281,7 @@ extern int main(int argc, char** argv)
sOutdoorPvPMgr->Die();
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
sScriptMgr->Unload();
sScriptReloadMgr->Unload();
// set server offline
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realm.Id.Realm);

View File

@@ -12,6 +12,7 @@
# SERVER LOGGING
# SERVER SETTINGS
# UPDATE SETTINGS
# HOTSWAP SETTINGS
# WARDEN SETTINGS
# PLAYER INTERACTION
# CREATURE SETTINGS
@@ -1261,6 +1262,78 @@ Updates.CleanDeadRefMaxCount = 3
#
###################################################################################################
###################################################################################################
# HOTSWAP SETTINGS
#
# HotSwap.Enabled (Requires compilation with DYNAMIC_LINKING=1)
# Description: Enables dynamic script hotswapping.
# Reloads scripts on changes.
# Default: 1 - (Enabled)
# 0 - (Disabled)
HotSwap.Enabled = 1
#
# HotSwap.ScriptDir
# Description: Directory containing the script shared libraries (.dll/.so).
# Example: "/usr/local/scripts"
# Default: "scripts"
HotSwap.ScriptDir = "scripts"
# HotSwap.EnableReCompiler
# Description: Enables the dynamic script recompiler.
# Watches your script source directories and recompiles the
# script modules on changes.
# Default: 0 - (Disabled)
# 1 - (Enabled)
HotSwap.EnableReCompiler = 1
# HotSwap.EnableEarlyTermination
# Description: Terminate the build of a module when an associated
# source file was changed meanwhile.
# Default: 1 - (Enabled)
# 0 - (Disabled)
HotSwap.EnableEarlyTermination = 1
# HotSwap.EnableBuildFileRecreation
# Description: Recreate build files when sources to a module
# were added or removed.
# Default: 1 - (Enabled)
# 0 - (Disabled)
HotSwap.EnableBuildFileRecreation = 1
#
# HotSwap.EnableInstall
# Description: Enables cmake install after automatic builds have finished
# Default: 1 - (Enabled)
# 0 - (Disabled)
HotSwap.EnableInstall = 1
#
# HotSwap.EnablePrefixCorrection
# Description: Allows the core to automatic set the CMAKE_INSTALL_PREFIX
# to it's current location in the filesystem.
# Default: 1 - (Enabled)
# 0 - (Disabled)
HotSwap.EnablePrefixCorrection = 1
# HotSwap.ReCompilerBuildType
# Description: Defines the build type of the builds invoked by the recompiler.
# Default: "" - Built-in build type of the module is used.
# "Release" - Release builds only
# "Debug" - Debug builds only
HotSwap.ReCompilerBuildType = ""
#
###################################################################################################
###################################################################################################
# WARDEN SETTINGS
#
@@ -3622,6 +3695,7 @@ Logger.sql.updates=3,Console Server
#Logger.rbac=3,Console Server
#Logger.scripts=3,Console Server
#Logger.scripts.ai=3,Console Server
#Logger.scripts.hotswap=3,Console Server
#Logger.server.authserver=3,Console Server
#Logger.spells=3,Console Server
#Logger.spells.periodic=3,Console Server