diff --git a/.travis.yml b/.travis.yml
index d8158ae9..99dc3656 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,6 +32,7 @@ before_install:
- sudo add-apt-repository -y ppa:rexut/recoil
- sudo apt-get update
- sudo apt-get install -y libboost1.63-dev libboost1.63-all-dev
+ - sudo apt-get install -y libmysqlclient-dev
# Build steps
script:
diff --git a/bin/config/settings_zone.xml b/bin/config/settings_zone.xml
index a0d56a0a..4dc1b7ef 100644
--- a/bin/config/settings_zone.xml
+++ b/bin/config/settings_zone.xml
@@ -14,6 +14,7 @@
1
+ ../scripts/native/
../cmake-build-debug/
cmake --build %1% --target %2%
diff --git a/scripts/native/ScriptObject.h b/scripts/native/ScriptObject.h
index 108b8df0..6691f474 100644
--- a/scripts/native/ScriptObject.h
+++ b/scripts/native/ScriptObject.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#endif //SAPPHIRE_SCRIPTOBJECT_H
diff --git a/src/libraries b/src/libraries
index 8a26ae78..f4d3c5b3 160000
--- a/src/libraries
+++ b/src/libraries
@@ -1 +1 @@
-Subproject commit 8a26ae78e37701a9b66e7200f1e0ad3387da17c3
+Subproject commit f4d3c5b38d13a15efc42686c9bac768c2be28be1
diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp
index 9f6a39dd..5010e770 100644
--- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp
+++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp
@@ -594,10 +594,10 @@ void Core::DebugCommandHandler::script( char* data, Entity::Player &player, boos
if( subCommand == params )
player.sendDebug( "Command failed: requires name of script to reload" );
else
- if( g_scriptMgr.getNativeScriptHandler().reloadScript( params ) )
- player.sendDebug( "Reloaded '" + params + "' successfully" );
- else
- player.sendDebug( "Failed to reload '" + params + "'" );
+ {
+ g_scriptMgr.getNativeScriptHandler().reloadScript( params );
+ player.sendDebug( "Attempting to reload script: " + params );
+ }
}
else if( subCommand == "build" || subCommand == "b" )
{
diff --git a/src/servers/Server_Zone/Script/NativeScriptManager.cpp b/src/servers/Server_Zone/Script/NativeScriptManager.cpp
index 2441816e..4ccf1c15 100644
--- a/src/servers/Server_Zone/Script/NativeScriptManager.cpp
+++ b/src/servers/Server_Zone/Script/NativeScriptManager.cpp
@@ -137,19 +137,31 @@ namespace Core {
return m_loader.unloadScript( info );
}
- bool NativeScriptManager::reloadScript( const std::string& name )
+ void NativeScriptManager::reloadScript( const std::string &name )
{
auto info = m_loader.getScriptInfo( name );
if( !info )
- return false;
+ return;
// backup actual lib path
std::string libPath( info->library_path );
if( !unloadScript( info ) )
- return false;
+ return;
- return loadScript( libPath );
+ m_scriptLoadQueue.push( libPath );
+ }
+
+ void NativeScriptManager::processLoadQueue()
+ {
+ while( !m_scriptLoadQueue.empty() )
+ {
+ auto item = m_scriptLoadQueue.front();
+
+ loadScript( item );
+
+ m_scriptLoadQueue.pop();
+ }
}
void NativeScriptManager::findScripts( std::set< Core::Scripting::ScriptInfo* >& scripts, const std::string& search )
@@ -157,6 +169,11 @@ namespace Core {
return m_loader.findScripts( scripts, search );
}
+ bool NativeScriptManager::isModuleLoaded( const std::string &name )
+ {
+ return m_loader.isModuleLoaded( name );
+ }
+
boost::shared_ptr< NativeScriptManager > createNativeScriptMgr()
diff --git a/src/servers/Server_Zone/Script/NativeScriptManager.h b/src/servers/Server_Zone/Script/NativeScriptManager.h
index 42c4a4ed..8bd4ec41 100644
--- a/src/servers/Server_Zone/Script/NativeScriptManager.h
+++ b/src/servers/Server_Zone/Script/NativeScriptManager.h
@@ -3,6 +3,7 @@
#include
#include
+#include
#include
#include
@@ -26,6 +27,8 @@ namespace Scripting {
ScriptLoader m_loader;
+ std::queue< std::string > m_scriptLoadQueue;
+
bool unloadScript( ScriptInfo* info );
public:
@@ -39,10 +42,13 @@ namespace Scripting {
bool loadScript( const std::string& path );
bool unloadScript( const std::string& name );
- bool reloadScript( const std::string& name );
+ void reloadScript( const std::string &name );
void findScripts( std::set< Core::Scripting::ScriptInfo* >& scripts, const std::string& search );
+ void processLoadQueue();
+
const std::string getModuleExtension();
+ bool isModuleLoaded( const std::string& name );
template< typename key, typename val >
bool removeValueFromMap( ScriptObject* ptr, std::unordered_map< key, val >& map )
diff --git a/src/servers/Server_Zone/Script/ScriptLoader.cpp b/src/servers/Server_Zone/Script/ScriptLoader.cpp
index 7900a91e..b480e06e 100644
--- a/src/servers/Server_Zone/Script/ScriptLoader.cpp
+++ b/src/servers/Server_Zone/Script/ScriptLoader.cpp
@@ -62,12 +62,17 @@ Core::Scripting::ScriptInfo* Core::Scripting::ScriptLoader::loadModule( const st
fs::create_directories( cacheDir );
fs::path dest( cacheDir /= f.filename().string() );
- if ( fs::exists( dest ) )
+ try
{
- fs::remove( dest );
+ fs::copy_file( f, dest, fs::copy_option::overwrite_if_exists );
+ }
+ catch( const boost::filesystem::filesystem_error& err )
+ {
+ g_log.error( "Error copying file to cache: " + err.code().message() );
+
+ return nullptr;
}
- fs::copy_file( f, dest );
#ifdef _WIN32
ModuleHandle handle = LoadLibrary( dest.string().c_str() );
@@ -82,7 +87,7 @@ Core::Scripting::ScriptInfo* Core::Scripting::ScriptLoader::loadModule( const st
return nullptr;
}
- g_log.info( "Loaded module '" + f.filename().string() + "' @ 0x" + boost::str( boost::format( "%|08X|" ) % handle ) );
+ g_log.debug( "Loaded module '" + f.filename().string() + "' @ 0x" + boost::str( boost::format( "%|08X|" ) % handle ) );
auto info = new ScriptInfo;
info->handle = handle;
diff --git a/src/servers/Server_Zone/Script/ScriptManager.cpp b/src/servers/Server_Zone/Script/ScriptManager.cpp
index 2680618e..cd7afa50 100644
--- a/src/servers/Server_Zone/Script/ScriptManager.cpp
+++ b/src/servers/Server_Zone/Script/ScriptManager.cpp
@@ -21,18 +21,28 @@
#include
+// enable the ambiguity fix for every platform to avoid #define nonsense
+#define WIN_AMBIGUITY_FIX
+#include
+
extern Core::Logger g_log;
extern Core::Data::ExdData g_exdData;
extern Core::ServerZone g_serverZone;
-Core::Scripting::ScriptManager::ScriptManager()
+Core::Scripting::ScriptManager::ScriptManager() :
+ m_firstScriptChangeNotificiation( false )
{
m_nativeScriptManager = createNativeScriptMgr();
}
Core::Scripting::ScriptManager::~ScriptManager()
{
+ Watchdog::unwatchAll();
+}
+void Core::Scripting::ScriptManager::update()
+{
+ m_nativeScriptManager->processLoadQueue();
}
bool Core::Scripting::ScriptManager::init()
@@ -42,16 +52,57 @@ bool Core::Scripting::ScriptManager::init()
loadDir( g_serverZone.getConfig()->getValue< std::string >( "Settings.General.Scripts.Path", "./compiledscripts/" ),
files, m_nativeScriptManager->getModuleExtension() );
+ uint32_t scriptsFound = 0;
+ uint32_t scriptsLoaded = 0;
+
for( auto itr = files.begin(); itr != files.end(); ++itr )
{
auto& path = *itr;
- m_nativeScriptManager->loadScript( path );
+ scriptsFound++;
+
+ if( m_nativeScriptManager->loadScript( path ) )
+ scriptsLoaded++;
}
+ g_log.info( "ScriptManager: Loaded " + std::to_string( scriptsLoaded ) + "/" + std::to_string( scriptsFound ) + " scripts successfully" );
+
+ watchDirectories();
+
return true;
}
+void Core::Scripting::ScriptManager::watchDirectories()
+{
+ Watchdog::watchMany( g_serverZone.getConfig()->getValue< std::string >( "Settings.General.Scripts.Path", "./compiledscripts/" ) + "*" + m_nativeScriptManager->getModuleExtension(),
+ [ this ]( const std::vector< ci::fs::path >& paths )
+ {
+ if( !m_firstScriptChangeNotificiation )
+ {
+ // for whatever reason, the first time this runs, it detects every file as changed
+ // so we're always going to ignore the first notification
+ m_firstScriptChangeNotificiation = true;
+ return;
+ }
+
+ for( auto path : paths )
+ {
+ if( m_nativeScriptManager->isModuleLoaded( path.stem().string() ) )
+ {
+ g_log.debug( "Reloading changed script: " + path.stem().string() );
+
+ m_nativeScriptManager->reloadScript( path.stem().string() );
+ }
+ else
+ {
+ g_log.debug( "Loading new script: " + path.stem().string() );
+
+ m_nativeScriptManager->loadScript( path.string() );
+ }
+ }
+ });
+}
+
void Core::Scripting::ScriptManager::loadDir( std::string dirname, std::set& files, std::string ext )
{
@@ -59,7 +110,7 @@ void Core::Scripting::ScriptManager::loadDir( std::string dirname, std::set m_onFirstEnterWorld;
// auto fn = m_pChaiHandler->eval< std::function >( "onFirstEnterWorld" );
+ bool m_firstScriptChangeNotificiation;
+
public:
ScriptManager();
~ScriptManager();
@@ -29,6 +31,10 @@ namespace Core
bool init();
void reload();
+ void update();
+
+ void watchDirectories();
+
void onPlayerFirstEnterWorld( Entity::Player& player );
static bool registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId, uint32_t bnpcNameId, uint32_t modelId, std::string aiName );
diff --git a/src/servers/Server_Zone/ServerZone.cpp b/src/servers/Server_Zone/ServerZone.cpp
index 8044f7ec..eccb7ea4 100644
--- a/src/servers/Server_Zone/ServerZone.cpp
+++ b/src/servers/Server_Zone/ServerZone.cpp
@@ -260,6 +260,8 @@ void Core::ServerZone::mainLoop()
g_zoneMgr.updateZones();
+ g_scriptMgr.update();
+
auto currTime = static_cast< uint32_t >( time( nullptr ) );
lock_guard< std::mutex > lock( this->m_sessionMutex );