From b3fd7879596defeb6af78acb4ea45e4418821bdf Mon Sep 17 00:00:00 2001 From: glx22 Date: Sat, 7 Sep 2019 18:37:01 +0200 Subject: Fix #7188: check the validity of command callback for scripts (#7701) --- src/script/api/script_object.cpp | 20 ++++++++++++++++++++ src/script/api/script_object.hpp | 10 ++++++++++ src/script/script_instance.cpp | 8 +++++++- src/script/script_instance.hpp | 4 +++- src/script/script_storage.hpp | 9 +++++++++ 5 files changed, 49 insertions(+), 2 deletions(-) (limited to 'src/script') diff --git a/src/script/api/script_object.cpp b/src/script/api/script_object.cpp index 62a71574f..ac06c4c2d 100644 --- a/src/script/api/script_object.cpp +++ b/src/script/api/script_object.cpp @@ -83,6 +83,23 @@ ScriptObject::ActiveInstance::~ActiveInstance() return GetStorage()->mode_instance; } +/* static */ void ScriptObject::SetLastCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) +{ + GetStorage()->last_tile = tile; + GetStorage()->last_p1 = p1; + GetStorage()->last_p2 = p2; + GetStorage()->last_cmd = cmd; +} + +/* static */ bool ScriptObject::CheckLastCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) +{ + if (GetStorage()->last_tile != tile) return false; + if (GetStorage()->last_p1 != p1) return false; + if (GetStorage()->last_p2 != p2) return false; + if (GetStorage()->last_cmd != cmd) return false; + return true; +} + /* static */ void ScriptObject::SetDoCommandCosts(Money value) { GetStorage()->costs = CommandCost(value); @@ -304,6 +321,9 @@ ScriptObject::ActiveInstance::~ActiveInstance() /* Only set p2 when the command does not come from the network. */ if (GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = UINT32_MAX; + /* Store the command for command callback validation. */ + if (!estimate_only && _networking && !_generating_world) SetLastCommand(tile, p1, p2, cmd); + /* Try to perform the command. */ CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : nullptr, text, false, estimate_only); diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp index 55dd5e39b..fba4b69f2 100644 --- a/src/script/api/script_object.hpp +++ b/src/script/api/script_object.hpp @@ -73,6 +73,16 @@ protected: */ static bool DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text = nullptr, Script_SuspendCallbackProc *callback = nullptr); + /** + * Store the latest command executed by the script. + */ + static void SetLastCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd); + + /** + * Check if it's the latest command executed by the script. + */ + static bool CheckLastCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd); + /** * Sets the DoCommand costs counter to a value. */ diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index 5734c2c83..64ae51cf3 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -680,10 +680,12 @@ SQInteger ScriptInstance::GetOpsTillSuspend() return this->engine->GetOpsTillSuspend(); } -void ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +bool ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) { ScriptObject::ActiveInstance active(this); + if (!ScriptObject::CheckLastCommand(tile, p1, p2, cmd)) return false; + ScriptObject::SetLastCommandRes(result.Succeeded()); if (result.Failed()) { @@ -692,6 +694,10 @@ void ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile ScriptObject::IncreaseDoCommandCosts(result.GetCost()); ScriptObject::SetLastCost(result.GetCost()); } + + ScriptObject::SetLastCommand(INVALID_TILE, 0, 0, CMD_END); + + return true; } void ScriptInstance::InsertEvent(class ScriptEvent *event) diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index 653ec3884..dc5b28dfb 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -182,8 +182,10 @@ public: * @param tile The tile on which the command was executed. * @param p1 p1 as given to DoCommandPInternal. * @param p2 p2 as given to DoCommandPInternal. + * @param cmd cmd as given to DoCommandPInternal. + * @return true if we handled result. */ - void DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2); + bool DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd); /** * Insert an event for this script. diff --git a/src/script/script_storage.hpp b/src/script/script_storage.hpp index ef7d81ed7..d06cc9efa 100644 --- a/src/script/script_storage.hpp +++ b/src/script/script_storage.hpp @@ -46,6 +46,11 @@ private: uint last_error; ///< The last error of the command. bool last_command_res; ///< The last result of the command. + TileIndex last_tile; ///< The last tile passed to a command. + uint32 last_p1; ///< The last p1 passed to a command. + uint32 last_p2; ///< The last p2 passed to a command. + uint32 last_cmd; ///< The last cmd passed to a command. + VehicleID new_vehicle_id; ///< The ID of the new Vehicle. SignID new_sign_id; ///< The ID of the new Sign. GroupID new_group_id; ///< The ID of the new Group. @@ -73,6 +78,10 @@ public: last_cost (0), last_error (STR_NULL), last_command_res (true), + last_tile (INVALID_TILE), + last_p1 (0), + last_p2 (0), + last_cmd (CMD_END), new_vehicle_id (0), new_sign_id (0), new_group_id (0), -- cgit v1.2.3-54-g00ecf