1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 19:13:07 +01:00

Close plugin's windows gracefully when stopped

When a plugin is stopped, close all windows created by that plugin.
Ensure the close event on the window can not open a new window if the plugin is being stopped.
This commit is contained in:
Ted John
2022-02-15 20:26:37 +00:00
parent 105009f3f8
commit 007a33404e
7 changed files with 63 additions and 17 deletions

View File

@@ -9,16 +9,17 @@
#ifdef ENABLE_SCRIPTING
# include "../UiContext.h"
# include "../interface/Dropdown.h"
# include "../interface/Widget.h"
# include "../scripting/ScGraphicsContext.hpp"
# include "../scripting/ScWidget.hpp"
# include "../windows/Window.h"
# include "CustomListView.h"
# include "ScUi.hpp"
# include "ScWindow.hpp"
# include <limits>
# include <openrct2-ui/interface/Widget.h>
# include <openrct2-ui/windows/Window.h>
# include <openrct2/drawing/Drawing.h>
# include <openrct2/interface/Window.h>
# include <openrct2/localisation/Formatter.h>
@@ -1433,6 +1434,29 @@ namespace OpenRCT2::Ui::Windows
}
}
void CloseWindowsOwnedByPlugin(std::shared_ptr<Plugin> plugin)
{
// Get all the windows that need closing
std::vector<std::shared_ptr<rct_window>> customWindows;
for (const auto& window : g_window_list)
{
if (window->classification == WC_CUSTOM)
{
auto customWindow = reinterpret_cast<CustomWindow*>(window.get());
auto customInfo = reinterpret_cast<CustomWindowInfo*>(customWindow->custom_info);
if (customInfo != nullptr && customInfo->Owner == plugin)
{
customWindows.push_back(window);
}
}
}
for (auto& window : customWindows)
{
window_close(window.get());
}
}
} // namespace OpenRCT2::Ui::Windows
#endif

View File

@@ -36,6 +36,7 @@ namespace OpenRCT2::Ui::Windows
CustomListView* GetCustomListView(rct_window* w, rct_widgetindex widgetIndex);
int32_t GetWidgetMaxLength(rct_window* w, rct_widgetindex widgetIndex);
void SetWidgetMaxLength(rct_window* w, rct_widgetindex widgetIndex, int32_t value);
void CloseWindowsOwnedByPlugin(std::shared_ptr<Plugin> plugin);
} // namespace OpenRCT2::Ui::Windows
#endif

View File

@@ -162,6 +162,8 @@ namespace OpenRCT2::Scripting
auto& execInfo = _scriptEngine.GetExecInfo();
auto owner = execInfo.GetCurrentPlugin();
owner->ThrowIfStopping();
std::shared_ptr<ScWindow> scWindow = nullptr;
auto w = window_custom_open(owner, desc);
if (w != nullptr)

View File

@@ -56,6 +56,8 @@ void UiScriptExtensions::Extend(ScriptEngine& scriptEngine)
ScWindow::Register(ctx);
InitialiseCustomMenuItems(scriptEngine);
scriptEngine.SubscribeToPluginStoppedEvent(
[](std::shared_ptr<Plugin> plugin) -> void { CloseWindowsOwnedByPlugin(plugin); });
}
std::shared_ptr<ScWindow> ScWidget::window_get() const

View File

@@ -96,11 +96,25 @@ void Plugin::Start()
_hasStarted = true;
}
void Plugin::Stop()
void Plugin::StopBegin()
{
_isStopping = true;
}
void Plugin::StopEnd()
{
_isStopping = false;
_hasStarted = false;
}
void Plugin::ThrowIfStopping() const
{
if (IsStopping())
{
duk_error(_context, DUK_ERR_ERROR, "Plugin is stopping.");
}
}
void Plugin::LoadCodeFromFile()
{
_code = File::ReadAllText(_path);

View File

@@ -54,6 +54,7 @@ namespace OpenRCT2::Scripting
PluginMetadata _metadata{};
std::string _code;
bool _hasStarted{};
bool _isStopping{};
public:
std::string GetPath() const
@@ -81,6 +82,11 @@ namespace OpenRCT2::Scripting
return _hasStarted;
}
bool IsStopping() const
{
return _isStopping;
}
int32_t GetTargetAPIVersion() const;
Plugin() = default;
@@ -91,7 +97,10 @@ namespace OpenRCT2::Scripting
void SetCode(std::string_view code);
void Load();
void Start();
void Stop();
void StopBegin();
void StopEnd();
void ThrowIfStopping() const;
private:
void LoadCodeFromFile();

View File

@@ -509,24 +509,18 @@ void ScriptEngine::StopPlugin(std::shared_ptr<Plugin> plugin)
{
if (plugin->HasStarted())
{
RemoveCustomGameActions(plugin);
RemoveIntervals(plugin);
RemoveSockets(plugin);
_hookEngine.UnsubscribeAll(plugin);
plugin->StopBegin();
for (const auto& callback : _pluginStoppedSubscriptions)
{
callback(plugin);
}
RemoveCustomGameActions(plugin);
RemoveIntervals(plugin);
RemoveSockets(plugin);
_hookEngine.UnsubscribeAll(plugin);
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
try
{
plugin->Stop();
}
catch (const std::exception& e)
{
_console.WriteLineError(e.what());
}
plugin->StopEnd();
}
}