From 0f4e30c3e3fe1916b92bc0a3c9c1d2b2e9ad49c4 Mon Sep 17 00:00:00 2001 From: GokuWeedLord Date: Thu, 14 Dec 2017 22:30:06 +1100 Subject: [PATCH 1/4] automagically reload rebuilt scripts --- .travis.yml | 1 + bin/config/settings_zone.xml | 1 + scripts/native/ScriptObject.h | 1 + src/libraries | 2 +- .../DebugCommand/DebugCommandHandler.cpp | 8 +-- .../Script/NativeScriptManager.cpp | 25 ++++++-- .../Server_Zone/Script/NativeScriptManager.h | 8 ++- .../Server_Zone/Script/ScriptLoader.cpp | 13 +++-- .../Server_Zone/Script/ScriptManager.cpp | 57 ++++++++++++++++++- .../Server_Zone/Script/ScriptManager.h | 6 ++ src/servers/Server_Zone/ServerZone.cpp | 2 + 11 files changed, 107 insertions(+), 17 deletions(-) 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 ); From 7df77ae52065a11a6dc6747206ded5cb0ae71e39 Mon Sep 17 00:00:00 2001 From: GokuWeedLord Date: Thu, 14 Dec 2017 23:05:53 +1100 Subject: [PATCH 2/4] change reload -> queue reload & some minor refactoring --- bin/config/settings_zone.xml | 22 +++++++++---------- .../DebugCommand/DebugCommandHandler.cpp | 6 ++--- .../Script/NativeScriptManager.cpp | 2 +- .../Server_Zone/Script/NativeScriptManager.h | 2 +- .../Server_Zone/Script/ScriptManager.cpp | 7 +++--- .../Server_Zone/Script/ScriptManager.h | 2 +- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/bin/config/settings_zone.xml b/bin/config/settings_zone.xml index 4dc1b7ef..a16b685d 100644 --- a/bin/config/settings_zone.xml +++ b/bin/config/settings_zone.xml @@ -8,16 +8,16 @@ H:\\SteamLibrary\\steamapps\\common\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv - - ./compiledscripts/ - ./cache/ + + ./compiledscripts/ + ./cache/ - - 1 + + 1 ../scripts/native/ - ../cmake-build-debug/ - cmake --build %1% --target %2% - + ../cmake-build-debug/ + cmake --build %1% --target %2% + @@ -29,13 +29,13 @@ root sapphire - 2 - 2 + 2 + 2 - + <<<Welcome to Sapphire>>> This is a very good server diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp index 5010e770..60dd6967 100644 --- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp +++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp @@ -589,14 +589,14 @@ void Core::DebugCommandHandler::script( char* data, Entity::Player &player, boos } } - else if( subCommand == "reload" || subCommand == "rl" ) + else if( subCommand == "queuereload" || subCommand == "qrl" ) { if( subCommand == params ) player.sendDebug( "Command failed: requires name of script to reload" ); else { - g_scriptMgr.getNativeScriptHandler().reloadScript( params ); - player.sendDebug( "Attempting to reload script: " + params ); + g_scriptMgr.getNativeScriptHandler( ).queueScriptReload( params ); + player.sendDebug( "Queued script reload for 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 4ccf1c15..5e644f67 100644 --- a/src/servers/Server_Zone/Script/NativeScriptManager.cpp +++ b/src/servers/Server_Zone/Script/NativeScriptManager.cpp @@ -137,7 +137,7 @@ namespace Core { return m_loader.unloadScript( info ); } - void NativeScriptManager::reloadScript( const std::string &name ) + void NativeScriptManager::queueScriptReload( const std::string &name ) { auto info = m_loader.getScriptInfo( name ); if( !info ) diff --git a/src/servers/Server_Zone/Script/NativeScriptManager.h b/src/servers/Server_Zone/Script/NativeScriptManager.h index 8bd4ec41..43db0d76 100644 --- a/src/servers/Server_Zone/Script/NativeScriptManager.h +++ b/src/servers/Server_Zone/Script/NativeScriptManager.h @@ -42,7 +42,7 @@ namespace Scripting { bool loadScript( const std::string& path ); bool unloadScript( const std::string& name ); - void reloadScript( const std::string &name ); + void queueScriptReload( const std::string& name ); void findScripts( std::set< Core::Scripting::ScriptInfo* >& scripts, const std::string& search ); void processLoadQueue(); diff --git a/src/servers/Server_Zone/Script/ScriptManager.cpp b/src/servers/Server_Zone/Script/ScriptManager.cpp index cd7afa50..039c59be 100644 --- a/src/servers/Server_Zone/Script/ScriptManager.cpp +++ b/src/servers/Server_Zone/Script/ScriptManager.cpp @@ -91,7 +91,7 @@ void Core::Scripting::ScriptManager::watchDirectories() { g_log.debug( "Reloading changed script: " + path.stem().string() ); - m_nativeScriptManager->reloadScript( path.stem().string() ); + m_nativeScriptManager->queueScriptReload( path.stem( ).string( )); } else { @@ -103,14 +103,15 @@ void Core::Scripting::ScriptManager::watchDirectories() }); } -void Core::Scripting::ScriptManager::loadDir( std::string dirname, std::set& files, std::string ext ) +void Core::Scripting::ScriptManager::loadDir( const std::string& dirname, std::set &files, const std::string& ext ) { g_log.info( "ScriptEngine: loading scripts from " + dirname ); boost::filesystem::path targetDir( dirname ); - boost::filesystem::directory_iterator iter( targetDir ), eod; + boost::filesystem::directory_iterator iter( targetDir ); + boost::filesystem::directory_iterator eod; BOOST_FOREACH( boost::filesystem::path const& i, make_pair( iter, eod ) ) { diff --git a/src/servers/Server_Zone/Script/ScriptManager.h b/src/servers/Server_Zone/Script/ScriptManager.h index 945bd885..f87d434f 100644 --- a/src/servers/Server_Zone/Script/ScriptManager.h +++ b/src/servers/Server_Zone/Script/ScriptManager.h @@ -60,7 +60,7 @@ namespace Core bool onEventHandlerTradeReturn( Entity::Player& player, uint32_t eventId, uint16_t subEvent, uint16_t param, uint32_t catalogId ); - void loadDir( std::string dirname, std::set& files, std::string ext ); + void loadDir( const std::string& dirname, std::set &files, const std::string& ext ); NativeScriptManager& getNativeScriptHandler(); }; From b6730df029311dfa22ddb6d287016d901ae54cca Mon Sep 17 00:00:00 2001 From: GokuWeedLord Date: Thu, 14 Dec 2017 23:11:29 +1100 Subject: [PATCH 3/4] my spacebar died for my sins --- src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp index 60dd6967..dceb3432 100644 --- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp +++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp @@ -595,7 +595,7 @@ void Core::DebugCommandHandler::script( char* data, Entity::Player &player, boos player.sendDebug( "Command failed: requires name of script to reload" ); else { - g_scriptMgr.getNativeScriptHandler( ).queueScriptReload( params ); + g_scriptMgr.getNativeScriptHandler().queueScriptReload( params ); player.sendDebug( "Queued script reload for script: " + params ); } } From 052add56e2d986f35f2dde568f174060d1ed3557 Mon Sep 17 00:00:00 2001 From: GokuWeedLord Date: Fri, 15 Dec 2017 00:19:30 +1100 Subject: [PATCH 4/4] improve script reloading and fix openinggridania --- scripts/native/opening/OpeningGridania.cpp | 2 ++ .../Server_Zone/Script/NativeScriptManager.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/native/opening/OpeningGridania.cpp b/scripts/native/opening/OpeningGridania.cpp index 2a9e5e6b..5e4374c1 100644 --- a/scripts/native/opening/OpeningGridania.cpp +++ b/scripts/native/opening/OpeningGridania.cpp @@ -63,6 +63,8 @@ public: Scene00030( player ); } }; + + player.eventPlay( getId(), 40, 1, 2, 1, callback ); } /////////////////////////////// diff --git a/src/servers/Server_Zone/Script/NativeScriptManager.cpp b/src/servers/Server_Zone/Script/NativeScriptManager.cpp index 5e644f67..a28a823f 100644 --- a/src/servers/Server_Zone/Script/NativeScriptManager.cpp +++ b/src/servers/Server_Zone/Script/NativeScriptManager.cpp @@ -154,14 +154,24 @@ namespace Core { void NativeScriptManager::processLoadQueue() { + std::vector< std::string > deferredLoads; + while( !m_scriptLoadQueue.empty() ) { auto item = m_scriptLoadQueue.front(); - loadScript( item ); + // if it fails, we defer the loading to the next tick + if( !loadScript( item ) ) + deferredLoads.push_back( item ); m_scriptLoadQueue.pop(); } + + if( !deferredLoads.empty() ) + { + for( auto& item : deferredLoads ) + m_scriptLoadQueue.push( item ); + } } void NativeScriptManager::findScripts( std::set< Core::Scripting::ScriptInfo* >& scripts, const std::string& search )