1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-23 15:52:55 +01:00

Add game mutable protection

This commit is contained in:
Ted John
2020-02-23 02:00:22 +00:00
parent dc64d3541d
commit a5c8ff920f
14 changed files with 77 additions and 24 deletions

View File

@@ -38,7 +38,7 @@ namespace OpenRCT2::Scripting
auto& execInfo = scriptEngine.GetExecInfo(); auto& execInfo = scriptEngine.GetExecInfo();
auto ctx = scriptEngine.GetContext(); auto ctx = scriptEngine.GetContext();
ScriptExecutionInfo::PluginScope scope(execInfo, Owner); ScriptExecutionInfo::PluginScope scope(execInfo, Owner, false);
Callback.push(); Callback.push();
duk_pcall(ctx, 0); duk_pcall(ctx, 0);
duk_pop(ctx); duk_pop(ctx);

View File

@@ -648,7 +648,7 @@ namespace OpenRCT2::Ui::Windows
auto& scriptEngine = GetContext()->GetScriptEngine(); auto& scriptEngine = GetContext()->GetScriptEngine();
auto& execInfo = scriptEngine.GetExecInfo(); auto& execInfo = scriptEngine.GetExecInfo();
{ {
ScriptExecutionInfo::PluginScope scope(execInfo, owner); ScriptExecutionInfo::PluginScope scope(execInfo, owner, false);
dukHandler.push(); dukHandler.push();
for (const auto& arg : args) for (const auto& arg : args)
{ {

View File

@@ -232,7 +232,8 @@ namespace OpenRCT2::Scripting
dukglue_register_property(ctx, &ScViewport::bottom_get, &ScViewport::bottom_set, "bottom"); dukglue_register_property(ctx, &ScViewport::bottom_get, &ScViewport::bottom_set, "bottom");
dukglue_register_property(ctx, &ScViewport::rotation_get, &ScViewport::rotation_set, "rotation"); dukglue_register_property(ctx, &ScViewport::rotation_get, &ScViewport::rotation_set, "rotation");
dukglue_register_property(ctx, &ScViewport::zoom_get, &ScViewport::zoom_set, "zoom"); dukglue_register_property(ctx, &ScViewport::zoom_get, &ScViewport::zoom_set, "zoom");
dukglue_register_property(ctx, &ScViewport::visibilityFlags_get, &ScViewport::visibilityFlags_set, "visibilityFlags"); dukglue_register_property(
ctx, &ScViewport::visibilityFlags_get, &ScViewport::visibilityFlags_set, "visibilityFlags");
dukglue_register_method(ctx, &ScViewport::getCentrePosition, "getCentrePosition"); dukglue_register_method(ctx, &ScViewport::getCentrePosition, "getCentrePosition");
dukglue_register_method(ctx, &ScViewport::moveTo, "moveTo"); dukglue_register_method(ctx, &ScViewport::moveTo, "moveTo");
dukglue_register_method(ctx, &ScViewport::scrollTo, "scrollTo"); dukglue_register_method(ctx, &ScViewport::scrollTo, "scrollTo");

View File

@@ -270,7 +270,7 @@ void GameState::UpdateLogic()
} }
auto& hookEngine = GetContext()->GetScriptEngine().GetHookEngine(); auto& hookEngine = GetContext()->GetScriptEngine().GetHookEngine();
hookEngine.Call(HOOK_TYPE::INTERVAL_TICK); hookEngine.Call(HOOK_TYPE::INTERVAL_TICK, true);
auto day = _date.GetDay(); auto day = _date.GetDay();
@@ -279,7 +279,7 @@ void GameState::UpdateLogic()
if (day != _date.GetDay()) if (day != _date.GetDay())
{ {
hookEngine.Call(HOOK_TYPE::INTERVAL_DAY); hookEngine.Call(HOOK_TYPE::INTERVAL_DAY, true);
} }
scenario_update(); scenario_update();

View File

@@ -2905,7 +2905,7 @@ void Network::Server_Handle_CHAT(NetworkConnection& connection, NetworkPacket& p
auto e = DukValue::take_from_stack(ctx); auto e = DukValue::take_from_stack(ctx);
// Call the subscriptions // Call the subscriptions
hookEngine.Call(OpenRCT2::Scripting::HOOK_TYPE::NETWORK_CHAT, e); hookEngine.Call(OpenRCT2::Scripting::HOOK_TYPE::NETWORK_CHAT, e, false);
// Update text from object if subscriptions changed it // Update text from object if subscriptions changed it
if (e["message"].type() != DukValue::Type::STRING) if (e["message"].type() != DukValue::Type::STRING)

View File

@@ -93,12 +93,12 @@ bool HookEngine::HasSubscriptions(HOOK_TYPE type) const
return !hookList.Hooks.empty(); return !hookList.Hooks.empty();
} }
void HookEngine::Call(HOOK_TYPE type) void HookEngine::Call(HOOK_TYPE type, bool isGameStateMutable)
{ {
auto& hookList = GetHookList(type); auto& hookList = GetHookList(type);
for (auto& hook : hookList.Hooks) for (auto& hook : hookList.Hooks)
{ {
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner); ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false);
const auto& function = hook.Function; const auto& function = hook.Function;
function.push(); function.push();
@@ -107,12 +107,12 @@ void HookEngine::Call(HOOK_TYPE type)
} }
} }
void HookEngine::Call(HOOK_TYPE type, DukValue args) void HookEngine::Call(HOOK_TYPE type, DukValue args, bool isGameStateMutable)
{ {
auto& hookList = GetHookList(type); auto& hookList = GetHookList(type);
for (auto& hook : hookList.Hooks) for (auto& hook : hookList.Hooks)
{ {
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner); ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false);
const auto& function = hook.Function; const auto& function = hook.Function;
auto ctx = function.context(); auto ctx = function.context();
@@ -124,12 +124,12 @@ void HookEngine::Call(HOOK_TYPE type, DukValue args)
} }
} }
void HookEngine::Call(HOOK_TYPE type, const std::initializer_list<std::pair<std::string_view, std::any>>& args) void HookEngine::Call(HOOK_TYPE type, const std::initializer_list<std::pair<std::string_view, std::any>>& args, bool isGameStateMutable)
{ {
auto& hookList = GetHookList(type); auto& hookList = GetHookList(type);
for (auto& hook : hookList.Hooks) for (auto& hook : hookList.Hooks)
{ {
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner); ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false);
const auto& function = hook.Function; const auto& function = hook.Function;
auto ctx = function.context(); auto ctx = function.context();

View File

@@ -81,9 +81,9 @@ namespace OpenRCT2::Scripting
void UnsubscribeAll(std::shared_ptr<const Plugin> owner); void UnsubscribeAll(std::shared_ptr<const Plugin> owner);
void UnsubscribeAll(); void UnsubscribeAll();
bool HasSubscriptions(HOOK_TYPE type) const; bool HasSubscriptions(HOOK_TYPE type) const;
void Call(HOOK_TYPE type); void Call(HOOK_TYPE type, bool isGameStateMutable);
void Call(HOOK_TYPE type, DukValue args); void Call(HOOK_TYPE type, DukValue args, bool isGameStateMutable);
void Call(HOOK_TYPE type, const std::initializer_list<std::pair<std::string_view, std::any>>& args); void Call(HOOK_TYPE type, const std::initializer_list<std::pair<std::string_view, std::any>>& args, bool isGameStateMutable);
private: private:
HookList& GetHookList(HOOK_TYPE type); HookList& GetHookList(HOOK_TYPE type);

View File

@@ -42,6 +42,7 @@ namespace OpenRCT2::Scripting
void monthsElapsed_set(uint32_t value) void monthsElapsed_set(uint32_t value)
{ {
ThrowIfGameStateNotMutable();
gDateMonthsElapsed = value; gDateMonthsElapsed = value;
} }
@@ -53,6 +54,7 @@ namespace OpenRCT2::Scripting
void monthProgress_set(int32_t value) void monthProgress_set(int32_t value)
{ {
ThrowIfGameStateNotMutable();
gDateMonthTicks = value; gDateMonthTicks = value;
} }

View File

@@ -16,6 +16,7 @@
#include "../windows/Intent.h" #include "../windows/Intent.h"
#include "../world/Park.h" #include "../world/Park.h"
#include "Duktape.hpp" #include "Duktape.hpp"
#include "ScriptEngine.h"
#include <algorithm> #include <algorithm>
@@ -30,6 +31,7 @@ namespace OpenRCT2::Scripting
} }
void cash_set(money32 value) void cash_set(money32 value)
{ {
ThrowIfGameStateNotMutable();
gCash = value; gCash = value;
auto intent = Intent(INTENT_ACTION_UPDATE_CASH); auto intent = Intent(INTENT_ACTION_UPDATE_CASH);
context_broadcast_intent(&intent); context_broadcast_intent(&intent);
@@ -41,6 +43,7 @@ namespace OpenRCT2::Scripting
} }
void rating_set(int32_t value) void rating_set(int32_t value)
{ {
ThrowIfGameStateNotMutable();
gParkRating = std::min(std::max(0, value), 999); gParkRating = std::min(std::max(0, value), 999);
auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING); auto intent = Intent(INTENT_ACTION_UPDATE_PARK_RATING);
context_broadcast_intent(&intent); context_broadcast_intent(&intent);
@@ -52,6 +55,7 @@ namespace OpenRCT2::Scripting
} }
void bankLoan_set(money32 value) void bankLoan_set(money32 value)
{ {
ThrowIfGameStateNotMutable();
gBankLoan = value; gBankLoan = value;
auto intent = Intent(INTENT_ACTION_UPDATE_CASH); auto intent = Intent(INTENT_ACTION_UPDATE_CASH);
context_broadcast_intent(&intent); context_broadcast_intent(&intent);
@@ -63,6 +67,7 @@ namespace OpenRCT2::Scripting
} }
void maxBankLoan_set(money32 value) void maxBankLoan_set(money32 value)
{ {
ThrowIfGameStateNotMutable();
gMaxBankLoan = value; gMaxBankLoan = value;
auto intent = Intent(INTENT_ACTION_UPDATE_CASH); auto intent = Intent(INTENT_ACTION_UPDATE_CASH);
context_broadcast_intent(&intent); context_broadcast_intent(&intent);
@@ -70,6 +75,7 @@ namespace OpenRCT2::Scripting
void postMessage(DukValue message) void postMessage(DukValue message)
{ {
ThrowIfGameStateNotMutable();
try try
{ {
uint8_t type = NEWS_ITEM_BLANK; uint8_t type = NEWS_ITEM_BLANK;

View File

@@ -114,6 +114,7 @@ namespace OpenRCT2::Scripting
} }
void name_set(std::string value) void name_set(std::string value)
{ {
ThrowIfGameStateNotMutable();
_ride->custom_name = value; _ride->custom_name = value;
} }
@@ -123,6 +124,7 @@ namespace OpenRCT2::Scripting
} }
void excitement_set(int32_t value) void excitement_set(int32_t value)
{ {
ThrowIfGameStateNotMutable();
_ride->excitement = value; _ride->excitement = value;
} }
@@ -132,6 +134,7 @@ namespace OpenRCT2::Scripting
} }
void intensity_set(int32_t value) void intensity_set(int32_t value)
{ {
ThrowIfGameStateNotMutable();
_ride->intensity = value; _ride->intensity = value;
} }
@@ -141,6 +144,7 @@ namespace OpenRCT2::Scripting
} }
void nausea_set(int32_t value) void nausea_set(int32_t value)
{ {
ThrowIfGameStateNotMutable();
_ride->nausea = value; _ride->nausea = value;
} }
@@ -150,6 +154,7 @@ namespace OpenRCT2::Scripting
} }
void totalCustomers_set(int32_t value) void totalCustomers_set(int32_t value)
{ {
ThrowIfGameStateNotMutable();
_ride->total_customers = value; _ride->total_customers = value;
} }

View File

@@ -42,7 +42,8 @@ namespace OpenRCT2::Scripting
} }
void x_set(int32_t value) void x_set(int32_t value)
{ {
_sprite->generic.x = value; ThrowIfGameStateNotMutable();
sprite_move(value, _sprite->generic.y, _sprite->generic.z, &_sprite->generic);
} }
// y getter and setter // y getter and setter
@@ -52,7 +53,8 @@ namespace OpenRCT2::Scripting
} }
void y_set(int32_t value) void y_set(int32_t value)
{ {
_sprite->generic.y = value; ThrowIfGameStateNotMutable();
sprite_move(_sprite->generic.x, value, _sprite->generic.z, &_sprite->generic);
} }
// z getter and setter // z getter and setter
@@ -62,7 +64,8 @@ namespace OpenRCT2::Scripting
} }
void z_set(int16_t value) void z_set(int16_t value)
{ {
_sprite->generic.z = value; ThrowIfGameStateNotMutable();
sprite_move(_sprite->generic.x, _sprite->generic.y, value, &_sprite->generic);
} }
uint8_t tshirtColour_get() uint8_t tshirtColour_get()
@@ -71,6 +74,7 @@ namespace OpenRCT2::Scripting
} }
void tshirtColour_set(uint8_t value) void tshirtColour_set(uint8_t value)
{ {
ThrowIfGameStateNotMutable();
_sprite->peep.tshirt_colour = value; _sprite->peep.tshirt_colour = value;
} }
uint8_t trousersColour_get() uint8_t trousersColour_get()
@@ -79,6 +83,7 @@ namespace OpenRCT2::Scripting
} }
void trousersColour_set(uint8_t value) void trousersColour_set(uint8_t value)
{ {
ThrowIfGameStateNotMutable();
_sprite->peep.trousers_colour = value; _sprite->peep.trousers_colour = value;
} }

View File

@@ -69,6 +69,7 @@ namespace OpenRCT2::Scripting
} }
void broken_set(bool value) void broken_set(bool value)
{ {
ThrowIfGameStateNotMutable();
if (value) if (value)
{ {
_element->flags |= TILE_ELEMENT_FLAG_BROKEN; _element->flags |= TILE_ELEMENT_FLAG_BROKEN;
@@ -85,6 +86,7 @@ namespace OpenRCT2::Scripting
} }
void baseHeight_set(uint8_t newBaseHeight) void baseHeight_set(uint8_t newBaseHeight)
{ {
ThrowIfGameStateNotMutable();
_element->base_height = newBaseHeight; _element->base_height = newBaseHeight;
} }
@@ -94,6 +96,7 @@ namespace OpenRCT2::Scripting
} }
void clearanceHeight_set(uint8_t newClearanceHeight) void clearanceHeight_set(uint8_t newClearanceHeight)
{ {
ThrowIfGameStateNotMutable();
_element->clearance_height = newClearanceHeight; _element->clearance_height = newClearanceHeight;
} }
@@ -106,6 +109,7 @@ namespace OpenRCT2::Scripting
} }
void grassLength_set(uint8_t value) void grassLength_set(uint8_t value)
{ {
ThrowIfGameStateNotMutable();
auto el = _element->AsSurface(); auto el = _element->AsSurface();
if (el != nullptr) if (el != nullptr)
{ {

View File

@@ -132,7 +132,7 @@ void ScriptEngine::LoadPlugin(std::shared_ptr<Plugin>& plugin)
{ {
try try
{ {
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin); ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
plugin->Load(); plugin->Load();
auto metadata = plugin->GetMetadata(); auto metadata = plugin->GetMetadata();
@@ -162,7 +162,7 @@ void ScriptEngine::StopPlugin(std::shared_ptr<Plugin> plugin)
callback(plugin); callback(plugin);
} }
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin); ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
try try
{ {
plugin->Stop(); plugin->Stop();
@@ -214,7 +214,7 @@ void ScriptEngine::AutoReloadPlugins()
{ {
StopPlugin(plugin); StopPlugin(plugin);
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin); ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
plugin->Load(); plugin->Load();
LogPluginInfo(plugin, "Reloaded"); LogPluginInfo(plugin, "Reloaded");
plugin->Start(); plugin->Start();
@@ -247,7 +247,7 @@ void ScriptEngine::StartPlugins()
{ {
if (!plugin->HasStarted() && ShouldStartPlugin(plugin)) if (!plugin->HasStarted() && ShouldStartPlugin(plugin))
{ {
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin); ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
try try
{ {
LogPluginInfo(plugin, "Started"); LogPluginInfo(plugin, "Started");
@@ -380,3 +380,21 @@ static std::string Stringify(duk_context* ctx, duk_idx_t idx)
return duk_safe_to_string(ctx, idx); return duk_safe_to_string(ctx, idx);
} }
} }
bool OpenRCT2::Scripting::IsGameStateMutable()
{
auto& scriptEngine = GetContext()->GetScriptEngine();
auto& execInfo = scriptEngine.GetExecInfo();
return execInfo.IsGameStateMutable();
}
void OpenRCT2::Scripting::ThrowIfGameStateNotMutable()
{
auto& scriptEngine = GetContext()->GetScriptEngine();
auto& execInfo = scriptEngine.GetExecInfo();
if (!execInfo.IsGameStateMutable())
{
auto ctx = scriptEngine.GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Game state is not mutable in this context.");
}
}

View File

@@ -39,6 +39,7 @@ namespace OpenRCT2::Scripting
{ {
private: private:
std::shared_ptr<Plugin> _plugin; std::shared_ptr<Plugin> _plugin;
bool _isGameStateMutable{};
public: public:
class PluginScope class PluginScope
@@ -48,16 +49,18 @@ namespace OpenRCT2::Scripting
std::shared_ptr<Plugin> _plugin; std::shared_ptr<Plugin> _plugin;
public: public:
PluginScope(ScriptExecutionInfo& execInfo, std::shared_ptr<Plugin> plugin) PluginScope(ScriptExecutionInfo& execInfo, std::shared_ptr<Plugin> plugin, bool isGameStateMutable)
: _execInfo(execInfo) : _execInfo(execInfo)
, _plugin(plugin) , _plugin(plugin)
{ {
_execInfo._plugin = plugin; _execInfo._plugin = plugin;
_execInfo._isGameStateMutable = isGameStateMutable;
} }
PluginScope(const PluginScope&) = delete; PluginScope(const PluginScope&) = delete;
~PluginScope() ~PluginScope()
{ {
_execInfo._plugin = nullptr; _execInfo._plugin = nullptr;
_execInfo._isGameStateMutable = false;
} }
}; };
@@ -65,6 +68,11 @@ namespace OpenRCT2::Scripting
{ {
return _plugin; return _plugin;
} }
bool IsGameStateMutable()
{
return _isGameStateMutable;
}
}; };
class DukContext class DukContext
@@ -155,4 +163,8 @@ namespace OpenRCT2::Scripting
void AutoReloadPlugins(); void AutoReloadPlugins();
void ProcessREPL(); void ProcessREPL();
}; };
bool IsGameStateMutable();
void ThrowIfGameStateNotMutable();
} // namespace OpenRCT2::Scripting } // namespace OpenRCT2::Scripting