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()
|
||||
{
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
GetContext()->GetScriptEngine().LoadPlugins();
|
||||
GetContext()->GetScriptEngine().LoadTransientPlugins();
|
||||
#endif
|
||||
}
|
||||
|
||||
void game_unload_scripts()
|
||||
{
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
GetContext()->GetScriptEngine().UnloadPlugins();
|
||||
GetContext()->GetScriptEngine().UnloadTransientPlugins();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -436,10 +436,10 @@ void ScriptEngine::Initialise()
|
|||
dukglue_register_global(ctx, std::make_shared<ScScenario>(), "scenario");
|
||||
|
||||
_initialised = true;
|
||||
_pluginsLoaded = false;
|
||||
_pluginsStarted = false;
|
||||
_transientPluginsEnabled = false;
|
||||
_transientPluginsStarted = false;
|
||||
|
||||
InitSharedStorage();
|
||||
LoadSharedStorage();
|
||||
ClearParkStorage();
|
||||
}
|
||||
|
||||
|
@ -477,7 +477,7 @@ void ScriptEngine::RefreshPlugins()
|
|||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
@ -493,8 +493,8 @@ std::vector<std::string> ScriptEngine::GetPluginFiles() const
|
|||
auto base = _env.GetDirectoryPath(DIRBASE::USER, DIRID::PLUGIN);
|
||||
if (Path::DirectoryExists(base))
|
||||
{
|
||||
auto pattern = Path::Combine(base, "*.js");
|
||||
auto scanner = std::unique_ptr<IFileScanner>(Path::ScanDirectory(pattern, true));
|
||||
auto pattern = Path::Combine(base, u8"*.js");
|
||||
auto scanner = Path::ScanDirectory(pattern, true);
|
||||
while (scanner->Next())
|
||||
{
|
||||
auto path = std::string(scanner->GetPath());
|
||||
|
@ -558,6 +558,8 @@ void ScriptEngine::RegisterPlugin(std::string_view path)
|
|||
|
||||
void ScriptEngine::StartIntransientPlugins()
|
||||
{
|
||||
LoadSharedStorage();
|
||||
|
||||
for (auto& plugin : _plugins)
|
||||
{
|
||||
if (!plugin->HasStarted() && !plugin->IsTransient())
|
||||
|
@ -586,38 +588,9 @@ void ScriptEngine::StopUnloadRegisterAllPlugins()
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::LoadPlugins()
|
||||
void ScriptEngine::LoadTransientPlugins()
|
||||
{
|
||||
if (!_initialised)
|
||||
{
|
||||
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;
|
||||
_transientPluginsEnabled = true;
|
||||
}
|
||||
|
||||
void ScriptEngine::LoadPlugin(const std::string& path)
|
||||
|
@ -705,7 +678,7 @@ void ScriptEngine::SetupHotReloading()
|
|||
std::lock_guard<std::mutex> guard(_changedPluginFilesMutex);
|
||||
_changedPluginFiles.emplace(path);
|
||||
};
|
||||
_hotReloading = true;
|
||||
_hotReloadingInitialised = true;
|
||||
}
|
||||
}
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
LogPluginInfo(plugin, "Unloaded");
|
||||
}
|
||||
_plugins.clear();
|
||||
_pluginsLoaded = false;
|
||||
_pluginsStarted = false;
|
||||
}
|
||||
|
||||
void ScriptEngine::StartPlugins()
|
||||
{
|
||||
LoadSharedStorage();
|
||||
|
||||
for (auto& plugin : _plugins)
|
||||
{
|
||||
if (!plugin->HasStarted() && ShouldStartPlugin(plugin))
|
||||
if (plugin->IsTransient())
|
||||
{
|
||||
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
|
||||
try
|
||||
if (plugin->HasStarted())
|
||||
{
|
||||
LogPluginInfo(plugin, "Started");
|
||||
plugin->Start();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
_console.WriteLineError(e.what());
|
||||
StopPlugin(plugin);
|
||||
LogPluginInfo(plugin, "Stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
_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)
|
||||
|
@ -797,19 +798,6 @@ bool ScriptEngine::ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin)
|
|||
return true;
|
||||
}
|
||||
|
||||
void ScriptEngine::StopPlugins()
|
||||
{
|
||||
for (auto& plugin : _plugins)
|
||||
{
|
||||
if (plugin->HasStarted())
|
||||
{
|
||||
StopPlugin(plugin);
|
||||
LogPluginInfo(plugin, "Stopped");
|
||||
}
|
||||
}
|
||||
_pluginsStarted = false;
|
||||
}
|
||||
|
||||
void ScriptEngine::Tick()
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
|
@ -820,26 +808,15 @@ void ScriptEngine::Tick()
|
|||
RefreshPlugins();
|
||||
}
|
||||
|
||||
if (_pluginsLoaded)
|
||||
if (_transientPluginsEnabled && !_transientPluginsStarted)
|
||||
{
|
||||
if (!_pluginsStarted)
|
||||
{
|
||||
StartPlugins();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tick = Platform::GetTicks();
|
||||
if (tick - _lastHotReloadCheckTick > 1000)
|
||||
{
|
||||
AutoReloadPlugins();
|
||||
_lastHotReloadCheckTick = tick;
|
||||
}
|
||||
}
|
||||
StartTransientPlugins();
|
||||
}
|
||||
|
||||
UpdateIntervals();
|
||||
UpdateSockets();
|
||||
ProcessREPL();
|
||||
DoAutoReloadPluginCheck();
|
||||
}
|
||||
|
||||
void ScriptEngine::ProcessREPL()
|
||||
|
|
|
@ -145,9 +145,9 @@ namespace OpenRCT2::Scripting
|
|||
IPlatformEnvironment& _env;
|
||||
DukContext _context;
|
||||
bool _initialised{};
|
||||
bool _hotReloading{};
|
||||
bool _pluginsLoaded{};
|
||||
bool _pluginsStarted{};
|
||||
bool _hotReloadingInitialised{};
|
||||
bool _transientPluginsEnabled{};
|
||||
bool _transientPluginsStarted{};
|
||||
std::queue<std::tuple<std::promise<void>, std::string>> _evalQueue;
|
||||
std::vector<std::shared_ptr<Plugin>> _plugins;
|
||||
uint32_t _lastHotReloadCheckTick{};
|
||||
|
@ -212,6 +212,8 @@ namespace OpenRCT2::Scripting
|
|||
|
||||
void LoadPlugins();
|
||||
void UnloadPlugins();
|
||||
void LoadTransientPlugins();
|
||||
void UnloadTransientPlugins();
|
||||
void Tick();
|
||||
std::future<void> Eval(const std::string& s);
|
||||
DukValue ExecutePluginCall(
|
||||
|
@ -253,8 +255,7 @@ namespace OpenRCT2::Scripting
|
|||
void UnregisterPlugin(std::string_view path);
|
||||
void RegisterPlugin(std::string_view path);
|
||||
void StartIntransientPlugins();
|
||||
void StartPlugins();
|
||||
void StopPlugins();
|
||||
void StartTransientPlugins();
|
||||
void LoadPlugin(const std::string& path);
|
||||
void LoadPlugin(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);
|
||||
bool ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin);
|
||||
void SetupHotReloading();
|
||||
void DoAutoReloadPluginCheck();
|
||||
void AutoReloadPlugins();
|
||||
void ProcessREPL();
|
||||
void RemoveCustomGameActions(const std::shared_ptr<Plugin>& plugin);
|
||||
|
|
Loading…
Reference in New Issue