38template <Commands Tcmd>
51 DoCommandFlags flags = {};
59struct RecursiveCommandCounter {
60 RecursiveCommandCounter()
noexcept { _counter++; }
61 ~RecursiveCommandCounter()
noexcept { _counter--; }
69#if defined(__GNUC__) && !defined(__clang__)
79# pragma GCC diagnostic push
80# pragma GCC diagnostic ignored "-Wcast-function-type"
81# define SILENCE_GCC_FUNCTION_POINTER_CAST
84template <Commands TCmd,
typename T,
bool THasTile>
struct CommandHelper;
105template <
Commands Tcmd,
typename Tret,
typename... Targs>
111 if constexpr (std::is_same_v<Tret, CommandCost>) {
114 return std::get<0>(ret);
139 static Tret
Do(DoCommandFlags flags, Targs... args)
141 if constexpr (std::is_same_v<
TileIndex, std::tuple_element_t<0, std::tuple<Targs...>>>) {
143 TileIndex tile = std::get<0>(std::make_tuple(args...));
178 template <
typename Tcallback>
179 static inline bool Post(Tcallback *callback, Targs... args) {
return Post((
StringID)0, callback, std::forward<Targs>(args)...); }
196 template <
typename Tcallback>
197 static bool Post(
StringID err_message, Tcallback *callback, Targs... args)
200 return InternalPost(err_message, callback,
true,
false, std::forward_as_tuple(args...));
211 template <
typename Tcallback>
212 static bool PostFromNet(
StringID err_message, Tcallback *callback,
bool my_cmd, std::tuple<Targs...> args)
214 return InternalPost(err_message, callback, my_cmd,
true, std::move(args));
225 auto args_tuple = std::forward_as_tuple(args...);
227 ::NetworkSendCommand(Tcmd, err_message,
nullptr, company, EndianBufferWriter<CommandDataBuffer>::FromValue(args_tuple));
240 template <
typename Tcallback>
241 static Tret
Unsafe(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool estimate_only,
TileIndex location, std::tuple<Targs...> args)
243 return Execute(err_message,
reinterpret_cast<CommandCallback *
>(
reinterpret_cast<void(*)()
>(callback)), my_cmd, estimate_only,
false, location, std::move(args));
251 if constexpr (std::is_same_v<ClientID, T>) {
257 template <
class Ttuple,
size_t... Tindices>
258 static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
264 template <
template <
typename...>
typename Tt,
typename T1,
typename... Ts>
267 return std::apply([](
auto &&,
const auto&... args) {
return std::tie(args...); }, tuple);
270 template <
typename Tcallback>
271 static bool InternalPost(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool network_command, std::tuple<Targs...> args)
275 if constexpr (std::is_same_v<
TileIndex, std::tuple_element_t<0,
decltype(args)>>) {
276 tile = std::get<0>(args);
279 return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args));
282 template <
typename Tcallback>
283 static bool InternalPost(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool network_command,
TileIndex tile, std::tuple<Targs...> args)
288 auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd,
GetCommandFlags<Tcmd>(), tile, err_message, network_command);
289 if (err)
return false;
294 Tret res =
Execute(err_message,
reinterpret_cast<CommandCallback *
>(
reinterpret_cast<void(*)()
>(callback)), my_cmd, estimate_only, network_command, tile, args);
295 InternalPostResult(ExtractCommandCost(res), tile, estimate_only, only_sending, err_message, my_cmd);
297 if (!estimate_only && !only_sending && callback !=
nullptr) {
298 if constexpr (std::is_same_v<Tcallback, CommandCallback>) {
300 callback(Tcmd, ExtractCommandCost(res), tile);
301 }
else if constexpr (std::is_same_v<Tcallback, CommandCallbackData>) {
303 if constexpr (std::is_same_v<Tret, CommandCost>) {
304 callback(Tcmd, ExtractCommandCost(res), EndianBufferWriter<CommandDataBuffer>::FromValue(args), {});
306 callback(Tcmd, ExtractCommandCost(res), EndianBufferWriter<CommandDataBuffer>::FromValue(args), EndianBufferWriter<CommandDataBuffer>::FromValue(RemoveFirstTupleElement(res)));
308 }
else if constexpr (!std::is_same_v<Tret, CommandCost> && std::is_same_v<Tcallback *, typename CommandTraits<Tcmd>::RetCallbackProc>) {
309 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd), res));
312 if constexpr (std::is_same_v<Tret, CommandCost>) {
313 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd, res), args));
315 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd), res, args));
320 return ExtractCommandCost(res).Succeeded();
327 if constexpr (std::is_same_v<ClientID, T>) {
335 template <
class Ttuple,
size_t... Tindices>
341 template <
class Ttuple>
342 static inline Money ExtractAdditionalMoney([[maybe_unused]] Ttuple &values)
344 if constexpr (std::is_same_v<std::tuple_element_t<1, Tret>, Money>) {
345 return std::get<1>(values);
362 assert(AllClientIdsSet(args, std::index_sequence_for<Targs...>{}));
366 if (!InternalExecutePrepTest(cmd_flags, cur_company)) {
375 auto [exit_test, desync_log, send_net] = InternalExecuteValidateTestAndPrepExec(ExtractCommandCost(res), cmd_flags, estimate_only, network_command, cur_company);
377 if (desync_log) LogCommandExecution(Tcmd, err_message, EndianBufferWriter<CommandDataBuffer>::FromValue(args),
true);
378 cur_company.Restore();
386 cur_company.Restore();
395 if (desync_log) LogCommandExecution(Tcmd, err_message, EndianBufferWriter<CommandDataBuffer>::FromValue(args),
false);
402 Money additional_money{};
403 if constexpr (!std::is_same_v<Tret, CommandCost>) {
404 additional_money = ExtractAdditionalMoney(res2);
407 if constexpr (std::is_same_v<Tret, CommandCost>) {
408 return InternalExecuteProcessResult(Tcmd, cmd_flags, res, res2, additional_money, tile, cur_company);
410 std::get<0>(res2) = InternalExecuteProcessResult(Tcmd, cmd_flags, ExtractCommandCost(res), ExtractCommandCost(res2), additional_money, tile, cur_company);
423template <
Commands Tcmd,
typename Tret,
typename... Targs>
427 static inline bool Post(
StringID err_message, Targs... args) =
delete;
428 template <
typename Tcallback>
429 static inline bool Post(Tcallback *callback, Targs... args) =
delete;
430 static inline bool Post(Targs... args) =
delete;
431 template <
typename Tcallback>
432 static bool Post(
StringID err_message, Tcallback *callback, Targs... args) =
delete;
440 static inline bool Post(
StringID err_message,
TileIndex location, Targs... args) {
return Post<CommandCallback>(err_message,
nullptr, location, std::forward<Targs>(args)...); }
447 template <
typename Tcallback>
448 static inline bool Post(Tcallback *callback,
TileIndex location, Targs... args) {
return Post((
StringID)0, callback, location, std::forward<Targs>(args)...); }
454 static inline bool Post(
TileIndex location, Targs... args) {
return Post<CommandCallback>((
StringID)0,
nullptr, location, std::forward<Targs>(args)...); }
465 template <
typename Tcallback>
468 return CommandHelper<Tcmd, Tret(*)(DoCommandFlags, Targs...),
true>::InternalPost(err_message, callback,
true,
false, location, std::forward_as_tuple(args...));
472#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
473# pragma GCC diagnostic pop
476template <Commands Tcmd>
Class for backupping variables and making sure they are restored later.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
Common return value for all commands.
static std::tuple< bool, bool, bool > InternalPostBefore(Commands cmd, CommandFlags flags, TileIndex tile, StringID err_message, bool network_command)
Decide what to do with the command depending on current game state.
static void InternalPostResult(CommandCost &res, TileIndex tile, bool estimate_only, bool only_sending, StringID err_message, bool my_cmd)
Process result of executing a command, possibly displaying any error to the player.
static void InternalDoBefore(bool top_level, bool test)
Prepare for calling a command proc.
static void LogCommandExecution(Commands cmd, StringID err_message, const CommandDataBuffer &args, bool failed)
Helper to make a desync log for a command.
static CommandCost InternalExecuteProcessResult(Commands cmd, CommandFlags cmd_flags, const CommandCost &res_test, const CommandCost &res_exec, Money extra_cash, TileIndex tile, Backup< CompanyID > &cur_company)
Process the result of a command test run and execution run.
static bool InternalExecutePrepTest(CommandFlags cmd_flags, Backup< CompanyID > &cur_company)
Prepare for the test run of a command proc call.
static void InternalDoAfter(CommandCost &res, DoCommandFlags flags, bool top_level, bool test)
Process result after calling a command proc.
static std::tuple< bool, bool, bool > InternalExecuteValidateTestAndPrepExec(CommandCost &res, CommandFlags cmd_flags, bool estimate_only, bool network_command, Backup< CompanyID > &cur_company)
Validate result of test run and prepare for real execution.
CommandFlags GetCommandFlags(Commands cmd)
Get the command flags associated with the given command.
CommandFlags GetCommandFlags(Commands cmd)
Get the command flags associated with the given command.
bool IsCommandAllowedWhilePaused(Commands cmd)
Returns whether the command is allowed while the game is paused.
static constexpr DoCommandFlags CommandFlagsToDCFlags(CommandFlags cmd_flags)
Extracts the DC flags needed for DoCommand from the flags returned by GetCommandFlags.
bool IsNetworkRegisteredCallback(CommandCallback *callback)
Helper function to ensure that callbacks used when Posting commands are actually registered for the n...
std::string_view GetCommandName(Commands cmd)
Get the name of the given command.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
bool IsValidCommand(Commands cmd)
This function range-checks a Commands.
void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, const CommandDataBuffer &cmd_data)
Prepare a DoCommand to be send over the network.
Types related to commands.
void CommandCallback(Commands cmd, const CommandCost &result, TileIndex tile)
Define a callback function for the client, after the command is finished.
@ Auto
don't allow building on structures
@ NoWater
don't allow building on water
@ Execute
execute the given command
@ AllTiles
allow this command also on TileType::Void tiles
@ Auto
set the DoCommandFlag::Auto flag on this command
@ NoWater
set the DoCommandFlag::NoWater flag on this command
@ AllTiles
allow this command also on TileType::Void tiles
@ ClientID
set p2 with the ClientID of the sending client.
@ Location
the command has implicit location argument.
std::vector< uint8_t > CommandDataBuffer
Storage buffer for serialized command data.
Commands
List of commands.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Types related to companies.
static void SetClientIds(Ttuple &values, ClientID client_id, std::index_sequence< Tindices... >)
Set all invalid ClientID's to the proper value.
static void SetClientIdHelper(T &data, ClientID client_id)
Helper to process a single ClientID argument.
Types used for networking.
@ INVALID_CLIENT_ID
Client is not part of anything.
@ CLIENT_ID_SERVER
Servers always have this ID.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames).
Class to backup a specific variable and restore it later.
static bool Post(TileIndex location, Targs... args)
Shortcut for Post when not using a callback or an error message.
static bool Post(StringID err_message, Tcallback *callback, TileIndex location, Targs... args)
Post variant that takes a TileIndex (for error window location and text effects) for commands that do...
static bool Post(StringID err_message, TileIndex location, Targs... args)
Shortcut for Post when not using a callback.
static bool Post(Tcallback *callback, TileIndex location, Targs... args)
Shortcut for Post when not using an error message.
static bool Post(StringID err_message, Tcallback *callback, Targs... args)
Top-level network safe command execution for the current company.
static Tret Do(DoCommandFlags flags, Targs... args)
This function executes a given command.
static bool ClientIdIsSet(T &data)
Helper to process a single ClientID argument.
static bool Post(StringID err_message, Targs... args)
Shortcut for the long Post when not using a callback.
static void SetClientIdHelper(T &data)
Helper to process a single ClientID argument.
static bool PostFromNet(StringID err_message, Tcallback *callback, bool my_cmd, std::tuple< Targs... > args)
Execute a command coming from the network.
static Tret Unsafe(StringID err_message, Tcallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple< Targs... > args)
Top-level network safe command execution without safety checks.
static void SendNet(StringID err_message, CompanyID company, Targs... args)
Prepare a command to be send over the network.
static bool Post(Tcallback *callback, Targs... args)
Shortcut for the long Post when not using an error message.
static Tt< Ts... > RemoveFirstTupleElement(const Tt< T1, Ts... > &tuple)
Remove the first element of a tuple.
static Tret MakeResult(const CommandCost &cost)
Make a command proc result from a CommandCost.
static bool Post(Targs... args)
Shortcut for the long Post when not using a callback or an error message.
static bool AllClientIdsSet(Ttuple &values, std::index_sequence< Tindices... >)
Check if all ClientID arguments are set to valid values.
static CommandCost & ExtractCommandCost(Tret &ret)
Extract the CommandCost from a command proc result.
static void SetClientIds(Ttuple &values, std::index_sequence< Tindices... >)
Set all invalid ClientID's to the proper value.
Defines the traits of a command.
static uint Size()
Get the size of the map.
Helper class to keep track of command nesting level.
bool IsTopLevel() const
Are we in the top-level command execution?
Map writing/reading functions for tiles.
bool IsValidTile(Tile tile)
Checks if a tile is valid.
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.