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:
commit
2da6b7a47b
12 changed files with 134 additions and 31 deletions
|
@ -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:
|
||||||
|
|
|
@ -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><<<Welcome to Sapphire>>></MotD>
|
<MotD><<<Welcome to Sapphire>>></MotD>
|
||||||
<MotD>This is a very good server</MotD>
|
<MotD>This is a very good server</MotD>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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" )
|
||||||
{
|
{
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
Loading…
Add table
Reference in a new issue