diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 5996039c9d..5e0c720f00 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -1292,8 +1292,8 @@ struct AIDebugWindow : public Window { case WID_AID_RELOAD_TOGGLE: if (ai_debug_company == OWNER_DEITY) break; /* First kill the company of the AI, then start a new one. This should start the current AI again */ - Command::Post(0, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0, {}); - Command::Post(0, CCA_NEW_AI | ai_debug_company << 16, 0, {}); + Command::Post(CCA_DELETE, ai_debug_company, CRR_MANUAL, INVALID_CLIENT_ID); + Command::Post(CCA_NEW_AI, ai_debug_company, CRR_NONE, INVALID_CLIENT_ID); break; case WID_AID_SETTINGS: diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 998f75e6bd..f1263f00cd 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -263,11 +263,10 @@ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoff * @param flags type of operation. * @param tile tile of the depot where aircraft is built. * @param e the engine to build. - * @param data unused. * @param[out] ret the vehicle that has been built. * @return the cost of this operation or an error. */ -CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret) +CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret) { const AircraftVehicleInfo *avi = &e->u.air; const Station *st = Station::GetByTile(tile); diff --git a/src/aircraft_cmd.h b/src/aircraft_cmd.h index 719974af7b..df58739a54 100644 --- a/src/aircraft_cmd.h +++ b/src/aircraft_cmd.h @@ -14,6 +14,6 @@ #include "engine_type.h" #include "vehicle_type.h" -CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v); +CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **v); #endif /* AIRCRAFT_CMD_H */ diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 4ba41942c9..6a8937cb65 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -345,7 +345,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic } /* Build the new vehicle */ - cost = Command::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e | (CT_INVALID << 24), 0, {}); + cost = Command::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e, true, CT_INVALID, INVALID_CLIENT_ID); if (cost.Failed()) return cost; Vehicle *new_veh = Vehicle::Get(_new_vehicle_id); @@ -471,11 +471,11 @@ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, b } /* Sell the old vehicle */ - cost.AddCost(Command::Do(flags, 0, old_v->index, 0, {})); + cost.AddCost(Command::Do(flags, 0, old_v->index, false, false, INVALID_CLIENT_ID)); /* If we are not in DC_EXEC undo everything */ if ((flags & DC_EXEC) == 0) { - Command::Do(DC_EXEC, 0, new_v->index, 0, {}); + Command::Do(DC_EXEC, 0, new_v->index, false, false, INVALID_CLIENT_ID); } } @@ -602,7 +602,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon assert(RailVehInfo(wagon->engine_type)->railveh_type == RAILVEH_WAGON); /* Sell wagon */ - [[maybe_unused]] CommandCost ret = Command::Do(DC_EXEC, 0, wagon->index, 0, {}); + [[maybe_unused]] CommandCost ret = Command::Do(DC_EXEC, 0, wagon->index, false, false, INVALID_CLIENT_ID); assert(ret.Succeeded()); new_vehs[i] = nullptr; @@ -634,7 +634,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon /* Sell the vehicle. * Note: This might temporarily construct new trains, so use DC_AUTOREPLACE to prevent * it from failing due to engine limits. */ - cost.AddCost(Command::Do(flags | DC_AUTOREPLACE, 0, w->index, 0, {})); + cost.AddCost(Command::Do(flags | DC_AUTOREPLACE, 0, w->index, false, false, INVALID_CLIENT_ID)); if ((flags & DC_EXEC) != 0) { old_vehs[i] = nullptr; if (i == 0) old_head = nullptr; @@ -665,7 +665,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon if ((flags & DC_EXEC) == 0) { for (int i = num_units - 1; i >= 0; i--) { if (new_vehs[i] != nullptr) { - Command::Do(DC_EXEC, 0, new_vehs[i]->index, 0, {}); + Command::Do(DC_EXEC, 0, new_vehs[i]->index, false, false, INVALID_CLIENT_ID); new_vehs[i] = nullptr; } } @@ -696,12 +696,12 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon } /* Sell the old vehicle */ - cost.AddCost(Command::Do(flags, 0, old_head->index, 0, {})); + cost.AddCost(Command::Do(flags, 0, old_head->index, false, false, INVALID_CLIENT_ID)); } /* If we are not in DC_EXEC undo everything */ if ((flags & DC_EXEC) == 0) { - Command::Do(DC_EXEC, 0, new_head->index, 0, {}); + Command::Do(DC_EXEC, 0, new_head->index, false, false, INVALID_CLIENT_ID); } } } diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 639bab7a9f..ef87699ef8 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1229,7 +1229,7 @@ struct BuildVehicleWindow : Window { if (!this->listview_mode) { /* Query for cost and refitted capacity */ - CommandCost ret = Command::Do(DC_QUERY_COST, this->window_number, this->sel_engine | (cargo << 24), 0, {}); + CommandCost ret = Command::Do(DC_QUERY_COST, this->window_number, this->sel_engine, true, cargo, INVALID_CLIENT_ID); if (ret.Succeeded()) { this->te.cost = ret.GetCost() - e->GetCost(); this->te.capacity = _returned_refit_capacity; @@ -1472,7 +1472,7 @@ struct BuildVehicleWindow : Window { CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; CargoID cargo = this->cargo_filter[this->cargo_filter_criteria]; if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE; - Command::Post(GetCmdBuildVehMsg(this->vehicle_type), callback, this->window_number, sel_eng | (cargo << 24), 0, {}); + Command::Post(GetCmdBuildVehMsg(this->vehicle_type), callback, this->window_number, sel_eng, true, cargo, INVALID_CLIENT_ID); } break; } diff --git a/src/command.cpp b/src/command.cpp index 9997a66fec..08fe7b2659 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -75,15 +75,13 @@ int RecursiveCommandCounter::_counter = 0; * the #CMD_AUTO, #CMD_OFFLINE and #CMD_SERVER values. */ struct CommandInfo { - CommandProc *proc; ///< The procedure to actually executing const char *name; ///< A human readable name for the procedure CommandFlags flags; ///< The (command) flags to that apply to this command CommandType type; ///< The type of command. }; /* Helpers to generate the master command table from the command traits. */ - template -inline constexpr CommandInfo CommandFromTrait() noexcept { return { T::proc, T::name, T::flags, T::type }; }; +inline constexpr CommandInfo CommandFromTrait() noexcept { return { T::name, T::flags, T::type }; }; template inline constexpr auto MakeCommandsFromTraits(std::integer_sequence) noexcept { @@ -101,14 +99,14 @@ static constexpr auto _command_proc_table = MakeCommandsFromTraits(std::make_int /*! - * This function range-checks a cmd, and checks if the cmd is not nullptr + * This function range-checks a cmd. * * @param cmd The integer value of a command * @return true if the command is valid (and got a CommandProc function) */ bool IsValidCommand(Commands cmd) { - return cmd < _command_proc_table.size() && _command_proc_table[cmd].proc != nullptr; + return cmd < _command_proc_table.size(); } /*! diff --git a/src/command_func.h b/src/command_func.h index b69e97b393..e1f958f5bd 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -11,6 +11,7 @@ #define COMMAND_FUNC_H #include "command_type.h" +#include "network/network_type.h" #include "company_type.h" #include "company_func.h" #include "core/backup_type.hpp" @@ -225,6 +226,22 @@ public: } protected: + /** Helper to process a single ClientID argument. */ + template + static inline void SetClientIdHelper(T &data) + { + if constexpr (std::is_same_v) { + if (data == INVALID_CLIENT_ID) data = CLIENT_ID_SERVER; + } + } + + /** Set all invalid ClientID's to the proper value. */ + template + static inline void SetClientIds(Ttuple &values, std::index_sequence) + { + ((SetClientIdHelper(std::get(values))), ...); + } + static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, std::tuple args) { /* Where to show the message? */ @@ -241,8 +258,8 @@ protected: auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags(), tile, err_message, network_command); if (err) return false; - /* Only set p2 when the command does not come from the network. */ - if (!network_command && GetCommandFlags() & CMD_CLIENT_ID && std::get<2>(args) == 0) std::get<2>(args) = CLIENT_ID_SERVER; + /* Only set client IDs when the command does not come from the network. */ + if (!network_command && GetCommandFlags() & CMD_CLIENT_ID) SetClientIds(args, std::index_sequence_for{}); CommandCost res = Execute(err_message, callback, my_cmd, estimate_only, network_command, tile, args); InternalPostResult(res, tile, estimate_only, only_sending, err_message, my_cmd); @@ -254,6 +271,24 @@ protected: return res.Succeeded(); } + /** Helper to process a single ClientID argument. */ + template + static inline bool ClientIdIsSet(T &data) + { + if constexpr (std::is_same_v) { + return data != INVALID_CLIENT_ID; + } else { + return true; + } + } + + /** Check if all ClientID arguments are set to valid values. */ + template + static inline bool AllClientIdsSet(Ttuple &values, std::index_sequence) + { + return (ClientIdIsSet(std::get(values)) && ...); + } + static CommandCost Execute(StringID err_message, CommandCallback *callback, bool my_cmd, bool estimate_only, bool network_command, TileIndex tile, std::tuple args) { /* Prevent recursion; it gives a mess over the network */ @@ -261,10 +296,12 @@ protected: assert(counter.IsTopLevel()); /* Command flags are used internally */ - CommandFlags cmd_flags = GetCommandFlags(); + constexpr CommandFlags cmd_flags = GetCommandFlags(); - /* Make sure p2 is properly set to a ClientID also when processing external commands. */ - assert(!(cmd_flags & CMD_CLIENT_ID) || std::get<2>(args) != 0); + if constexpr ((cmd_flags & CMD_CLIENT_ID) != 0) { + /* Make sure arguments are properly set to a ClientID also when processing external commands. */ + assert(AllClientIdsSet(args, std::index_sequence_for{})); + } Backup cur_company(_current_company, FILE_LINE); if (!InternalExecutePrepTest(cmd_flags, tile, cur_company)) { diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index cf44af25c7..87231f3eb6 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -604,7 +604,7 @@ static bool MaybeStartNewCompany() if (n < (uint)_settings_game.difficulty.max_no_competitors) { /* Send a command to all clients to start up a new AI. * Works fine for Multiplayer and Singleplayer */ - return Command::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {}); + return Command::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID ); } return false; @@ -796,21 +796,16 @@ void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason) /** * Control the companies: add, delete, etc. * @param flags operation to perform - * @param tile unused - * @param p1 various functionality - * - bits 0..15: CompanyCtrlAction - * - bits 16..23: CompanyID - * - bits 24..31: CompanyRemoveReason (with CCA_DELETE) - * @param p2 ClientID - * @param text unused + * @param cca action to perform + * @param company_id company to perform the action on + * @param client_id ClientID * @return the cost of this operation or an error */ -CommandCost CmdCompanyCtrl(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) +CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id) { InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0); - CompanyID company_id = (CompanyID)GB(p1, 16, 8); - switch ((CompanyCtrlAction)GB(p1, 0, 16)) { + switch (cca) { case CCA_NEW: { // Create a new company /* This command is only executed in a multiplayer game */ if (!_networking) return CMD_ERROR; @@ -818,7 +813,6 @@ CommandCost CmdCompanyCtrl(DoCommandFlag flags, TileIndex tile, uint32 p1, uint3 /* Has the network client a correct ClientIndex? */ if (!(flags & DC_EXEC)) return CommandCost(); - ClientID client_id = (ClientID)p2; NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); /* Delete multiplayer progress bar */ @@ -873,7 +867,6 @@ CommandCost CmdCompanyCtrl(DoCommandFlag flags, TileIndex tile, uint32 p1, uint3 } case CCA_DELETE: { // Delete a company - CompanyRemoveReason reason = (CompanyRemoveReason)GB(p1, 24, 8); if (reason >= CRR_END) return CMD_ERROR; /* We can't delete the last existing company in singleplayer mode. */ diff --git a/src/company_cmd.h b/src/company_cmd.h index 0d3e2d2fd6..107a77f29c 100644 --- a/src/company_cmd.h +++ b/src/company_cmd.h @@ -12,7 +12,9 @@ #include "command_type.h" -CommandProc CmdCompanyCtrl; +enum ClientID : uint32; + +CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id); CommandProc CmdGiveMoney; CommandProc CmdRenameCompany; CommandProc CmdRenamePresident; diff --git a/src/company_type.h b/src/company_type.h index de2556b914..8da3133082 100644 --- a/src/company_type.h +++ b/src/company_type.h @@ -52,16 +52,18 @@ struct Company; typedef uint32 CompanyManagerFace; ///< Company manager face bits, info see in company_manager_face.h /** The reason why the company was removed. */ -enum CompanyRemoveReason { +enum CompanyRemoveReason : uint8 { CRR_MANUAL, ///< The company is manually removed. CRR_AUTOCLEAN, ///< The company is removed due to autoclean. CRR_BANKRUPT, ///< The company went belly-up. CRR_END, ///< Sentinel for end. + + CRR_NONE = CRR_MANUAL, ///< Dummy reason for actions that don't need one. }; /** The action to do with CMD_COMPANY_CTRL. */ -enum CompanyCtrlAction { +enum CompanyCtrlAction : uint8 { CCA_NEW, ///< Create a new company. CCA_NEW_AI, ///< Create a new AI company. CCA_DELETE, ///< Delete a company. diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 42a94aa89f..9e244dd439 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -865,7 +865,7 @@ DEF_CONSOLE_CMD(ConResetCompany) } /* It is safe to remove this company */ - Command::Post(0, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0, {}); + Command::Post(CCA_DELETE, index, CRR_MANUAL, INVALID_CLIENT_ID); IConsolePrint(CC_DEFAULT, "Company deleted."); return true; @@ -1222,7 +1222,7 @@ DEF_CONSOLE_CMD(ConStartAI) } /* Start a new AI company */ - Command::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {}); + Command::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID); return true; } @@ -1258,8 +1258,8 @@ DEF_CONSOLE_CMD(ConReloadAI) } /* First kill the company of the AI, then start a new one. This should start the current AI again */ - Command::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {}); - Command::Post(0, CCA_NEW_AI | company_id << 16, 0, {}); + Command::Post(CCA_DELETE, company_id, CRR_MANUAL, INVALID_CLIENT_ID); + Command::Post(CCA_NEW_AI, company_id, CRR_NONE, INVALID_CLIENT_ID); IConsolePrint(CC_DEFAULT, "AI reloaded."); return true; @@ -1296,7 +1296,7 @@ DEF_CONSOLE_CMD(ConStopAI) } /* Now kill the company of the AI. */ - Command::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {}); + Command::Post(CCA_DELETE, company_id, CRR_MANUAL, INVALID_CLIENT_ID); IConsolePrint(CC_DEFAULT, "AI stopped, company deleted."); return true; diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index d316d97ca0..830bdbaeed 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -1026,8 +1026,8 @@ struct DepotWindow : Window { this->sel = INVALID_VEHICLE; this->SetDirty(); - int sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0; - Command::Post(GetCmdSellVehMsg(v->type), v->tile, v->index | sell_cmd << 20 | MAKE_ORDER_BACKUP_FLAG, 0, {}); + bool sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || _ctrl_pressed)); + Command::Post(GetCmdSellVehMsg(v->type), v->tile, v->index, sell_cmd, true, INVALID_CLIENT_ID); break; } diff --git a/src/economy.cpp b/src/economy.cpp index c65d997b80..8bf608a864 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -630,7 +630,7 @@ static void CompanyCheckBankrupt(Company *c) * player we are sure (the above check) that we are not the local * company and thus we won't be moved. */ if (!_networking || _network_server) { - Command::Post(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, {}); + Command::Post(CCA_DELETE, c->index, CRR_BANKRUPT, INVALID_CLIENT_ID); return; } break; diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index cc7cd8336e..1868f5e603 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -840,7 +840,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet * the server will give us a client-id and let us in */ _network_join_status = NETWORK_JOIN_STATUS_REGISTERING; ShowJoinStatusWindow(); - Command::SendNet(STR_NULL, nullptr, _local_company, 0, CCA_NEW, 0, {}); + Command::SendNet(STR_NULL, nullptr, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID); } } else { /* take control over an existing company */ diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index f99c71b97c..58de73b198 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -89,15 +89,17 @@ static CommandCallback * const _callback_table[] = { template static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data); template static void UnpackNetworkCommand(const CommandPacket *cp); +template static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id); struct CommandDispatch { CommandDataBuffer(*Sanitize)(const CommandDataBuffer &); + void (*ReplaceClientId)(CommandPacket &, ClientID); void (*Unpack)(const CommandPacket *); }; template inline constexpr auto MakeDispatchTable(std::integer_sequence) noexcept { - return std::array{{ { &SanitizeCmdStrings(i)>, &UnpackNetworkCommand(i)> }... }}; + return std::array{{ { &SanitizeCmdStrings(i)>, &NetworkReplaceCommandClientId(i)>, &UnpackNetworkCommand(i)> }... }}; } static constexpr auto _cmd_dispatch = MakeDispatchTable(std::make_integer_sequence, CMD_END>{}); @@ -383,6 +385,35 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp) p->Send_uint8 (callback); } +/** Helper to process a single ClientID argument. */ +template +static inline void SetClientIdHelper(T &data, [[maybe_unused]] ClientID client_id) +{ + if constexpr (std::is_same_v) { + data = client_id; + } +} + +/** Set all invalid ClientID's to the proper value. */ +template +static inline void SetClientIds(Ttuple &values, ClientID client_id, std::index_sequence) +{ + ((SetClientIdHelper(std::get(values), client_id)), ...); +} + +template +static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id) +{ + /* Unpack command parameters. */ + auto params = EndianBufferReader::ToValue::Args>(cp.data); + + /* Insert client id. */ + SetClientIds(params, client_id, std::make_index_sequence>{}); + + /* Repack command parameters. */ + cp.data = EndianBufferWriter::FromValue(params); +} + /** * Insert a client ID into the command data in a command packet. * @param cp Command packet to modify. @@ -390,14 +421,7 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp) */ void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id) { - /* Unpack command parameters. */ - auto params = EndianBufferReader::ToValue>(cp.data); - - /* Insert client id. */ - std::get<2>(params) = client_id; - - /* Repack command parameters. */ - cp.data = EndianBufferWriter::FromValue(params); + _cmd_dispatch[cp.cmd].ReplaceClientId(cp, client_id); } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index ac12402ea5..0c7e361dd4 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1396,7 +1396,7 @@ static void AdminCompanyResetCallback(Window *w, bool confirmed) { if (confirmed) { if (NetworkCompanyHasClients(_admin_company_id)) return; - Command::Post(0, CCA_DELETE | _admin_company_id << 16 | CRR_MANUAL << 24, 0, {}); + Command::Post(CCA_DELETE, _admin_company_id, CRR_MANUAL, INVALID_CLIENT_ID); } } @@ -1536,9 +1536,9 @@ private: static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID company_id) { if (_network_server) { - Command::Post(0, CCA_NEW, _network_own_client_id, {}); + Command::Post(CCA_NEW, INVALID_COMPANY, CRR_NONE, _network_own_client_id); } else { - Command::SendNet(STR_NULL, nullptr, _local_company, 0, CCA_NEW, 0, {}); + Command::SendNet(STR_NULL, nullptr, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID); } } diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index ad891aef8c..197d398bf6 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1050,15 +1050,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet * to match the company in the packet. If it doesn't, the client has done * something pretty naughty (or a bug), and will be kicked */ - uint32 company_p1 = cp.cmd == CMD_COMPANY_CTRL ? std::get<1>(EndianBufferReader::ToValue::Args>(cp.data)) : 0; - if (!(cp.cmd == CMD_COMPANY_CTRL && company_p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) { + CompanyCtrlAction cca = cp.cmd == CMD_COMPANY_CTRL ? std::get<0>(EndianBufferReader::ToValue::Args>(cp.data)) : CCA_NEW; + if (!(cp.cmd == CMD_COMPANY_CTRL && cca == CCA_NEW && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) { IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a command as another company {}.", ci->client_playas + 1, this->GetClientIP(), cp.company + 1); return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH); } if (cp.cmd == CMD_COMPANY_CTRL) { - if (company_p1 != 0 || cp.company != COMPANY_SPECTATOR) { + if (cca != CCA_NEW || cp.company != COMPANY_SPECTATOR) { return this->SendError(NETWORK_ERROR_CHEATER); } @@ -1556,7 +1556,7 @@ static void NetworkAutoCleanCompanies() /* Is the company empty for autoclean_unprotected-months, and is there no protection? */ if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && _network_company_states[c->index].password.empty()) { /* Shut the company down */ - Command::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {}); + Command::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID); IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no password.", c->index + 1); } /* Is the company empty for autoclean_protected-months, and there is a protection? */ @@ -1570,7 +1570,7 @@ static void NetworkAutoCleanCompanies() /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */ if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) { /* Shut the company down */ - Command::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {}); + Command::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID); IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1); } } else { diff --git a/src/order_backup.cpp b/src/order_backup.cpp index 6bececc0cc..69ae6507db 100644 --- a/src/order_backup.cpp +++ b/src/order_backup.cpp @@ -144,15 +144,13 @@ void OrderBackup::DoRestore(Vehicle *v) * Clear an OrderBackup * @param flags For command. * @param tile Tile related to the to-be-cleared OrderBackup. - * @param p1 Unused. - * @param p2 User that had the OrderBackup. - * @param text Unused. + * @param user_id User that had the OrderBackup. * @return The cost of this operation or an error. */ -CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) +CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, ClientID user_id) { /* No need to check anything. If the tile or user don't exist we just ignore it. */ - if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2); + if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, user_id); return CommandCost(); } @@ -171,7 +169,7 @@ CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, uint32 p1, /* If it's not a backup of us, ignore it. */ if (ob->user != user) continue; - Command::Post(0, 0, user, {}); + Command::Post(0, static_cast(user)); return; } } @@ -200,7 +198,7 @@ CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, uint32 p1, /* We need to circumvent the "prevention" from this command being executed * while the game is paused, so use the internal method. Nor do we want * this command to get its cost estimated when shift is pressed. */ - Command::Unsafe(STR_NULL, nullptr, true, false, ob->tile, CommandTraits::Args{ ob->tile, 0, user, {} }); + Command::Unsafe(STR_NULL, nullptr, true, false, ob->tile, CommandTraits::Args{ ob->tile, static_cast(user) }); } else { /* The command came from the game logic, i.e. the clearing of a tile. * In that case we have no need to actually sync this, just do it. */ diff --git a/src/order_cmd.h b/src/order_cmd.h index 606cbef605..fa3424ce42 100644 --- a/src/order_cmd.h +++ b/src/order_cmd.h @@ -19,7 +19,7 @@ CommandProc CmdInsertOrder; CommandProc CmdOrderRefit; CommandProc CmdCloneOrder; CommandProc CmdMoveOrder; -CommandProc CmdClearOrderBackup; +CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, ClientID user_id); DEF_CMD_TRAIT(CMD_MODIFY_ORDER, CmdModifyOrder, 0, CMDT_ROUTE_MANAGEMENT) DEF_CMD_TRAIT(CMD_SKIP_TO_ORDER, CmdSkipToOrder, 0, CMDT_ROUTE_MANAGEMENT) diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index efe45c507d..a6442430e0 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -254,11 +254,10 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length) * @param flags type of operation. * @param tile tile of the depot where road vehicle is built. * @param e the engine to build. - * @param data unused. * @param[out] ret the vehicle that has been built. * @return the cost of this operation or an error. */ -CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret) +CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret) { /* Check that the vehicle can drive on the road in question */ RoadType rt = e->u.road.roadtype; diff --git a/src/roadveh_cmd.h b/src/roadveh_cmd.h index ca99dee3ab..94aaee743f 100644 --- a/src/roadveh_cmd.h +++ b/src/roadveh_cmd.h @@ -14,7 +14,7 @@ #include "engine_type.h" #include "vehicle_type.h" -CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v); +CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **v); CommandProc CmdTurnRoadVeh; diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp index 26da500c4c..8d9be14c46 100644 --- a/src/script/api/script_object.hpp +++ b/src/script/api/script_object.hpp @@ -347,6 +347,22 @@ namespace ScriptObjectInternal { { ((SanitizeSingleStringHelper(std::get(values))), ...); } + + /** Helper to process a single ClientID argument. */ + template + static inline void SetClientIdHelper(T &data) + { + if constexpr (std::is_same_v) { + if (data == INVALID_CLIENT_ID) data = (ClientID)UINT32_MAX; + } + } + + /** Set all invalid ClientID's to the proper value. */ + template + static inline void SetClientIds(Ttuple &values, std::index_sequence) + { + ((SetClientIdHelper(std::get(values))), ...); + } } template @@ -364,8 +380,8 @@ bool ScriptObject::ScriptDoCommandHelper(args); } - /* Only set p2 when the command does not come from the network. */ - if ((::GetCommandFlags() & CMD_CLIENT_ID) != 0 && std::get<2>(args) == 0) std::get<2>(args) = UINT32_MAX; + /* Only set ClientID parameters when the command does not come from the network. */ + if constexpr ((::GetCommandFlags() & CMD_CLIENT_ID) != 0) ScriptObjectInternal::SetClientIds(args, std::index_sequence_for{}); /* Store the command for command callback validation. */ if (!estimate_only && networking) ScriptObject::SetLastCommand(tile, EndianBufferWriter::FromValue(args), Tcmd); diff --git a/src/script/api/script_vehicle.cpp b/src/script/api/script_vehicle.cpp index d245f41327..3da5739eeb 100644 --- a/src/script/api/script_vehicle.cpp +++ b/src/script/api/script_vehicle.cpp @@ -72,7 +72,7 @@ EnforcePreconditionCustomError(VEHICLE_INVALID, !ScriptGameSettings::IsDisabledVehicleType((ScriptVehicle::VehicleType)type), ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); - if (!ScriptObject::Command::Do(&ScriptInstance::DoCommandReturnVehicleID, depot, engine_id | (cargo << 24), 0, {})) return VEHICLE_INVALID; + if (!ScriptObject::Command::Do(&ScriptInstance::DoCommandReturnVehicleID, depot, engine_id, true, cargo, INVALID_CLIENT_ID)) return VEHICLE_INVALID; /* In case of test-mode, we return VehicleID 0 */ return 0; @@ -94,7 +94,7 @@ if (!ScriptEngine::IsBuildable(engine_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; - CommandCost res = ::Command::Do(DC_QUERY_COST, depot, engine_id | (cargo << 24), 0, {}); + CommandCost res = ::Command::Do(DC_QUERY_COST, depot, engine_id, true, cargo, INVALID_CLIENT_ID); return res.Succeeded() ? _returned_refit_capacity : -1; } @@ -162,7 +162,7 @@ EnforcePrecondition(false, IsValidVehicle(vehicle_id)); const Vehicle *v = ::Vehicle::Get(vehicle_id); - return ScriptObject::Command::Do(0, vehicle_id | (v->type == VEH_TRAIN ? 1 : 0) << 20, 0, {}); + return ScriptObject::Command::Do(0, vehicle_id, v->type == VEH_TRAIN, false, INVALID_CLIENT_ID); } /* static */ bool ScriptVehicle::_SellWagonInternal(VehicleID vehicle_id, int wagon, bool sell_attached_wagons) @@ -174,7 +174,7 @@ const Train *v = ::Train::Get(vehicle_id); while (wagon-- > 0) v = v->GetNextUnit(); - return ScriptObject::Command::Do(0, v->index | (sell_attached_wagons ? 1 : 0) << 20, 0, {}); + return ScriptObject::Command::Do(0, v->index, sell_attached_wagons, false, INVALID_CLIENT_ID); } /* static */ bool ScriptVehicle::SellWagon(VehicleID vehicle_id, int wagon) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 0e0bccce0f..2729030d31 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -841,11 +841,10 @@ void Ship::SetDestTile(TileIndex tile) * @param flags type of operation. * @param tile tile of the depot where ship is built. * @param e the engine to build. - * @param data unused. * @param[out] ret the vehicle that has been built. * @return the cost of this operation or an error. */ -CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret) +CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret) { tile = GetShipDepotNorthTile(tile); if (flags & DC_EXEC) { diff --git a/src/ship_cmd.h b/src/ship_cmd.h index 8738f54207..b17885e371 100644 --- a/src/ship_cmd.h +++ b/src/ship_cmd.h @@ -14,6 +14,6 @@ #include "engine_type.h" #include "vehicle_type.h" -CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v); +CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **v); #endif /* SHIP_CMD_H */ diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index a86e835bd3..d2517d65ba 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -718,11 +718,11 @@ static void AddRearEngineToMultiheadedTrain(Train *v) * @param flags type of operation. * @param tile tile of the depot where rail-vehicle is built. * @param e the engine to build. - * @param data bit 0 prevents any free cars from being added to the train. + * @param free_cars add any free cars to the train. * @param[out] ret the vehicle that has been built. * @return the cost of this operation or an error. */ -CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret) +CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, bool free_cars, Vehicle **ret) { const RailVehicleInfo *rvi = &e->u.rail; @@ -789,7 +789,7 @@ CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engin v->ConsistChanged(CCF_ARRANGE); UpdateTrainGroupID(v); - if (!HasBit(data, 0) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle + if (free_cars && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle NormalizeTrainVehInDepot(v); } @@ -1357,18 +1357,16 @@ CommandCost CmdMoveRailVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, u * Sell a (single) train wagon/engine. * @param flags type of operation * @param t the train wagon to sell - * @param data the selling mode - * - data = 0: only sell the single dragged wagon/engine (and any belonging rear-engines) - * - data = 1: sell the vehicle and all vehicles following it in the chain - * if the wagon is dragged, don't delete the possibly belonging rear-engine to some front + * @param sell_chain the selling mode + * - sell_chain = false: only sell the single dragged wagon/engine (and any belonging rear-engines) + * - sell_chain = true: sell the vehicle and all vehicles following it in the chain + * if the wagon is dragged, don't delete the possibly belonging rear-engine to some front + * @param backup_order make order backup? * @param user the user for the order backup. * @return the cost of this operation or an error */ -CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user) +CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user) { - /* Sell a chain of vehicles or not? */ - bool sell_chain = HasBit(data, 0); - Train *v = Train::From(t)->GetFirstEnginePart(); Train *first = v->First(); @@ -1418,7 +1416,7 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3 /* Copy other important data from the front engine */ new_head->CopyVehicleConfigAndStatistics(first); GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit - } else if (v->IsPrimaryVehicle() && data & (MAKE_ORDER_BACKUP_FLAG >> 20)) { + } else if (v->IsPrimaryVehicle() && backup_order) { OrderBackup::Backup(v, user); } diff --git a/src/train_cmd.h b/src/train_cmd.h index 7b286e9983..4a7e5036ec 100644 --- a/src/train_cmd.h +++ b/src/train_cmd.h @@ -14,8 +14,8 @@ #include "engine_type.h" #include "vehicle_type.h" -CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v); -CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *v, uint16 data, uint32 user); +CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, bool free_cars, Vehicle **ret); +CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user); CommandProc CmdMoveRailVehicle; CommandProc CmdForceTrainProceed; diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index aeaefe68f4..f25a3cdd3e 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -79,15 +79,13 @@ const StringID _send_to_depot_msg_table[] = { * Build a vehicle. * @param flags for command * @param tile tile of depot where the vehicle is built - * @param p1 various bitstuffed data - * bits 0-15: vehicle type being built. - * bits 16-23: vehicle type specific bits passed on to the vehicle build functions. - * bits 24-31: refit cargo type. - * @param p2 User - * @param text unused + * @param eid vehicle type being built. + * @param use_free_vehicles use free vehicles when building the vehicle. + * @param cargo refit cargo type. + * @param client_id User * @return the cost of this operation or an error */ -CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) +CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoID cargo, ClientID client_id) { /* Elementary check for valid location. */ if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR; @@ -95,11 +93,9 @@ CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint VehicleType type = GetDepotVehicleType(tile); /* Validate the engine type. */ - EngineID eid = GB(p1, 0, 16); if (!IsEngineBuildable(eid, type, _current_company)) return_cmd_error(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + type); /* Validate the cargo type. */ - CargoID cargo = GB(p1, 24, 8); if (cargo >= NUM_CARGO && cargo != CT_INVALID) return CMD_ERROR; const Engine *e = Engine::Get(eid); @@ -140,10 +136,10 @@ CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint Vehicle *v = nullptr; switch (type) { - case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(subflags, tile, e, GB(p1, 16, 8), &v)); break; - case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(subflags, tile, e, GB(p1, 16, 8), &v)); break; - case VEH_SHIP: value.AddCost(CmdBuildShip (subflags, tile, e, GB(p1, 16, 8), &v)); break; - case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (subflags, tile, e, GB(p1, 16, 8), &v)); break; + case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(subflags, tile, e, use_free_vehicles, &v)); break; + case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(subflags, tile, e, &v)); break; + case VEH_SHIP: value.AddCost(CmdBuildShip (subflags, tile, e, &v)); break; + case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (subflags, tile, e, &v)); break; default: NOT_REACHED(); // Safe due to IsDepotTile() } @@ -176,14 +172,14 @@ CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint if (v->IsPrimaryVehicle()) { GroupStatistics::CountVehicle(v, 1); - if (!(subflags & DC_AUTOREPLACE)) OrderBackup::Restore(v, p2); + if (!(subflags & DC_AUTOREPLACE)) OrderBackup::Restore(v, client_id); } } /* If we are not in DC_EXEC undo everything */ if (flags != subflags) { - Command::Do(DC_EXEC, 0, v->index, 0, {}); + Command::Do(DC_EXEC, 0, v->index, false, false, INVALID_CLIENT_ID); } } @@ -197,17 +193,16 @@ CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint * Sell a vehicle. * @param tile unused. * @param flags for command. - * @param p1 various bitstuffed data. - * bits 0-19: vehicle ID being sold. - * bits 20-30: vehicle type specific bits passed on to the vehicle build functions. - * bit 31: make a backup of the vehicle's order (if an engine). - * @param p2 User. + * @aram v_id vehicle ID being sold. + * @param sell_chain sell the vehicle and all vehicles following it in the chain. + * @param backup_order make a backup of the vehicle's order (if an engine). + * @param client_id User. * @param text unused. * @return the cost of this operation or an error. */ -CommandCost CmdSellVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) +CommandCost CmdSellVehicle(DoCommandFlag flags, TileIndex tile, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id) { - Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); + Vehicle *v = Vehicle::GetIfValid(v_id); if (v == nullptr) return CMD_ERROR; Vehicle *front = v->First(); @@ -220,22 +215,22 @@ CommandCost CmdSellVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint3 if (!front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); /* Can we actually make the order backup, i.e. are there enough orders? */ - if (p1 & MAKE_ORDER_BACKUP_FLAG && + if (backup_order && front->orders.list != nullptr && !front->orders.list->IsShared() && !Order::CanAllocateItem(front->orders.list->GetNumOrders())) { /* Only happens in exceptional cases when there aren't enough orders anyhow. * Thus it should be safe to just drop the orders in that case. */ - p1 &= ~MAKE_ORDER_BACKUP_FLAG; + backup_order = false; } if (v->type == VEH_TRAIN) { - ret = CmdSellRailWagon(flags, v, GB(p1, 20, 12), p2); + ret = CmdSellRailWagon(flags, v, sell_chain, backup_order, client_id); } else { ret = CommandCost(EXPENSES_NEW_VEHICLES, -front->value); if (flags & DC_EXEC) { - if (front->IsPrimaryVehicle() && p1 & MAKE_ORDER_BACKUP_FLAG) OrderBackup::Backup(front, p2); + if (front->IsPrimaryVehicle() && backup_order) OrderBackup::Backup(front, client_id); delete front; } } @@ -694,7 +689,7 @@ CommandCost CmdDepotSellAllVehicles(DoCommandFlag flags, TileIndex tile, uint32 CommandCost last_error = CMD_ERROR; bool had_success = false; for (uint i = 0; i < list.size(); i++) { - CommandCost ret = Command::Do(flags, tile, list[i]->index | (1 << 20), 0, {}); + CommandCost ret = Command::Do(flags, tile, list[i]->index, true, false, INVALID_CLIENT_ID); if (ret.Succeeded()) { cost.AddCost(ret); had_success = true; @@ -872,11 +867,11 @@ CommandCost CmdCloneVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint DoCommandFlag build_flags = flags; if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE; - CommandCost cost = Command::Do(build_flags, tile, v->engine_type | (1 << 16) | (CT_INVALID << 24), 0, {}); + CommandCost cost = Command::Do(build_flags, tile, v->engine_type, false, CT_INVALID, INVALID_CLIENT_ID); if (cost.Failed()) { /* Can't build a part, then sell the stuff we already made; clear up the mess */ - if (w_front != nullptr) Command::Do(flags, w_front->tile, w_front->index | (1 << 20), 0, {}); + if (w_front != nullptr) Command::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID); return cost; } @@ -896,8 +891,8 @@ CommandCost CmdCloneVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint if (result.Failed()) { /* The train can't be joined to make the same consist as the original. * Sell what we already made (clean up) and return an error. */ - Command::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {}); - Command::Do(flags, w_front->tile, w->index | 1 << 20, 0, {}); + Command::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID); + Command::Do(flags, w_front->tile, w->index, true, false, INVALID_CLIENT_ID); return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE } } else { @@ -978,7 +973,7 @@ CommandCost CmdCloneVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint CommandCost result = Command::Do(flags, 0, w_front->index | (p2 & 1 ? CO_SHARE : CO_COPY) << 30, v_front->index, {}); if (result.Failed()) { /* The vehicle has already been bought, so now it must be sold again. */ - Command::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {}); + Command::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID); return result; } @@ -989,7 +984,7 @@ CommandCost CmdCloneVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint * check whether the company has enough money manually. */ if (!CheckCompanyHasMoney(total_cost)) { /* The vehicle has already been bought, so now it must be sold again. */ - Command::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {}); + Command::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID); return total_cost; } } diff --git a/src/vehicle_cmd.h b/src/vehicle_cmd.h index e6872e838b..98444033cc 100644 --- a/src/vehicle_cmd.h +++ b/src/vehicle_cmd.h @@ -12,8 +12,8 @@ #include "command_type.h" -CommandProc CmdBuildVehicle; -CommandProc CmdSellVehicle; +CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoID cargo, ClientID client_id); +CommandCost CmdSellVehicle(DoCommandFlag flags, TileIndex tile, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id); CommandProc CmdRefitVehicle; CommandProc CmdSendVehicleToDepot; CommandProc CmdChangeServiceInt;