From 4d5e7f19ca015266db40be91a880138309e42662 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 29 Feb 2020 13:18:31 +0000 Subject: [PATCH] Implement surface style API and improve plugin calling --- distribution/openrct2.d.ts | 5 ++- src/openrct2-ui/scripting/CustomMenu.h | 8 +---- src/openrct2-ui/scripting/CustomWindow.cpp | 17 ++-------- src/openrct2/scripting/HookEngine.cpp | 37 +++++++-------------- src/openrct2/scripting/HookEngine.h | 14 ++++---- src/openrct2/scripting/ScTile.hpp | 38 +++++++++++++++++----- src/openrct2/scripting/ScriptEngine.cpp | 30 ++++++++++++++++- src/openrct2/scripting/ScriptEngine.h | 3 ++ 8 files changed, 86 insertions(+), 66 deletions(-) diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 585e5dbd28..c24f568639 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -155,9 +155,8 @@ declare global { interface BaseTileElement { type: TileElementType; - baseHeight: number; - clearanceHeight: number; - broken: boolean; + baseZ: number; + clearanceZ: number; } // interface TileElement extends BaseTileElement { diff --git a/src/openrct2-ui/scripting/CustomMenu.h b/src/openrct2-ui/scripting/CustomMenu.h index 05300ac894..5b754a34bb 100644 --- a/src/openrct2-ui/scripting/CustomMenu.h +++ b/src/openrct2-ui/scripting/CustomMenu.h @@ -37,13 +37,7 @@ namespace OpenRCT2::Scripting void Invoke() const { auto& scriptEngine = GetContext()->GetScriptEngine(); - auto& execInfo = scriptEngine.GetExecInfo(); - auto ctx = scriptEngine.GetContext(); - - ScriptExecutionInfo::PluginScope scope(execInfo, Owner, false); - Callback.push(); - duk_pcall(ctx, 0); - duk_pop(ctx); + scriptEngine.ExecutePluginCall(Owner, Callback, {}, false); } }; diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp index 6a6f3e929f..d5299bc9f2 100644 --- a/src/openrct2-ui/scripting/CustomWindow.cpp +++ b/src/openrct2-ui/scripting/CustomWindow.cpp @@ -708,21 +708,8 @@ namespace OpenRCT2::Ui::Windows static void InvokeEventHandler(std::shared_ptr owner, const DukValue& dukHandler, const std::vector& args) { - if (dukHandler.is_function()) - { - auto& scriptEngine = GetContext()->GetScriptEngine(); - auto& execInfo = scriptEngine.GetExecInfo(); - { - ScriptExecutionInfo::PluginScope scope(execInfo, owner, false); - dukHandler.push(); - for (const auto& arg : args) - { - arg.push(); - } - duk_pcall(dukHandler.context(), (duk_idx_t)args.size()); - duk_pop(dukHandler.context()); - } - } + auto& scriptEngine = GetContext()->GetScriptEngine(); + scriptEngine.ExecutePluginCall(owner, dukHandler, args, false); } std::string GetWindowTitle(rct_window* w) diff --git a/src/openrct2/scripting/HookEngine.cpp b/src/openrct2/scripting/HookEngine.cpp index ee554fd75a..fa3442f2ce 100644 --- a/src/openrct2/scripting/HookEngine.cpp +++ b/src/openrct2/scripting/HookEngine.cpp @@ -28,8 +28,9 @@ HOOK_TYPE OpenRCT2::Scripting::GetHookType(const std::string& name) return (result != LookupTable.end()) ? result->second : HOOK_TYPE::UNDEFINED; } -HookEngine::HookEngine(ScriptExecutionInfo& execInfo) - : _execInfo(execInfo) +HookEngine::HookEngine(ScriptEngine& scriptEngine, ScriptExecutionInfo& execInfo) + : _scriptEngine(scriptEngine) + , _execInfo(execInfo) { _hookMap.resize(NUM_HOOK_TYPES); for (size_t i = 0; i < NUM_HOOK_TYPES; i++) @@ -100,29 +101,16 @@ void HookEngine::Call(HOOK_TYPE type, bool isGameStateMutable) auto& hookList = GetHookList(type); for (auto& hook : hookList.Hooks) { - ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false); - - const auto& function = hook.Function; - function.push(); - duk_pcall(function.context(), 0); - duk_pop(function.context()); + _scriptEngine.ExecutePluginCall(hook.Owner, hook.Function, {}, isGameStateMutable); } } -void HookEngine::Call(HOOK_TYPE type, DukValue args, bool isGameStateMutable) +void HookEngine::Call(HOOK_TYPE type, const DukValue& arg, bool isGameStateMutable) { auto& hookList = GetHookList(type); for (auto& hook : hookList.Hooks) { - ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false); - - const auto& function = hook.Function; - auto ctx = function.context(); - function.push(); - - args.push(); - duk_pcall(ctx, 1); - duk_pop(ctx); + _scriptEngine.ExecutePluginCall(hook.Owner, hook.Function, { arg }, isGameStateMutable); } } @@ -132,12 +120,9 @@ void HookEngine::Call( auto& hookList = GetHookList(type); for (auto& hook : hookList.Hooks) { - ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false); - - const auto& function = hook.Function; - auto ctx = function.context(); - function.push(); + auto ctx = _scriptEngine.GetContext(); + // Convert key/value pairs into an object auto objIdx = duk_push_object(ctx); for (const auto& arg : args) { @@ -157,8 +142,10 @@ void HookEngine::Call( } duk_put_prop_string(ctx, objIdx, arg.first.data()); } - duk_pcall(ctx, 1); - duk_pop(ctx); + + std::vector dukArgs; + dukArgs.push_back(DukValue::take_from_stack(ctx)); + _scriptEngine.ExecutePluginCall(hook.Owner, hook.Function, dukArgs, isGameStateMutable); } } diff --git a/src/openrct2/scripting/HookEngine.h b/src/openrct2/scripting/HookEngine.h index cfaeaf9474..60ba158cfe 100644 --- a/src/openrct2/scripting/HookEngine.h +++ b/src/openrct2/scripting/HookEngine.h @@ -22,6 +22,7 @@ namespace OpenRCT2::Scripting { + class ScriptEngine; class ScriptExecutionInfo; class Plugin; @@ -42,7 +43,7 @@ namespace OpenRCT2::Scripting std::shared_ptr Owner; DukValue Function; - Hook(); + Hook() = default; Hook(uint32_t cookie, std::shared_ptr owner, const DukValue& function) : Cookie(cookie) , Owner(owner) @@ -56,11 +57,9 @@ namespace OpenRCT2::Scripting HOOK_TYPE Type{}; std::vector Hooks; - HookList() - { - } + HookList() = default; HookList(const HookList&) = delete; - HookList(HookList&& src) + HookList(HookList&& src) noexcept : Type(std::move(src.Type)) , Hooks(std::move(src.Hooks)) { @@ -70,12 +69,13 @@ namespace OpenRCT2::Scripting class HookEngine { private: + ScriptEngine& _scriptEngine; ScriptExecutionInfo& _execInfo; std::vector _hookMap; uint32_t _nextCookie = 1; public: - HookEngine(ScriptExecutionInfo& execInfo); + HookEngine(ScriptEngine& scriptEngine, ScriptExecutionInfo& execInfo); HookEngine(const HookEngine&) = delete; uint32_t Subscribe(HOOK_TYPE type, std::shared_ptr owner, const DukValue& function); void Unsubscribe(HOOK_TYPE type, uint32_t cookie); @@ -83,7 +83,7 @@ namespace OpenRCT2::Scripting void UnsubscribeAll(); bool HasSubscriptions(HOOK_TYPE type) const; void Call(HOOK_TYPE type, bool isGameStateMutable); - void Call(HOOK_TYPE type, DukValue args, bool isGameStateMutable); + void Call(HOOK_TYPE type, const DukValue& arg, bool isGameStateMutable); void Call( HOOK_TYPE type, const std::initializer_list>& args, bool isGameStateMutable); diff --git a/src/openrct2/scripting/ScTile.hpp b/src/openrct2/scripting/ScTile.hpp index 2f72c4f04c..1b56d4dca7 100644 --- a/src/openrct2/scripting/ScTile.hpp +++ b/src/openrct2/scripting/ScTile.hpp @@ -20,6 +20,7 @@ # include "ScriptEngine.h" # include +# include namespace OpenRCT2::Scripting { @@ -110,26 +111,43 @@ namespace OpenRCT2::Scripting } } - auto baseHeight_get() const + auto baseZ_get() const { return _element->base_height; } - void baseHeight_set(uint8_t newBaseHeight) + void baseZ_set(uint8_t newBaseHeight) { ThrowIfGameStateNotMutable(); _element->base_height = newBaseHeight; } - auto clearanceHeight_get() const + auto clearanceZ_get() const { return _element->clearance_height; } - void clearanceHeight_set(uint8_t newClearanceHeight) + void clearanceZ_set(uint8_t newClearanceHeight) { ThrowIfGameStateNotMutable(); _element->clearance_height = newClearanceHeight; } + uint32_t surfaceStyle_get() + { + auto el = _element->AsSurface(); + if (el != nullptr) + return el->GetSurfaceStyle(); + return 0; + } + void surfaceStyle_set(uint32_t value) + { + ThrowIfGameStateNotMutable(); + auto el = _element->AsSurface(); + if (el != nullptr) + { + el->SetSurfaceStyle(value); + } + } + uint8_t grassLength_get() { auto el = _element->AsSurface(); @@ -160,13 +178,14 @@ namespace OpenRCT2::Scripting static void Register(duk_context* ctx) { dukglue_register_property(ctx, &ScTileElement::type_get, &ScTileElement::type_set, "type"); - dukglue_register_property(ctx, &ScTileElement::baseHeight_get, &ScTileElement::baseHeight_set, "baseHeight"); - dukglue_register_property( - ctx, &ScTileElement::clearanceHeight_get, &ScTileElement::clearanceHeight_set, "clearanceHeight"); + dukglue_register_property(ctx, &ScTileElement::baseZ_get, &ScTileElement::baseZ_set, "baseZ"); + dukglue_register_property(ctx, &ScTileElement::clearanceZ_get, &ScTileElement::clearanceZ_set, "clearanceZ"); - dukglue_register_property(ctx, &ScTileElement::broken_get, &ScTileElement::broken_set, "broken"); + dukglue_register_property(ctx, &ScTileElement::surfaceStyle_get, &ScTileElement::surfaceStyle_set, "surfaceStyle"); dukglue_register_property(ctx, &ScTileElement::grassLength_get, &ScTileElement::grassLength_set, "grassLength"); dukglue_register_property(ctx, &ScTileElement::hasOwnership_get, nullptr, "hasOwnership"); + + dukglue_register_property(ctx, &ScTileElement::broken_get, &ScTileElement::broken_set, "broken"); } }; @@ -230,6 +249,7 @@ namespace OpenRCT2::Scripting void data_set(DukValue value) { + ThrowIfGameStateNotMutable(); auto ctx = value.context(); value.push(); if (duk_is_buffer_data(ctx, -1)) @@ -288,6 +308,7 @@ namespace OpenRCT2::Scripting std::shared_ptr insertElement(size_t index) { + ThrowIfGameStateNotMutable(); auto first = GetFirstElement(); auto origNumElements = GetNumElements(first); if (index >= 0 && index <= origNumElements) @@ -335,6 +356,7 @@ namespace OpenRCT2::Scripting void removeElement(size_t index) { + ThrowIfGameStateNotMutable(); auto first = GetFirstElement(); if (index < GetNumElements(first)) { diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 0dc5514ff9..6ce31a317a 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -356,7 +356,7 @@ DukContext::~DukContext() ScriptEngine::ScriptEngine(InteractiveConsole& console, IPlatformEnvironment& env) : _console(console) , _env(env) - , _hookEngine(_execInfo) + , _hookEngine(*this, _execInfo) { } @@ -652,6 +652,34 @@ std::future ScriptEngine::Eval(const std::string& s) return future; } +bool ScriptEngine::ExecutePluginCall( + const std::shared_ptr& plugin, const DukValue& func, const std::vector& args, bool isGameStateMutable) +{ + if (func.is_function()) + { + ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, isGameStateMutable); + func.push(); + for (const auto& arg : args) + { + arg.push(); + } + auto result = duk_pcall(_context, static_cast(args.size())); + if (result == DUK_EXEC_SUCCESS) + { + // TODO allow result to be returned as a DukValue + duk_pop(_context); + return true; + } + else + { + auto message = duk_safe_to_string(_context, -1); + LogPluginInfo(plugin, message); + duk_pop(_context); + } + } + return false; +} + void ScriptEngine::LogPluginInfo(const std::shared_ptr& plugin, const std::string_view& message) { const auto& pluginName = plugin->GetMetadata().Name; diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index 705db8a2ef..cf7f62acfa 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -142,6 +142,9 @@ namespace OpenRCT2::Scripting void UnloadPlugins(); void Update(); std::future Eval(const std::string& s); + bool ExecutePluginCall( + const std::shared_ptr& plugin, const DukValue& func, const std::vector& args, + bool isGameStateMutable); void LogPluginInfo(const std::shared_ptr& plugin, const std::string_view& message);