1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-24 13:47:46 +00:00

Merge pull request #202 from GokuWeedLord/feature/nativescripting

automagically reload rebuilt scripts
This commit is contained in:
Mordred 2017-12-14 23:54:48 +01:00 committed by GitHub
commit 2da6b7a47b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 134 additions and 31 deletions

View file

@ -32,6 +32,7 @@ before_install:
- sudo add-apt-repository -y ppa:rexut/recoil - sudo add-apt-repository -y ppa:rexut/recoil
- sudo apt-get update - sudo apt-get update
- sudo apt-get install -y libboost1.63-dev libboost1.63-all-dev - sudo apt-get install -y libboost1.63-dev libboost1.63-all-dev
- sudo apt-get install -y libmysqlclient-dev
# Build steps # Build steps
script: script:

View file

@ -8,15 +8,16 @@
<DataPath>H:\\SteamLibrary\\steamapps\\common\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv</DataPath> <DataPath>H:\\SteamLibrary\\steamapps\\common\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv</DataPath>
<Scripts> <Scripts>
<!-- where compiled scripts are placed --> <!-- where compiled scripts are placed -->
<Path>./compiledscripts/</Path> <Path>./compiledscripts/</Path>
<CachePath>./cache/</CachePath> <CachePath>./cache/</CachePath>
<HotSwap> <HotSwap>
<Enabled>1</Enabled> <Enabled>1</Enabled>
<BuildDir>../cmake-build-debug/</BuildDir> <ScriptsDir>../scripts/native/</ScriptsDir>
<BuildCmd>cmake --build %1% --target %2%</BuildCmd> <BuildDir>../cmake-build-debug/</BuildDir>
</HotSwap> <BuildCmd>cmake --build %1% --target %2%</BuildCmd>
</HotSwap>
</Scripts> </Scripts>
<!-- Path of Chai script files --> <!-- Path of Chai script files -->
@ -28,13 +29,13 @@
<Username>root</Username> <Username>root</Username>
<Pass></Pass> <Pass></Pass>
<Database>sapphire</Database> <Database>sapphire</Database>
<SyncThreads>2</SyncThreads> <SyncThreads>2</SyncThreads>
<AsyncThreads>2</AsyncThreads> <AsyncThreads>2</AsyncThreads>
</Mysql> </Mysql>
</General> </General>
<Parameters> <Parameters>
<!-- Messages players see upon logging in - These *must* be smaller than 307 characters --> <!-- Messages players see upon logging in - These *must* be smaller than 307 characters -->
<MotDArray> <MotDArray>
<MotD>&lt;&lt;&lt;Welcome to Sapphire&gt;&gt;&gt;</MotD> <MotD>&lt;&lt;&lt;Welcome to Sapphire&gt;&gt;&gt;</MotD>
<MotD>This is a very good server</MotD> <MotD>This is a very good server</MotD>

View file

@ -5,6 +5,7 @@
#include <Forwards.h> #include <Forwards.h>
#include <Actor/Actor.h> #include <Actor/Actor.h>
#include <Actor/Player.h> #include <Actor/Player.h>
#include <Event/EventHelper.h>
#endif //SAPPHIRE_SCRIPTOBJECT_H #endif //SAPPHIRE_SCRIPTOBJECT_H

View file

@ -63,6 +63,8 @@ public:
Scene00030( player ); Scene00030( player );
} }
}; };
player.eventPlay( getId(), 40, 1, 2, 1, callback );
} }
/////////////////////////////// ///////////////////////////////

@ -1 +1 @@
Subproject commit 8a26ae78e37701a9b66e7200f1e0ad3387da17c3 Subproject commit f4d3c5b38d13a15efc42686c9bac768c2be28be1

View file

@ -589,15 +589,15 @@ 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 ) if( subCommand == params )
player.sendDebug( "Command failed: requires name of script to reload" ); player.sendDebug( "Command failed: requires name of script to reload" );
else else
if( g_scriptMgr.getNativeScriptHandler().reloadScript( params ) ) {
player.sendDebug( "Reloaded '" + params + "' successfully" ); g_scriptMgr.getNativeScriptHandler().queueScriptReload( params );
else player.sendDebug( "Queued script reload for script: " + params );
player.sendDebug( "Failed to reload '" + params + "'" ); }
} }
else if( subCommand == "build" || subCommand == "b" ) else if( subCommand == "build" || subCommand == "b" )
{ {

View file

@ -137,19 +137,41 @@ namespace Core {
return m_loader.unloadScript( info ); return m_loader.unloadScript( info );
} }
bool NativeScriptManager::reloadScript( const std::string& name ) void NativeScriptManager::queueScriptReload( const std::string &name )
{ {
auto info = m_loader.getScriptInfo( name ); auto info = m_loader.getScriptInfo( name );
if( !info ) if( !info )
return false; return;
// backup actual lib path // backup actual lib path
std::string libPath( info->library_path ); std::string libPath( info->library_path );
if( !unloadScript( info ) ) if( !unloadScript( info ) )
return false; return;
return loadScript( libPath ); m_scriptLoadQueue.push( libPath );
}
void NativeScriptManager::processLoadQueue()
{
std::vector< std::string > deferredLoads;
while( !m_scriptLoadQueue.empty() )
{
auto item = m_scriptLoadQueue.front();
// 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 ) void NativeScriptManager::findScripts( std::set< Core::Scripting::ScriptInfo* >& scripts, const std::string& search )
@ -157,6 +179,11 @@ namespace Core {
return m_loader.findScripts( scripts, search ); return m_loader.findScripts( scripts, search );
} }
bool NativeScriptManager::isModuleLoaded( const std::string &name )
{
return m_loader.isModuleLoaded( name );
}
boost::shared_ptr< NativeScriptManager > createNativeScriptMgr() boost::shared_ptr< NativeScriptManager > createNativeScriptMgr()

View file

@ -3,6 +3,7 @@
#include <unordered_map> #include <unordered_map>
#include <set> #include <set>
#include <queue>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
@ -26,6 +27,8 @@ namespace Scripting {
ScriptLoader m_loader; ScriptLoader m_loader;
std::queue< std::string > m_scriptLoadQueue;
bool unloadScript( ScriptInfo* info ); bool unloadScript( ScriptInfo* info );
public: public:
@ -39,10 +42,13 @@ namespace Scripting {
bool loadScript( const std::string& path ); bool loadScript( const std::string& path );
bool unloadScript( const std::string& name ); bool unloadScript( const std::string& name );
bool reloadScript( const std::string& name ); void queueScriptReload( const std::string& name );
void findScripts( std::set< Core::Scripting::ScriptInfo* >& scripts, const std::string& search ); void findScripts( std::set< Core::Scripting::ScriptInfo* >& scripts, const std::string& search );
void processLoadQueue();
const std::string getModuleExtension(); const std::string getModuleExtension();
bool isModuleLoaded( const std::string& name );
template< typename key, typename val > template< typename key, typename val >
bool removeValueFromMap( ScriptObject* ptr, std::unordered_map< key, val >& map ) bool removeValueFromMap( ScriptObject* ptr, std::unordered_map< key, val >& map )

View file

@ -62,12 +62,17 @@ Core::Scripting::ScriptInfo* Core::Scripting::ScriptLoader::loadModule( const st
fs::create_directories( cacheDir ); fs::create_directories( cacheDir );
fs::path dest( cacheDir /= f.filename().string() ); 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 #ifdef _WIN32
ModuleHandle handle = LoadLibrary( dest.string().c_str() ); ModuleHandle handle = LoadLibrary( dest.string().c_str() );
@ -82,7 +87,7 @@ Core::Scripting::ScriptInfo* Core::Scripting::ScriptLoader::loadModule( const st
return nullptr; 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; auto info = new ScriptInfo;
info->handle = handle; info->handle = handle;

View file

@ -21,18 +21,28 @@
#include <Server_Common/Config/XMLConfig.h> #include <Server_Common/Config/XMLConfig.h>
// enable the ambiguity fix for every platform to avoid #define nonsense
#define WIN_AMBIGUITY_FIX
#include <libraries/external/watchdog/Watchdog.h>
extern Core::Logger g_log; extern Core::Logger g_log;
extern Core::Data::ExdData g_exdData; extern Core::Data::ExdData g_exdData;
extern Core::ServerZone g_serverZone; extern Core::ServerZone g_serverZone;
Core::Scripting::ScriptManager::ScriptManager() Core::Scripting::ScriptManager::ScriptManager() :
m_firstScriptChangeNotificiation( false )
{ {
m_nativeScriptManager = createNativeScriptMgr(); m_nativeScriptManager = createNativeScriptMgr();
} }
Core::Scripting::ScriptManager::~ScriptManager() Core::Scripting::ScriptManager::~ScriptManager()
{ {
Watchdog::unwatchAll();
}
void Core::Scripting::ScriptManager::update()
{
m_nativeScriptManager->processLoadQueue();
} }
bool Core::Scripting::ScriptManager::init() bool Core::Scripting::ScriptManager::init()
@ -42,24 +52,66 @@ bool Core::Scripting::ScriptManager::init()
loadDir( g_serverZone.getConfig()->getValue< std::string >( "Settings.General.Scripts.Path", "./compiledscripts/" ), loadDir( g_serverZone.getConfig()->getValue< std::string >( "Settings.General.Scripts.Path", "./compiledscripts/" ),
files, m_nativeScriptManager->getModuleExtension() ); files, m_nativeScriptManager->getModuleExtension() );
uint32_t scriptsFound = 0;
uint32_t scriptsLoaded = 0;
for( auto itr = files.begin(); itr != files.end(); ++itr ) for( auto itr = files.begin(); itr != files.end(); ++itr )
{ {
auto& path = *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; return true;
} }
void Core::Scripting::ScriptManager::loadDir( std::string dirname, std::set<std::string>& files, std::string ext ) 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->queueScriptReload( path.stem( ).string( ));
}
else
{
g_log.debug( "Loading new script: " + path.stem().string() );
m_nativeScriptManager->loadScript( path.string() );
}
}
});
}
void Core::Scripting::ScriptManager::loadDir( const std::string& dirname, std::set<std::string> &files, const std::string& ext )
{ {
g_log.info( "ScriptEngine: loading scripts from " + dirname ); g_log.info( "ScriptEngine: loading scripts from " + dirname );
boost::filesystem::path targetDir( dirname ); boost::filesystem::path targetDir( dirname );
boost::filesystem::recursive_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 ) ) BOOST_FOREACH( boost::filesystem::path const& i, make_pair( iter, eod ) )
{ {

View file

@ -22,6 +22,8 @@ namespace Core
std::function< std::string( Entity::Player& ) > m_onFirstEnterWorld; std::function< std::string( Entity::Player& ) > m_onFirstEnterWorld;
// auto fn = m_pChaiHandler->eval< std::function<const std::string( Entity::Player ) > >( "onFirstEnterWorld" ); // auto fn = m_pChaiHandler->eval< std::function<const std::string( Entity::Player ) > >( "onFirstEnterWorld" );
bool m_firstScriptChangeNotificiation;
public: public:
ScriptManager(); ScriptManager();
~ScriptManager(); ~ScriptManager();
@ -29,6 +31,10 @@ namespace Core
bool init(); bool init();
void reload(); void reload();
void update();
void watchDirectories();
void onPlayerFirstEnterWorld( Entity::Player& player ); void onPlayerFirstEnterWorld( Entity::Player& player );
static bool registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId, uint32_t bnpcNameId, uint32_t modelId, std::string aiName ); static bool registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId, uint32_t bnpcNameId, uint32_t modelId, std::string aiName );
@ -54,7 +60,7 @@ namespace Core
bool onEventHandlerTradeReturn( Entity::Player& player, uint32_t eventId, uint16_t subEvent, uint16_t param, uint32_t catalogId ); bool onEventHandlerTradeReturn( Entity::Player& player, uint32_t eventId, uint16_t subEvent, uint16_t param, uint32_t catalogId );
void loadDir( std::string dirname, std::set<std::string>& files, std::string ext ); void loadDir( const std::string& dirname, std::set<std::string> &files, const std::string& ext );
NativeScriptManager& getNativeScriptHandler(); NativeScriptManager& getNativeScriptHandler();
}; };

View file

@ -260,6 +260,8 @@ void Core::ServerZone::mainLoop()
g_zoneMgr.updateZones(); g_zoneMgr.updateZones();
g_scriptMgr.update();
auto currTime = static_cast< uint32_t >( time( nullptr ) ); auto currTime = static_cast< uint32_t >( time( nullptr ) );
lock_guard< std::mutex > lock( this->m_sessionMutex ); lock_guard< std::mutex > lock( this->m_sessionMutex );