summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2021-11-02 21:34:39 +0100
committerMichael Lutz <michi@icosahedron.de>2021-12-16 22:28:32 +0100
commit4f3ea3907e23428461c626b6c861d834b358bc9f (patch)
treef60f17d713ed155a738adb469eed7f4262ffbe3c
parentccefa76a4686581b8d1a9bd13d7d754807a9f8d1 (diff)
downloadopenttd-4f3ea3907e23428461c626b6c861d834b358bc9f.tar.xz
Codechange: Un-bitstuff commands taking a ClientID (i.e. CMD_CLIENT_ID).
-rw-r--r--src/ai/ai_gui.cpp4
-rw-r--r--src/aircraft_cmd.cpp3
-rw-r--r--src/aircraft_cmd.h2
-rw-r--r--src/autoreplace_cmd.cpp16
-rw-r--r--src/build_vehicle_gui.cpp4
-rw-r--r--src/command.cpp8
-rw-r--r--src/command_func.h47
-rw-r--r--src/company_cmd.cpp19
-rw-r--r--src/company_cmd.h4
-rw-r--r--src/company_type.h6
-rw-r--r--src/console_cmds.cpp10
-rw-r--r--src/depot_gui.cpp4
-rw-r--r--src/economy.cpp2
-rw-r--r--src/network/network_client.cpp2
-rw-r--r--src/network/network_command.cpp42
-rw-r--r--src/network/network_gui.cpp6
-rw-r--r--src/network/network_server.cpp10
-rw-r--r--src/order_backup.cpp12
-rw-r--r--src/order_cmd.h2
-rw-r--r--src/roadveh_cmd.cpp3
-rw-r--r--src/roadveh_cmd.h2
-rw-r--r--src/script/api/script_object.hpp20
-rw-r--r--src/script/api/script_vehicle.cpp8
-rw-r--r--src/ship_cmd.cpp3
-rw-r--r--src/ship_cmd.h2
-rw-r--r--src/train_cmd.cpp22
-rw-r--r--src/train_cmd.h4
-rw-r--r--src/vehicle_cmd.cpp61
-rw-r--r--src/vehicle_cmd.h4
29 files changed, 196 insertions, 136 deletions
diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp
index 5996039c9..5e0c720f0 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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0, {});
- Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | ai_debug_company << 16, 0, {});
+ Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, ai_debug_company, CRR_MANUAL, INVALID_CLIENT_ID);
+ Command<CMD_COMPANY_CTRL>::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 998f75e6b..f1263f00c 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 719974af7..df58739a5 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 4ba41942c..6a8937cb6 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<CMD_BUILD_VEHICLE>::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e | (CT_INVALID << 24), 0, {});
+ cost = Command<CMD_BUILD_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(flags, 0, old_v->index, 0, {}));
+ cost.AddCost(Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_v->index, 0, {});
+ Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, wagon->index, 0, {});
+ [[maybe_unused]] CommandCost ret = Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(flags | DC_AUTOREPLACE, 0, w->index, 0, {}));
+ cost.AddCost(Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_vehs[i]->index, 0, {});
+ Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(flags, 0, old_head->index, 0, {}));
+ cost.AddCost(Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_head->index, 0, {});
+ Command<CMD_SELL_VEHICLE>::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 639bab7a9..ef87699ef 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<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, this->window_number, this->sel_engine | (cargo << 24), 0, {});
+ CommandCost ret = Command<CMD_BUILD_VEHICLE>::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<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), callback, this->window_number, sel_eng | (cargo << 24), 0, {});
+ Command<CMD_BUILD_VEHICLE>::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 9997a66fe..08fe7b265 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 <typename T>
-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<typename T, T... i>
inline constexpr auto MakeCommandsFromTraits(std::integer_sequence<T, i...>) 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 b69e97b39..e1f958f5b 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 <class T>
+ static inline void SetClientIdHelper(T &data)
+ {
+ if constexpr (std::is_same_v<ClientID, T>) {
+ if (data == INVALID_CLIENT_ID) data = CLIENT_ID_SERVER;
+ }
+ }
+
+ /** Set all invalid ClientID's to the proper value. */
+ template<class Ttuple, size_t... Tindices>
+ static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
+ {
+ ((SetClientIdHelper(std::get<Tindices>(values))), ...);
+ }
+
static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, std::tuple<Targs...> args)
{
/* Where to show the message? */
@@ -241,8 +258,8 @@ protected:
auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags<Tcmd>(), 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<Tcmd>() & 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<Tcmd>() & CMD_CLIENT_ID) SetClientIds(args, std::index_sequence_for<Targs...>{});
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 <class T>
+ static inline bool ClientIdIsSet(T &data)
+ {
+ if constexpr (std::is_same_v<ClientID, T>) {
+ return data != INVALID_CLIENT_ID;
+ } else {
+ return true;
+ }
+ }
+
+ /** Check if all ClientID arguments are set to valid values. */
+ template<class Ttuple, size_t... Tindices>
+ static inline bool AllClientIdsSet(Ttuple &values, std::index_sequence<Tindices...>)
+ {
+ return (ClientIdIsSet(std::get<Tindices>(values)) && ...);
+ }
+
static CommandCost Execute(StringID err_message, CommandCallback *callback, bool my_cmd, bool estimate_only, bool network_command, TileIndex tile, std::tuple<Targs...> 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<Tcmd>();
+ constexpr CommandFlags cmd_flags = GetCommandFlags<Tcmd>();
- /* 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<Targs...>{}));
+ }
Backup<CompanyID> 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 cf44af25c..87231f3eb 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<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {});
+ return Command<CMD_COMPANY_CTRL>::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 0d3e2d2fd..107a77f29 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 de2556b91..8da313308 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 42a94aa89..9e244dd43 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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0, {});
+ Command<CMD_COMPANY_CTRL>::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<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {});
+ Command<CMD_COMPANY_CTRL>::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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {});
- Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | company_id << 16, 0, {});
+ Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, company_id, CRR_MANUAL, INVALID_CLIENT_ID);
+ Command<CMD_COMPANY_CTRL>::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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {});
+ Command<CMD_COMPANY_CTRL>::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 d316d97ca..830bdbaee 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<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::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 c65d997b8..8bf608a86 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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, {});
+ Command<CMD_COMPANY_CTRL>::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 cc7cd8336..1868f5e60 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<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, 0, CCA_NEW, 0, {});
+ Command<CMD_COMPANY_CTRL>::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 f99c71b97..58de73b19 100644
--- a/src/network/network_command.cpp
+++ b/src/network/network_command.cpp
@@ -89,15 +89,17 @@ static CommandCallback * const _callback_table[] = {
template <Commands Tcmd> static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data);
template <Commands Tcmd> static void UnpackNetworkCommand(const CommandPacket *cp);
+template <Commands Tcmd> static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id);
struct CommandDispatch {
CommandDataBuffer(*Sanitize)(const CommandDataBuffer &);
+ void (*ReplaceClientId)(CommandPacket &, ClientID);
void (*Unpack)(const CommandPacket *);
};
template<typename T, T... i>
inline constexpr auto MakeDispatchTable(std::integer_sequence<T, i...>) noexcept
{
- return std::array<CommandDispatch, sizeof...(i)>{{ { &SanitizeCmdStrings<static_cast<Commands>(i)>, &UnpackNetworkCommand<static_cast<Commands>(i)> }... }};
+ return std::array<CommandDispatch, sizeof...(i)>{{ { &SanitizeCmdStrings<static_cast<Commands>(i)>, &NetworkReplaceCommandClientId<static_cast<Commands>(i)>, &UnpackNetworkCommand<static_cast<Commands>(i)> }... }};
}
static constexpr auto _cmd_dispatch = MakeDispatchTable(std::make_integer_sequence<std::underlying_type_t<Commands>, CMD_END>{});
@@ -383,23 +385,45 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
p->Send_uint8 (callback);
}
-/**
- * Insert a client ID into the command data in a command packet.
- * @param cp Command packet to modify.
- * @param client_id Client id to insert.
- */
-void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
+/** Helper to process a single ClientID argument. */
+template <class T>
+static inline void SetClientIdHelper(T &data, [[maybe_unused]] ClientID client_id)
+{
+ if constexpr (std::is_same_v<ClientID, T>) {
+ data = client_id;
+ }
+}
+
+/** Set all invalid ClientID's to the proper value. */
+template<class Ttuple, size_t... Tindices>
+static inline void SetClientIds(Ttuple &values, ClientID client_id, std::index_sequence<Tindices...>)
+{
+ ((SetClientIdHelper(std::get<Tindices>(values), client_id)), ...);
+}
+
+template <Commands Tcmd>
+static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
{
/* Unpack command parameters. */
- auto params = EndianBufferReader::ToValue<std::tuple<TileIndex, uint32, uint32, std::string>>(cp.data);
+ auto params = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp.data);
/* Insert client id. */
- std::get<2>(params) = client_id;
+ SetClientIds(params, client_id, std::make_index_sequence<std::tuple_size_v<decltype(params)>>{});
/* Repack command parameters. */
cp.data = EndianBufferWriter<CommandDataBuffer>::FromValue(params);
}
+/**
+ * Insert a client ID into the command data in a command packet.
+ * @param cp Command packet to modify.
+ * @param client_id Client id to insert.
+ */
+void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
+{
+ _cmd_dispatch[cp.cmd].ReplaceClientId(cp, client_id);
+}
+
/** Validate a single string argument coming from network. */
template <class T>
diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp
index ac12402ea..0c7e361dd 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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | _admin_company_id << 16 | CRR_MANUAL << 24, 0, {});
+ Command<CMD_COMPANY_CTRL>::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<CMD_COMPANY_CTRL>::Post(0, CCA_NEW, _network_own_client_id, {});
+ Command<CMD_COMPANY_CTRL>::Post(CCA_NEW, INVALID_COMPANY, CRR_NONE, _network_own_client_id);
} else {
- Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, 0, CCA_NEW, 0, {});
+ Command<CMD_COMPANY_CTRL>::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 ad891aef8..197d398bf 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<CommandTraits<CMD_COMPANY_CTRL>::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<CommandTraits<CMD_COMPANY_CTRL>::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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {});
+ Command<CMD_COMPANY_CTRL>::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<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {});
+ Command<CMD_COMPANY_CTRL>::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 6bececc0c..69ae6507d 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<CMD_CLEAR_ORDER_BACKUP>::Post(0, 0, user, {});
+ Command<CMD_CLEAR_ORDER_BACKUP>::Post(0, static_cast<ClientID>(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<CMD_CLEAR_ORDER_BACKUP>::Unsafe(STR_NULL, nullptr, true, false, ob->tile, CommandTraits<CMD_CLEAR_ORDER_BACKUP>::Args{ ob->tile, 0, user, {} });
+ Command<CMD_CLEAR_ORDER_BACKUP>::Unsafe(STR_NULL, nullptr, true, false, ob->tile, CommandTraits<CMD_CLEAR_ORDER_BACKUP>::Args{ ob->tile, static_cast<ClientID>(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 606cbef60..fa3424ce4 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 efe45c507..a6442430e 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 ca99dee3a..94aaee743 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 26da500c4..8d9be14c4 100644
--- a/src/script/api/script_object.hpp
+++ b/src/script/api/script_object.hpp
@@ -347,6 +347,22 @@ namespace ScriptObjectInternal {
{
((SanitizeSingleStringHelper(std::get<Tindices>(values))), ...);
}
+
+ /** Helper to process a single ClientID argument. */
+ template <class T>
+ static inline void SetClientIdHelper(T &data)
+ {
+ if constexpr (std::is_same_v<ClientID, T>) {
+ if (data == INVALID_CLIENT_ID) data = (ClientID)UINT32_MAX;
+ }
+ }
+
+ /** Set all invalid ClientID's to the proper value. */
+ template<class Ttuple, size_t... Tindices>
+ static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
+ {
+ ((SetClientIdHelper(std::get<Tindices>(values))), ...);
+ }
}
template <Commands Tcmd, typename... Targs>
@@ -364,8 +380,8 @@ bool ScriptObject::ScriptDoCommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Tar
tile = std::get<0>(args);
}
- /* Only set p2 when the command does not come from the network. */
- if ((::GetCommandFlags<Tcmd>() & 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<Tcmd>() & CMD_CLIENT_ID) != 0) ScriptObjectInternal::SetClientIds(args, std::index_sequence_for<Targs...>{});
/* Store the command for command callback validation. */
if (!estimate_only && networking) ScriptObject::SetLastCommand(tile, EndianBufferWriter<CommandDataBuffer>::FromValue(args), Tcmd);
diff --git a/src/script/api/script_vehicle.cpp b/src/script/api/script_vehicle.cpp
index d245f4132..3da5739ee 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<CMD_BUILD_VEHICLE>::Do(&ScriptInstance::DoCommandReturnVehicleID, depot, engine_id | (cargo << 24), 0, {})) return VEHICLE_INVALID;
+ if (!ScriptObject::Command<CMD_BUILD_VEHICLE>::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<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, depot, engine_id | (cargo << 24), 0, {});
+ CommandCost res = ::Command<CMD_BUILD_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(0, vehicle_id | (v->type == VEH_TRAIN ? 1 : 0) << 20, 0, {});
+ return ScriptObject::Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(0, v->index | (sell_attached_wagons ? 1 : 0) << 20, 0, {});
+ return ScriptObject::Command<CMD_SELL_VEHICLE>::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 0e0bccce0..2729030d3 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 8738f5420..b17885e37 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 a86e835bd..d2517d65b 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 7b286e998..4a7e5036e 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 aeaefe68f..f25a3cdd3 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<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, v->index, 0, {});
+ Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(flags, tile, list[i]->index | (1 << 20), 0, {});
+ CommandCost ret = Command<CMD_SELL_VEHICLE>::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<CMD_BUILD_VEHICLE>::Do(build_flags, tile, v->engine_type | (1 << 16) | (CT_INVALID << 24), 0, {});
+ CommandCost cost = Command<CMD_BUILD_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | (1 << 20), 0, {});
+ if (w_front != nullptr) Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {});
- Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w->index | 1 << 20, 0, {});
+ Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID);
+ Command<CMD_SELL_VEHICLE>::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<CMD_CLONE_ORDER>::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<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {});
+ Command<CMD_SELL_VEHICLE>::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<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {});
+ Command<CMD_SELL_VEHICLE>::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 e6872e838..98444033c 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;