mirror of https://github.com/OpenRCT2/OpenRCT2.git
Implement lifetime logic of transient plugins
This commit is contained in:
parent
6fea0b5025
commit
dbf83f018c
|
@ -502,14 +502,14 @@ void game_load_init()
|
||||||
void game_load_scripts()
|
void game_load_scripts()
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
GetContext()->GetScriptEngine().LoadPlugins();
|
GetContext()->GetScriptEngine().LoadTransientPlugins();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_unload_scripts()
|
void game_unload_scripts()
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
GetContext()->GetScriptEngine().UnloadPlugins();
|
GetContext()->GetScriptEngine().UnloadTransientPlugins();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -436,10 +436,10 @@ void ScriptEngine::Initialise()
|
||||||
dukglue_register_global(ctx, std::make_shared<ScScenario>(), "scenario");
|
dukglue_register_global(ctx, std::make_shared<ScScenario>(), "scenario");
|
||||||
|
|
||||||
_initialised = true;
|
_initialised = true;
|
||||||
_pluginsLoaded = false;
|
_transientPluginsEnabled = false;
|
||||||
_pluginsStarted = false;
|
_transientPluginsStarted = false;
|
||||||
|
|
||||||
InitSharedStorage();
|
LoadSharedStorage();
|
||||||
ClearParkStorage();
|
ClearParkStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +477,7 @@ void ScriptEngine::RefreshPlugins()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn on hot reload if not already enabled
|
// Turn on hot reload if not already enabled
|
||||||
if (!_hotReloading && gConfigPlugin.enable_hot_reloading && network_get_mode() == NETWORK_MODE_NONE)
|
if (!_hotReloadingInitialised && gConfigPlugin.enable_hot_reloading && network_get_mode() == NETWORK_MODE_NONE)
|
||||||
{
|
{
|
||||||
SetupHotReloading();
|
SetupHotReloading();
|
||||||
}
|
}
|
||||||
|
@ -493,8 +493,8 @@ std::vector<std::string> ScriptEngine::GetPluginFiles() const
|
||||||
auto base = _env.GetDirectoryPath(DIRBASE::USER, DIRID::PLUGIN);
|
auto base = _env.GetDirectoryPath(DIRBASE::USER, DIRID::PLUGIN);
|
||||||
if (Path::DirectoryExists(base))
|
if (Path::DirectoryExists(base))
|
||||||
{
|
{
|
||||||
auto pattern = Path::Combine(base, "*.js");
|
auto pattern = Path::Combine(base, u8"*.js");
|
||||||
auto scanner = std::unique_ptr<IFileScanner>(Path::ScanDirectory(pattern, true));
|
auto scanner = Path::ScanDirectory(pattern, true);
|
||||||
while (scanner->Next())
|
while (scanner->Next())
|
||||||
{
|
{
|
||||||
auto path = std::string(scanner->GetPath());
|
auto path = std::string(scanner->GetPath());
|
||||||
|
@ -558,6 +558,8 @@ void ScriptEngine::RegisterPlugin(std::string_view path)
|
||||||
|
|
||||||
void ScriptEngine::StartIntransientPlugins()
|
void ScriptEngine::StartIntransientPlugins()
|
||||||
{
|
{
|
||||||
|
LoadSharedStorage();
|
||||||
|
|
||||||
for (auto& plugin : _plugins)
|
for (auto& plugin : _plugins)
|
||||||
{
|
{
|
||||||
if (!plugin->HasStarted() && !plugin->IsTransient())
|
if (!plugin->HasStarted() && !plugin->IsTransient())
|
||||||
|
@ -586,38 +588,9 @@ void ScriptEngine::StopUnloadRegisterAllPlugins()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::LoadPlugins()
|
void ScriptEngine::LoadTransientPlugins()
|
||||||
{
|
{
|
||||||
if (!_initialised)
|
_transientPluginsEnabled = true;
|
||||||
{
|
|
||||||
Initialise();
|
|
||||||
}
|
|
||||||
if (_pluginsLoaded)
|
|
||||||
{
|
|
||||||
UnloadPlugins();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto base = _env.GetDirectoryPath(DIRBASE::USER, DIRID::PLUGIN);
|
|
||||||
if (Path::DirectoryExists(base))
|
|
||||||
{
|
|
||||||
auto pattern = Path::Combine(base, u8"*.js");
|
|
||||||
auto scanner = Path::ScanDirectory(pattern, true);
|
|
||||||
while (scanner->Next())
|
|
||||||
{
|
|
||||||
auto path = std::string(scanner->GetPath());
|
|
||||||
if (ShouldLoadScript(path))
|
|
||||||
{
|
|
||||||
LoadPlugin(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gConfigPlugin.enable_hot_reloading && network_get_mode() == NETWORK_MODE_NONE)
|
|
||||||
{
|
|
||||||
SetupHotReloading();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_pluginsLoaded = true;
|
|
||||||
_pluginsStarted = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::LoadPlugin(const std::string& path)
|
void ScriptEngine::LoadPlugin(const std::string& path)
|
||||||
|
@ -705,7 +678,7 @@ void ScriptEngine::SetupHotReloading()
|
||||||
std::lock_guard<std::mutex> guard(_changedPluginFilesMutex);
|
std::lock_guard<std::mutex> guard(_changedPluginFilesMutex);
|
||||||
_changedPluginFiles.emplace(path);
|
_changedPluginFiles.emplace(path);
|
||||||
};
|
};
|
||||||
_hotReloading = true;
|
_hotReloadingInitialised = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
|
@ -714,6 +687,19 @@ void ScriptEngine::SetupHotReloading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::DoAutoReloadPluginCheck()
|
||||||
|
{
|
||||||
|
if (_hotReloadingInitialised)
|
||||||
|
{
|
||||||
|
auto tick = Platform::GetTicks();
|
||||||
|
if (tick - _lastHotReloadCheckTick > 1000)
|
||||||
|
{
|
||||||
|
AutoReloadPlugins();
|
||||||
|
_lastHotReloadCheckTick = tick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptEngine::AutoReloadPlugins()
|
void ScriptEngine::AutoReloadPlugins()
|
||||||
{
|
{
|
||||||
if (_changedPluginFiles.size() > 0)
|
if (_changedPluginFiles.size() > 0)
|
||||||
|
@ -746,39 +732,54 @@ void ScriptEngine::AutoReloadPlugins()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::UnloadPlugins()
|
void ScriptEngine::UnloadTransientPlugins()
|
||||||
{
|
{
|
||||||
StopPlugins();
|
// Stop them all first
|
||||||
for (auto& plugin : _plugins)
|
for (auto& plugin : _plugins)
|
||||||
{
|
{
|
||||||
LogPluginInfo(plugin, "Unloaded");
|
if (plugin->IsTransient())
|
||||||
}
|
|
||||||
_plugins.clear();
|
|
||||||
_pluginsLoaded = false;
|
|
||||||
_pluginsStarted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptEngine::StartPlugins()
|
|
||||||
{
|
|
||||||
LoadSharedStorage();
|
|
||||||
|
|
||||||
for (auto& plugin : _plugins)
|
|
||||||
{
|
|
||||||
if (!plugin->HasStarted() && ShouldStartPlugin(plugin))
|
|
||||||
{
|
{
|
||||||
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
|
if (plugin->HasStarted())
|
||||||
try
|
|
||||||
{
|
{
|
||||||
LogPluginInfo(plugin, "Started");
|
StopPlugin(plugin);
|
||||||
plugin->Start();
|
LogPluginInfo(plugin, "Stopped");
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
_console.WriteLineError(e.what());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_pluginsStarted = true;
|
|
||||||
|
// Now unload them
|
||||||
|
for (auto& plugin : _plugins)
|
||||||
|
{
|
||||||
|
UnloadPlugin(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
_transientPluginsEnabled = false;
|
||||||
|
_transientPluginsStarted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::StartTransientPlugins()
|
||||||
|
{
|
||||||
|
LoadSharedStorage();
|
||||||
|
|
||||||
|
// Load transient plugins
|
||||||
|
for (auto& plugin : _plugins)
|
||||||
|
{
|
||||||
|
if (plugin->IsTransient() && !plugin->IsLoaded() && ShouldStartPlugin(plugin))
|
||||||
|
{
|
||||||
|
LoadPlugin(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start transient plugins
|
||||||
|
for (auto& plugin : _plugins)
|
||||||
|
{
|
||||||
|
if (plugin->IsTransient() && plugin->IsLoaded() && !plugin->HasStarted())
|
||||||
|
{
|
||||||
|
StartPlugin(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_transientPluginsStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScriptEngine::ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin)
|
bool ScriptEngine::ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin)
|
||||||
|
@ -797,19 +798,6 @@ bool ScriptEngine::ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::StopPlugins()
|
|
||||||
{
|
|
||||||
for (auto& plugin : _plugins)
|
|
||||||
{
|
|
||||||
if (plugin->HasStarted())
|
|
||||||
{
|
|
||||||
StopPlugin(plugin);
|
|
||||||
LogPluginInfo(plugin, "Stopped");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_pluginsStarted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptEngine::Tick()
|
void ScriptEngine::Tick()
|
||||||
{
|
{
|
||||||
PROFILED_FUNCTION();
|
PROFILED_FUNCTION();
|
||||||
|
@ -820,26 +808,15 @@ void ScriptEngine::Tick()
|
||||||
RefreshPlugins();
|
RefreshPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pluginsLoaded)
|
if (_transientPluginsEnabled && !_transientPluginsStarted)
|
||||||
{
|
{
|
||||||
if (!_pluginsStarted)
|
StartTransientPlugins();
|
||||||
{
|
|
||||||
StartPlugins();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto tick = Platform::GetTicks();
|
|
||||||
if (tick - _lastHotReloadCheckTick > 1000)
|
|
||||||
{
|
|
||||||
AutoReloadPlugins();
|
|
||||||
_lastHotReloadCheckTick = tick;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateIntervals();
|
UpdateIntervals();
|
||||||
UpdateSockets();
|
UpdateSockets();
|
||||||
ProcessREPL();
|
ProcessREPL();
|
||||||
|
DoAutoReloadPluginCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::ProcessREPL()
|
void ScriptEngine::ProcessREPL()
|
||||||
|
|
|
@ -145,9 +145,9 @@ namespace OpenRCT2::Scripting
|
||||||
IPlatformEnvironment& _env;
|
IPlatformEnvironment& _env;
|
||||||
DukContext _context;
|
DukContext _context;
|
||||||
bool _initialised{};
|
bool _initialised{};
|
||||||
bool _hotReloading{};
|
bool _hotReloadingInitialised{};
|
||||||
bool _pluginsLoaded{};
|
bool _transientPluginsEnabled{};
|
||||||
bool _pluginsStarted{};
|
bool _transientPluginsStarted{};
|
||||||
std::queue<std::tuple<std::promise<void>, std::string>> _evalQueue;
|
std::queue<std::tuple<std::promise<void>, std::string>> _evalQueue;
|
||||||
std::vector<std::shared_ptr<Plugin>> _plugins;
|
std::vector<std::shared_ptr<Plugin>> _plugins;
|
||||||
uint32_t _lastHotReloadCheckTick{};
|
uint32_t _lastHotReloadCheckTick{};
|
||||||
|
@ -212,6 +212,8 @@ namespace OpenRCT2::Scripting
|
||||||
|
|
||||||
void LoadPlugins();
|
void LoadPlugins();
|
||||||
void UnloadPlugins();
|
void UnloadPlugins();
|
||||||
|
void LoadTransientPlugins();
|
||||||
|
void UnloadTransientPlugins();
|
||||||
void Tick();
|
void Tick();
|
||||||
std::future<void> Eval(const std::string& s);
|
std::future<void> Eval(const std::string& s);
|
||||||
DukValue ExecutePluginCall(
|
DukValue ExecutePluginCall(
|
||||||
|
@ -253,8 +255,7 @@ namespace OpenRCT2::Scripting
|
||||||
void UnregisterPlugin(std::string_view path);
|
void UnregisterPlugin(std::string_view path);
|
||||||
void RegisterPlugin(std::string_view path);
|
void RegisterPlugin(std::string_view path);
|
||||||
void StartIntransientPlugins();
|
void StartIntransientPlugins();
|
||||||
void StartPlugins();
|
void StartTransientPlugins();
|
||||||
void StopPlugins();
|
|
||||||
void LoadPlugin(const std::string& path);
|
void LoadPlugin(const std::string& path);
|
||||||
void LoadPlugin(std::shared_ptr<Plugin>& plugin);
|
void LoadPlugin(std::shared_ptr<Plugin>& plugin);
|
||||||
void UnloadPlugin(std::shared_ptr<Plugin>& plugin);
|
void UnloadPlugin(std::shared_ptr<Plugin>& plugin);
|
||||||
|
@ -264,6 +265,7 @@ namespace OpenRCT2::Scripting
|
||||||
static bool ShouldLoadScript(std::string_view path);
|
static bool ShouldLoadScript(std::string_view path);
|
||||||
bool ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin);
|
bool ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin);
|
||||||
void SetupHotReloading();
|
void SetupHotReloading();
|
||||||
|
void DoAutoReloadPluginCheck();
|
||||||
void AutoReloadPlugins();
|
void AutoReloadPlugins();
|
||||||
void ProcessREPL();
|
void ProcessREPL();
|
||||||
void RemoveCustomGameActions(const std::shared_ptr<Plugin>& plugin);
|
void RemoveCustomGameActions(const std::shared_ptr<Plugin>& plugin);
|
||||||
|
|
Loading…
Reference in New Issue