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:
5
distribution/openrct2.d.ts
vendored
5
distribution/openrct2.d.ts
vendored
@@ -155,9 +155,8 @@ declare global {
|
||||
|
||||
interface BaseTileElement {
|
||||
type: TileElementType;
|
||||
baseHeight: number;
|
||||
clearanceHeight: number;
|
||||
broken: boolean;
|
||||
baseZ: number;
|
||||
clearanceZ: number;
|
||||
}
|
||||
|
||||
// interface TileElement extends BaseTileElement {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user