1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-06 06:32:56 +01:00

Implement surface style API and improve plugin calling

This commit is contained in:
Ted John
2020-02-29 13:18:31 +00:00
parent 32d72471b8
commit 4d5e7f19ca
8 changed files with 86 additions and 66 deletions

View File

@@ -155,9 +155,8 @@ declare global {
interface BaseTileElement {
type: TileElementType;
baseHeight: number;
clearanceHeight: number;
broken: boolean;
baseZ: number;
clearanceZ: number;
}
// interface TileElement extends BaseTileElement {

View File

@@ -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);
}
};

View File

@@ -708,21 +708,8 @@ namespace OpenRCT2::Ui::Windows
static void InvokeEventHandler(std::shared_ptr<Plugin> owner, const DukValue& dukHandler, const std::vector<DukValue>& 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)

View File

@@ -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<DukValue> dukArgs;
dukArgs.push_back(DukValue::take_from_stack(ctx));
_scriptEngine.ExecutePluginCall(hook.Owner, hook.Function, dukArgs, isGameStateMutable);
}
}

View File

@@ -22,6 +22,7 @@
namespace OpenRCT2::Scripting
{
class ScriptEngine;
class ScriptExecutionInfo;
class Plugin;
@@ -42,7 +43,7 @@ namespace OpenRCT2::Scripting
std::shared_ptr<Plugin> Owner;
DukValue Function;
Hook();
Hook() = default;
Hook(uint32_t cookie, std::shared_ptr<Plugin> owner, const DukValue& function)
: Cookie(cookie)
, Owner(owner)
@@ -56,11 +57,9 @@ namespace OpenRCT2::Scripting
HOOK_TYPE Type{};
std::vector<Hook> 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<HookList> _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<Plugin> 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<std::pair<std::string_view, std::any>>& args, bool isGameStateMutable);

View File

@@ -20,6 +20,7 @@
# include "ScriptEngine.h"
# include <cstdio>
# include <cstring>
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<ScTileElement> 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))
{

View File

@@ -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<void> ScriptEngine::Eval(const std::string& s)
return future;
}
bool ScriptEngine::ExecutePluginCall(
const std::shared_ptr<Plugin>& plugin, const DukValue& func, const std::vector<DukValue>& 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<duk_idx_t>(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>& plugin, const std::string_view& message)
{
const auto& pluginName = plugin->GetMetadata().Name;

View File

@@ -142,6 +142,9 @@ namespace OpenRCT2::Scripting
void UnloadPlugins();
void Update();
std::future<void> Eval(const std::string& s);
bool ExecutePluginCall(
const std::shared_ptr<Plugin>& plugin, const DukValue& func, const std::vector<DukValue>& args,
bool isGameStateMutable);
void LogPluginInfo(const std::shared_ptr<Plugin>& plugin, const std::string_view& message);