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 ctx = scriptEngine.GetContext();
ScriptExecutionInfo::PluginScope scope(execInfo, Owner);
ScriptExecutionInfo::PluginScope scope(execInfo, Owner, false);
Callback.push();
duk_pcall(ctx, 0);
duk_pop(ctx);

View File

@ -648,7 +648,7 @@ namespace OpenRCT2::Ui::Windows
auto& scriptEngine = GetContext()->GetScriptEngine();
auto& execInfo = scriptEngine.GetExecInfo();
{
ScriptExecutionInfo::PluginScope scope(execInfo, owner);
ScriptExecutionInfo::PluginScope scope(execInfo, owner, false);
dukHandler.push();
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::rotation_get, &ScViewport::rotation_set, "rotation");
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::moveTo, "moveTo");
dukglue_register_method(ctx, &ScViewport::scrollTo, "scrollTo");

View File

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

View File

@ -2905,7 +2905,7 @@ void Network::Server_Handle_CHAT(NetworkConnection& connection, NetworkPacket& p
auto e = DukValue::take_from_stack(ctx);
// 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
if (e["message"].type() != DukValue::Type::STRING)

View File

@ -93,12 +93,12 @@ bool HookEngine::HasSubscriptions(HOOK_TYPE type) const
return !hookList.Hooks.empty();
}
void HookEngine::Call(HOOK_TYPE type)
void HookEngine::Call(HOOK_TYPE type, bool isGameStateMutable)
{
auto& hookList = GetHookList(type);
for (auto& hook : hookList.Hooks)
{
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner);
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false);
const auto& function = hook.Function;
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);
for (auto& hook : hookList.Hooks)
{
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner);
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false);
const auto& function = hook.Function;
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);
for (auto& hook : hookList.Hooks)
{
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner);
ScriptExecutionInfo::PluginScope scope(_execInfo, hook.Owner, false);
const auto& function = hook.Function;
auto ctx = function.context();

View File

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

View File

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

View File

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

View File

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

View File

@ -42,7 +42,8 @@ namespace OpenRCT2::Scripting
}
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
@ -52,7 +53,8 @@ namespace OpenRCT2::Scripting
}
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
@ -62,7 +64,8 @@ namespace OpenRCT2::Scripting
}
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()
@ -71,6 +74,7 @@ namespace OpenRCT2::Scripting
}
void tshirtColour_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
_sprite->peep.tshirt_colour = value;
}
uint8_t trousersColour_get()
@ -79,6 +83,7 @@ namespace OpenRCT2::Scripting
}
void trousersColour_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
_sprite->peep.trousers_colour = value;
}

View File

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

View File

@ -132,7 +132,7 @@ void ScriptEngine::LoadPlugin(std::shared_ptr<Plugin>& plugin)
{
try
{
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin);
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
plugin->Load();
auto metadata = plugin->GetMetadata();
@ -162,7 +162,7 @@ void ScriptEngine::StopPlugin(std::shared_ptr<Plugin> plugin)
callback(plugin);
}
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin);
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
try
{
plugin->Stop();
@ -214,7 +214,7 @@ void ScriptEngine::AutoReloadPlugins()
{
StopPlugin(plugin);
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin);
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
plugin->Load();
LogPluginInfo(plugin, "Reloaded");
plugin->Start();
@ -247,7 +247,7 @@ void ScriptEngine::StartPlugins()
{
if (!plugin->HasStarted() && ShouldStartPlugin(plugin))
{
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin);
ScriptExecutionInfo::PluginScope scope(_execInfo, plugin, false);
try
{
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);
}
}
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:
std::shared_ptr<Plugin> _plugin;
bool _isGameStateMutable{};
public:
class PluginScope
@ -48,16 +49,18 @@ namespace OpenRCT2::Scripting
std::shared_ptr<Plugin> _plugin;
public:
PluginScope(ScriptExecutionInfo& execInfo, std::shared_ptr<Plugin> plugin)
PluginScope(ScriptExecutionInfo& execInfo, std::shared_ptr<Plugin> plugin, bool isGameStateMutable)
: _execInfo(execInfo)
, _plugin(plugin)
{
_execInfo._plugin = plugin;
_execInfo._isGameStateMutable = isGameStateMutable;
}
PluginScope(const PluginScope&) = delete;
~PluginScope()
{
_execInfo._plugin = nullptr;
_execInfo._isGameStateMutable = false;
}
};
@ -65,6 +68,11 @@ namespace OpenRCT2::Scripting
{
return _plugin;
}
bool IsGameStateMutable()
{
return _isGameStateMutable;
}
};
class DukContext
@ -150,9 +158,13 @@ namespace OpenRCT2::Scripting
void LoadPlugin(std::shared_ptr<Plugin>& plugin);
void StopPlugin(std::shared_ptr<Plugin> plugin);
bool ShouldLoadScript(const std::string& path);
bool ShouldStartPlugin(const std::shared_ptr<Plugin> &plugin);
bool ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin);
void SetupHotReloading();
void AutoReloadPlugins();
void ProcessREPL();
};
bool IsGameStateMutable();
void ThrowIfGameStateNotMutable();
} // namespace OpenRCT2::Scripting