Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #7188: check the validity of command callback for scripts #7701

Merged
merged 2 commits into from Sep 7, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -251,8 +251,9 @@ ScriptInfo *AIInstance::FindLibrary(const char *library, int version)
* @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.
*/
void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
/*
* The company might not exist anymore. Check for this.
@@ -263,8 +264,9 @@ void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
const Company *c = Company::GetIfValid(_current_company);
if (c == nullptr || c->ai_instance == nullptr) return;

c->ai_instance->DoCommandCallback(result, tile, p1, p2);
c->ai_instance->Continue();
if (c->ai_instance->DoCommandCallback(result, tile, p1, p2, cmd)) {
c->ai_instance->Continue();
}
}

CommandCallback *AIInstance::GetDoCommandCallback()
@@ -42,7 +42,7 @@ static void ShowBuildAirportPicker(Window *parent);

SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout);

void CcBuildAirport(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcBuildAirport(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

@@ -58,8 +58,9 @@ typedef GUIList<BuildBridgeData> GUIBridgeList; ///< List of bridges, used in #B
* - p2 = (bit 0- 7) - bridge type (hi bh)
* - p2 = (bit 8-13) - rail type or road types.
* - p2 = (bit 15-16) - transport type.
* @param cmd unused
*/
void CcBuildBridge(const CommandCost &result, TileIndex end_tile, uint32 p1, uint32 p2)
void CcBuildBridge(const CommandCost &result, TileIndex end_tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;
if (_settings_client.sound.confirm) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, end_tile);
@@ -598,7 +598,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
}

if (!estimate_only && !only_sending && callback != nullptr) {
callback(res, tile, p1, p2);
callback(res, tile, p1, p2, cmd);
}

return res.Succeeded();
@@ -469,7 +469,7 @@ struct Command {
* @param p1 Additional data of the command
* @see CommandProc
*/
typedef void CommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2);
typedef void CommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd);

/**
* Structure for buffering the build command when selecting a station to join.
@@ -117,8 +117,9 @@ extern void DepotSortList(VehicleList *list);
* @param tile unused
* @param p1 unused
* @param p2 unused
* @param cmd unused
*/
void CcCloneVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcCloneVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

@@ -40,15 +40,15 @@ static void ShowBuildDocksDepotPicker(Window *parent);

static Axis _ship_depot_direction;

void CcBuildDocks(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcBuildDocks(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

if (_settings_client.sound.confirm) SndPlayTileFx(SND_02_SPLAT_WATER, tile);
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
}

void CcPlaySound_SPLAT_WATER(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcPlaySound_SPLAT_WATER(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_02_SPLAT_WATER, tile);
}
@@ -257,11 +257,13 @@ void GameInstance::Died()
* @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.
*/
void CcGame(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcGame(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
Game::GetGameInstance()->DoCommandCallback(result, tile, p1, p2);
Game::GetGameInstance()->Continue();
if (Game::GetGameInstance()->DoCommandCallback(result, tile, p1, p2, cmd)) {
Game::GetGameInstance()->Continue();
}
}

CommandCallback *GameInstance::GetDoCommandCallback()
@@ -1046,9 +1046,10 @@ static inline VehicleGroupWindow *FindVehicleGroupWindow(VehicleType vt, Owner o
* @param tile Unused.
* @param p1 Vehicle type.
* @param p2 Unused.
* @param cmd Unused.
* @see CmdCreateGroup
*/
void CcCreateGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcCreateGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;
assert(p1 <= VEH_AIRCRAFT);
@@ -1063,13 +1064,14 @@ void CcCreateGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32
* @param tile Unused.
* @param p1 Unused.
* @param p2 Bit 0-19: Vehicle ID.
* @param cmd Unused.
*/
void CcAddVehicleNewGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcAddVehicleNewGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;
assert(Vehicle::IsValidID(GB(p2, 0, 20)));

CcCreateGroup(result, 0, Vehicle::Get(GB(p2, 0, 20))->type, 0);
CcCreateGroup(result, 0, Vehicle::Get(GB(p2, 0, 20))->type, 0, cmd);
}

/**
@@ -222,8 +222,9 @@ void SortIndustryTypes()
* @param tile Tile where the industry is placed.
* @param p1 Additional data of the #CMD_BUILD_INDUSTRY command.
* @param p2 Additional data of the #CMD_BUILD_INDUSTRY command.
* @param cmd Unused.
*/
void CcBuildIndustry(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcBuildIndustry(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded()) return;

@@ -51,7 +51,7 @@
static int _rename_id = 1;
static int _rename_what = -1;

void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed() || !_settings_game.economy.give_money) return;

@@ -115,7 +115,7 @@ bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyl
}


void CcPlaySound_EXPLOSION(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcPlaySound_EXPLOSION(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_12_EXPLOSION, tile);
}
@@ -86,7 +86,7 @@ static bool IsStationAvailable(const StationSpec *statspec)
return Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res);
}

void CcPlaySound_SPLAT_RAIL(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcPlaySound_SPLAT_RAIL(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile);
}
@@ -129,7 +129,7 @@ static const DiagDirection _place_depot_extra_dir[12] = {
DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE,
};

void CcRailDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcRailDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

@@ -170,7 +170,7 @@ static void PlaceRail_Waypoint(TileIndex tile)
}
}

void CcStation(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcStation(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

@@ -272,7 +272,7 @@ static void PlaceRail_Bridge(TileIndex tile, Window *w)
}

/** Command callback for building a tunnel */
void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded()) {
if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile);
@@ -68,7 +68,7 @@ static RoadType _cur_roadtype;
static DiagDirection _road_depot_orientation;
static DiagDirection _road_station_picker_orientation;

void CcPlaySound_SPLAT_OTHER(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcPlaySound_SPLAT_OTHER(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile);
}
@@ -96,8 +96,9 @@ static void PlaceRoad_Bridge(TileIndex tile, Window *w)
* @param p1 bit 0-3 railtype or roadtypes
* bit 8-9 transport type
* @param p2 unused
* @param cmd unused
*/
void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p1, uint32 p2)
void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded()) {
if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, start_tile);
@@ -130,7 +131,7 @@ void ConnectRoadToStructure(TileIndex tile, DiagDirection direction)
}
}

void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

@@ -153,9 +154,10 @@ void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2
* bit 3: #Axis of the road for drive-through stops.
* bit 5..9: The roadtype.
* bit 16..31: Station ID to join (NEW_STATION if build new one).
* @param cmd Unused.
* @see CmdBuildRoadStop
*/
void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

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

@@ -73,6 +73,16 @@ friend class ScriptController;
*/
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.
*/
@@ -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)
@@ -182,8 +182,10 @@ class ScriptInstance {
* @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.
@@ -46,6 +46,11 @@ friend class ScriptObject;
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 @@ friend class ScriptObject;
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),
@@ -117,8 +117,9 @@ CommandCost CmdRenameSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
* @param tile unused
* @param p1 unused
* @param p2 unused
* @param cmd unused
*/
void CcPlaceSign(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcPlaceSign(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

@@ -40,7 +40,7 @@

#include "safeguards.h"

void CcTerraform(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcTerraform(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded()) {
if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile);
@@ -1050,15 +1050,15 @@ void ShowTownDirectory()
new TownDirectoryWindow(&_town_directory_desc);
}

void CcFoundTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcFoundTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Failed()) return;

if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile);
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
}

void CcFoundRandomTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
void CcFoundRandomTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(_new_town_id)->xy);
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.