38template <Commands Tcmd>
51 DoCommandFlags flags = {};
74#if defined(__GNUC__) && !defined(__clang__)
84# pragma GCC diagnostic push
85# pragma GCC diagnostic ignored "-Wcast-function-type"
86# define SILENCE_GCC_FUNCTION_POINTER_CAST
89template <Commands TCmd,
typename T,
bool THasTile>
struct CommandHelper;
109template <
typename Tret>
112 if constexpr (std::is_same_v<Tret, CommandCost>) {
115 static_assert(std::is_same_v<std::tuple_element_t<0, Tret>,
CommandCost>);
116 return std::get<0>(ret);
121template <
typename Tret>
124 if constexpr (std::is_same_v<Tret, CommandCost>) {
127 static_assert(std::is_same_v<std::tuple_element_t<0, Tret>,
CommandCost>);
128 return std::get<0>(ret);
139template <
Commands Tcmd,
typename Tret,
typename... Targs>
167 static Tret
Do(DoCommandFlags flags, Targs... args)
169 if constexpr (std::is_same_v<
TileIndex, std::tuple_element_t<0, std::tuple<Targs...>>>) {
171 TileIndex tile = std::get<0>(std::make_tuple(args...));
209 template <
typename Tcallback>
210 static inline bool Post(Tcallback *callback, Targs... args) {
return Post((
StringID)0, callback, std::forward<Targs>(args)...); }
229 template <
typename Tcallback>
230 static bool Post(
StringID err_message, Tcallback *callback, Targs... args)
233 return InternalPost(err_message, callback,
true,
false, std::forward_as_tuple(args...));
244 template <
typename Tcallback>
245 static bool PostFromNet(
StringID err_message, Tcallback *callback,
bool my_cmd, std::tuple<Targs...> args)
247 return InternalPost(err_message, callback, my_cmd,
true, std::move(args));
258 auto args_tuple = std::forward_as_tuple(args...);
260 ::NetworkSendCommand(Tcmd, err_message,
nullptr, company, EndianBufferWriter<CommandDataBuffer>::FromValue(args_tuple));
273 template <
typename Tcallback>
274 static Tret
Unsafe(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool estimate_only,
TileIndex location, std::tuple<Targs...> args)
276 return Execute(err_message,
reinterpret_cast<CommandCallback *
>(
reinterpret_cast<void(*)()
>(callback)), my_cmd, estimate_only,
false, location, std::move(args));
287 if constexpr (std::is_same_v<ClientID, T>) {
296 template <
class Ttuple,
size_t... Tindices>
297 static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
307 template <
template <
typename...>
typename Tt,
typename T1,
typename... Ts>
310 return std::apply([](
auto &&,
const auto&... args) {
return std::tie(args...); }, tuple);
313 template <
typename Tcallback>
314 static bool InternalPost(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool network_command, std::tuple<Targs...> args)
318 if constexpr (std::is_same_v<
TileIndex, std::tuple_element_t<0,
decltype(args)>>) {
319 tile = std::get<0>(args);
322 return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args));
325 template <
typename Tcallback>
326 static bool InternalPost(
StringID err_message, Tcallback *callback,
bool my_cmd,
bool network_command,
TileIndex tile, std::tuple<Targs...> args)
331 auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd,
GetCommandFlags<Tcmd>(), tile, err_message, network_command);
332 if (err)
return false;
337 Tret res =
Execute(err_message,
reinterpret_cast<CommandCallback *
>(
reinterpret_cast<void(*)()
>(callback)), my_cmd, estimate_only, network_command, tile, args);
338 InternalPostResult(
ExtractCommandCost(res), tile, estimate_only, only_sending, err_message, my_cmd);
340 if (!estimate_only && !only_sending && callback !=
nullptr) {
341 if constexpr (std::is_same_v<Tcallback, CommandCallback>) {
344 }
else if constexpr (std::is_same_v<Tcallback, CommandCallbackData>) {
346 if constexpr (std::is_same_v<Tret, CommandCost>) {
347 callback(Tcmd,
ExtractCommandCost(res), EndianBufferWriter<CommandDataBuffer>::FromValue(args), {});
349 callback(Tcmd,
ExtractCommandCost(res), EndianBufferWriter<CommandDataBuffer>::FromValue(args), EndianBufferWriter<CommandDataBuffer>::FromValue(RemoveFirstTupleElement(res)));
351 }
else if constexpr (!std::is_same_v<Tret, CommandCost> && std::is_same_v<Tcallback *, typename CommandTraits<Tcmd>::RetCallbackProc>) {
352 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd), res));
355 if constexpr (std::is_same_v<Tret, CommandCost>) {
356 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd, res), args));
358 std::apply(callback, std::tuple_cat(std::make_tuple(Tcmd), res, args));
374 if constexpr (std::is_same_v<ClientID, T>) {
386 template <
class Ttuple,
size_t... Tindices>
392 template <
class Ttuple>
393 static inline Money ExtractAdditionalMoney([[maybe_unused]] Ttuple &values)
395 if constexpr (std::is_same_v<std::tuple_element_t<1, Tret>, Money>) {
396 return std::get<1>(values);
413 assert(AllClientIdsSet(args, std::index_sequence_for<Targs...>{}));
417 if (!InternalExecutePrepTest(cmd_flags, cur_company)) {
426 auto [exit_test, desync_log, send_net] = InternalExecuteValidateTestAndPrepExec(
ExtractCommandCost(res), cmd_flags, estimate_only, network_command, cur_company);
428 if (desync_log) LogCommandExecution(Tcmd, err_message, EndianBufferWriter<CommandDataBuffer>::FromValue(args),
true);
429 cur_company.Restore();
437 cur_company.Restore();
446 if (desync_log) LogCommandExecution(Tcmd, err_message, EndianBufferWriter<CommandDataBuffer>::FromValue(args),
false);
453 Money additional_money{};
454 if constexpr (!std::is_same_v<Tret, CommandCost>) {
455 additional_money = ExtractAdditionalMoney(res2);
458 if constexpr (std::is_same_v<Tret, CommandCost>) {
459 return InternalExecuteProcessResult(Tcmd, cmd_flags, res, res2, additional_money, tile, cur_company);
474template <
Commands Tcmd,
typename Tret,
typename... Targs>
478 static inline bool Post(
StringID err_message, Targs... args) =
delete;
479 template <
typename Tcallback>
480 static inline bool Post(Tcallback *callback, Targs... args) =
delete;
481 static inline bool Post(Targs... args) =
delete;
482 template <
typename Tcallback>
483 static bool Post(
StringID err_message, Tcallback *callback, Targs... args) =
delete;
492 static inline bool Post(
StringID err_message,
TileIndex location, Targs... args) {
return Post<CommandCallback>(err_message,
nullptr, location, std::forward<Targs>(args)...); }
501 template <
typename Tcallback>
502 static inline bool Post(Tcallback *callback,
TileIndex location, Targs... args) {
return Post((
StringID)0, callback, location, std::forward<Targs>(args)...); }
510 static inline bool Post(
TileIndex location, Targs... args) {
return Post<CommandCallback>((
StringID)0,
nullptr, location, std::forward<Targs>(args)...); }
521 template <
typename Tcallback>
524 return CommandHelper<Tcmd, Tret(*)(DoCommandFlags, Targs...),
true>::InternalPost(err_message, callback,
true,
false, location, std::forward_as_tuple(args...));
528#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
529# pragma GCC diagnostic pop
532template <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.
bool Succeeded() const
Did this command succeed?
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.
CommandCost & ExtractCommandCost(Tret &ret)
Extract the CommandCost from a command proc result.
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.
#define T
Climate temperate.
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 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.
~RecursiveCommandCounter() noexcept
Decrement the recursion counter.
static int _counter
Number of instances of this class.
RecursiveCommandCounter() noexcept
Increment the recursion counter.
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.