38template <Commands Tcmd>
51 DoCommandFlags flags = {};
59struct RecursiveCommandCounter {
60 RecursiveCommandCounter()
noexcept {
_counter++; }
61 ~RecursiveCommandCounter()
noexcept {
_counter--; }
72#if defined(__GNUC__) && !defined(__clang__)
82# pragma GCC diagnostic push
83# pragma GCC diagnostic ignored "-Wcast-function-type"
84# define SILENCE_GCC_FUNCTION_POINTER_CAST
87template <Commands TCmd,
typename T,
bool THasTile>
struct CommandHelper;
108template <
Commands Tcmd,
typename Tret,
typename... Targs>
118 if constexpr (std::is_same_v<Tret, CommandCost>) {
121 return std::get<0>(ret);
150 static Tret
Do(DoCommandFlags flags, Targs... args)
152 if constexpr (std::is_same_v<
TileIndex, std::tuple_element_t<0, std::tuple<Targs...>>>) {
154 TileIndex tile = std::get<0>(std::make_tuple(args...));
192 template <
typename Tcallback>
193 static inline bool Post(Tcallback *callback, Targs... args) {
return Post((
StringID)0, callback, std::forward<Targs>(args)...); }
212 template <
typename Tcallback>
213 static bool Post(
StringID err_message, Tcallback *callback, Targs... args)
216 return InternalPost(err_message, callback,
true,
false, std::forward_as_tuple(args...));
227 template <
typename Tcallback>
228 static bool PostFromNet(
StringID err_message, Tcallback *callback,
bool my_cmd, std::tuple<Targs...> args)
230 return InternalPost(err_message, callback, my_cmd,
true, std::move(args));
241 auto args_tuple = std::forward_as_tuple(args...);
243 ::NetworkSendCommand(Tcmd, err_message,
nullptr, company, EndianBufferWriter<CommandDataBuffer>::FromValue(args_tuple));
256 template <
typename Tcallback>
257 static Tret
Unsafe(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool estimate_only,
TileIndex location, std::tuple<Targs...> args)
259 return Execute(err_message,
reinterpret_cast<CommandCallback *
>(
reinterpret_cast<void(*)()
>(callback)), my_cmd, estimate_only,
false, location, std::move(args));
270 if constexpr (std::is_same_v<ClientID, T>) {
279 template <
class Ttuple,
size_t... Tindices>
280 static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
290 template <
template <
typename...>
typename Tt,
typename T1,
typename... Ts>
293 return std::apply([](
auto &&,
const auto&... args) {
return std::tie(args...); }, tuple);
296 template <
typename Tcallback>
297 static bool InternalPost(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool network_command, std::tuple<Targs...> args)
301 if constexpr (std::is_same_v<
TileIndex, std::tuple_element_t<0,
decltype(args)>>) {
302 tile = std::get<0>(args);
305 return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args));
308 template <
typename Tcallback>
309 static bool InternalPost(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool network_command,
TileIndex tile, std::tuple<Targs...> args)
314 auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd,
GetCommandFlags<Tcmd>(), tile, err_message, network_command);
315 if (err)
return false;
320 Tret res =
Execute(err_message,
reinterpret_cast<CommandCallback *
>(
reinterpret_cast<void(*)()
>(callback)), my_cmd, estimate_only, network_command, tile, args);
321 InternalPostResult(ExtractCommandCost(res), tile, estimate_only, only_sending, err_message, my_cmd);
323 if (!estimate_only && !only_sending && callback !=
nullptr) {
324 if constexpr (std::is_same_v<Tcallback, CommandCallback>) {
326 callback(Tcmd, ExtractCommandCost(res), tile);
327 }
else if constexpr (std::is_same_v<Tcallback, CommandCallbackData>) {
329 if constexpr (std::is_same_v<Tret, CommandCost>) {
330 callback(Tcmd, ExtractCommandCost(res), EndianBufferWriter<CommandDataBuffer>::FromValue(args), {});
332 callback(Tcmd, ExtractCommandCost(res), EndianBufferWriter<CommandDataBuffer>::FromValue(args), EndianBufferWriter<CommandDataBuffer>::FromValue(RemoveFirstTupleElement(res)));
334 }
else if constexpr (!std::is_same_v<Tret, CommandCost> && std::is_same_v<Tcallback *, typename CommandTraits<Tcmd>::RetCallbackProc>) {
335 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd), res));
338 if constexpr (std::is_same_v<Tret, CommandCost>) {
339 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd, res), args));
341 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd), res, args));
346 return ExtractCommandCost(res).Succeeded();
357 if constexpr (std::is_same_v<ClientID, T>) {
369 template <
class Ttuple,
size_t... Tindices>
375 template <
class Ttuple>
376 static inline Money ExtractAdditionalMoney([[maybe_unused]] Ttuple &values)
378 if constexpr (std::is_same_v<std::tuple_element_t<1, Tret>, Money>) {
379 return std::get<1>(values);
396 assert(AllClientIdsSet(args, std::index_sequence_for<Targs...>{}));
400 if (!InternalExecutePrepTest(cmd_flags, cur_company)) {
409 auto [exit_test, desync_log, send_net] = InternalExecuteValidateTestAndPrepExec(ExtractCommandCost(res), cmd_flags, estimate_only, network_command, cur_company);
411 if (desync_log) LogCommandExecution(Tcmd, err_message, EndianBufferWriter<CommandDataBuffer>::FromValue(args),
true);
412 cur_company.Restore();
420 cur_company.Restore();
429 if (desync_log) LogCommandExecution(Tcmd, err_message, EndianBufferWriter<CommandDataBuffer>::FromValue(args),
false);
436 Money additional_money{};
437 if constexpr (!std::is_same_v<Tret, CommandCost>) {
438 additional_money = ExtractAdditionalMoney(res2);
441 if constexpr (std::is_same_v<Tret, CommandCost>) {
442 return InternalExecuteProcessResult(Tcmd, cmd_flags, res, res2, additional_money, tile, cur_company);
444 std::get<0>(res2) = InternalExecuteProcessResult(Tcmd, cmd_flags, ExtractCommandCost(res), ExtractCommandCost(res2), additional_money, tile, cur_company);
457template <
Commands Tcmd,
typename Tret,
typename... Targs>
461 static inline bool Post(
StringID err_message, Targs... args) =
delete;
462 template <
typename Tcallback>
463 static inline bool Post(Tcallback *callback, Targs... args) =
delete;
464 static inline bool Post(Targs... args) =
delete;
465 template <
typename Tcallback>
466 static bool Post(
StringID err_message, Tcallback *callback, Targs... args) =
delete;
475 static inline bool Post(
StringID err_message,
TileIndex location, Targs... args) {
return Post<CommandCallback>(err_message,
nullptr, location, std::forward<Targs>(args)...); }
484 template <
typename Tcallback>
485 static inline bool Post(Tcallback *callback,
TileIndex location, Targs... args) {
return Post((
StringID)0, callback, location, std::forward<Targs>(args)...); }
493 static inline bool Post(
TileIndex location, Targs... args) {
return Post<CommandCallback>((
StringID)0,
nullptr, location, std::forward<Targs>(args)...); }
504 template <
typename Tcallback>
507 return CommandHelper<Tcmd, Tret(*)(DoCommandFlags, Targs...),
true>::InternalPost(err_message, callback,
true,
false, location, std::forward_as_tuple(args...));
511#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
512# pragma GCC diagnostic pop
515template <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 ClientIDs 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 ClientIDs 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.
static int _counter
Number of instances of this class.
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.