mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: Template the command callback function type to allow unpacked arguments.
This commit is contained in:
parent
13528bfcd0
commit
d85348b1d1
|
@ -78,6 +78,20 @@ private:
|
||||||
static int _counter;
|
static int _counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
/*
|
||||||
|
* We cast specialized function pointers to a generic one, but don't use the
|
||||||
|
* converted value to call the function, which is safe, except that GCC
|
||||||
|
* helpfully thinks it is not.
|
||||||
|
*
|
||||||
|
* "Any pointer to function can be converted to a pointer to a different function type.
|
||||||
|
* Calling the function through a pointer to a different function type is undefined,
|
||||||
|
* but converting such pointer back to pointer to the original function type yields
|
||||||
|
* the pointer to the original function." */
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||||
|
# define SILENCE_GCC_FUNCTION_POINTER_CAST
|
||||||
|
#endif
|
||||||
|
|
||||||
template<Commands TCmd, typename T, bool THasTile> struct CommandHelper;
|
template<Commands TCmd, typename T, bool THasTile> struct CommandHelper;
|
||||||
|
|
||||||
|
@ -148,18 +162,19 @@ public:
|
||||||
* @param err_message Message prefix to show on error
|
* @param err_message Message prefix to show on error
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
*/
|
*/
|
||||||
static inline bool Post(StringID err_message, Targs... args) { return Post(err_message, nullptr, std::forward<Targs>(args)...); }
|
static inline bool Post(StringID err_message, Targs... args) { return Post<CommandCallback>(err_message, nullptr, std::forward<Targs>(args)...); }
|
||||||
/**
|
/**
|
||||||
* Shortcut for the long Post when not using an error message.
|
* Shortcut for the long Post when not using an error message.
|
||||||
* @param callback A callback function to call after the command is finished
|
* @param callback A callback function to call after the command is finished
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
*/
|
*/
|
||||||
static inline bool Post(CommandCallback *callback, Targs... args) { return Post((StringID)0, callback, std::forward<Targs>(args)...); }
|
template <typename Tcallback>
|
||||||
|
static inline bool Post(Tcallback *callback, Targs... args) { return Post((StringID)0, callback, std::forward<Targs>(args)...); }
|
||||||
/**
|
/**
|
||||||
* Shortcut for the long Post when not using a callback or an error message.
|
* Shortcut for the long Post when not using a callback or an error message.
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
*/
|
*/
|
||||||
static inline bool Post(Targs... args) { return Post((StringID)0, nullptr, std::forward<Targs>(args)...); }
|
static inline bool Post(Targs... args) { return Post<CommandCallback>((StringID)0, nullptr, std::forward<Targs>(args)...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top-level network safe command execution for the current company.
|
* Top-level network safe command execution for the current company.
|
||||||
|
@ -171,7 +186,8 @@ public:
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
* @return \c true if the command succeeded, else \c false.
|
* @return \c true if the command succeeded, else \c false.
|
||||||
*/
|
*/
|
||||||
static bool Post(StringID err_message, CommandCallback *callback, Targs... args)
|
template <typename Tcallback>
|
||||||
|
static bool Post(StringID err_message, Tcallback *callback, Targs... args)
|
||||||
{
|
{
|
||||||
return InternalPost(err_message, callback, true, false, std::forward_as_tuple(args...));
|
return InternalPost(err_message, callback, true, false, std::forward_as_tuple(args...));
|
||||||
}
|
}
|
||||||
|
@ -185,7 +201,8 @@ public:
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
* @return \c true if the command succeeded, else \c false.
|
* @return \c true if the command succeeded, else \c false.
|
||||||
*/
|
*/
|
||||||
static bool PostFromNet(StringID err_message, CommandCallback *callback, bool my_cmd, TileIndex location, std::tuple<Targs...> args)
|
template <typename Tcallback>
|
||||||
|
static bool PostFromNet(StringID err_message, Tcallback *callback, bool my_cmd, TileIndex location, std::tuple<Targs...> args)
|
||||||
{
|
{
|
||||||
return InternalPost(err_message, callback, my_cmd, true, location, std::move(args));
|
return InternalPost(err_message, callback, my_cmd, true, location, std::move(args));
|
||||||
}
|
}
|
||||||
|
@ -194,11 +211,10 @@ public:
|
||||||
* Prepare a command to be send over the network
|
* Prepare a command to be send over the network
|
||||||
* @param cmd The command to execute (a CMD_* value)
|
* @param cmd The command to execute (a CMD_* value)
|
||||||
* @param err_message Message prefix to show on error
|
* @param err_message Message prefix to show on error
|
||||||
* @param callback A callback function to call after the command is finished
|
|
||||||
* @param company The company that wants to send the command
|
* @param company The company that wants to send the command
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
*/
|
*/
|
||||||
static void SendNet(StringID err_message, CommandCallback *callback, CompanyID company, Targs... args)
|
static void SendNet(StringID err_message, CompanyID company, Targs... args)
|
||||||
{
|
{
|
||||||
auto args_tuple = std::forward_as_tuple(args...);
|
auto args_tuple = std::forward_as_tuple(args...);
|
||||||
|
|
||||||
|
@ -207,7 +223,7 @@ public:
|
||||||
tile = std::get<0>(args_tuple);
|
tile = std::get<0>(args_tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
::NetworkSendCommand(Tcmd, err_message, callback, _current_company, tile, EndianBufferWriter<CommandDataBuffer>::FromValue(args_tuple));
|
::NetworkSendCommand(Tcmd, err_message, nullptr, _current_company, tile, EndianBufferWriter<CommandDataBuffer>::FromValue(args_tuple));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,9 +236,10 @@ public:
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
* @return the command cost of this function.
|
* @return the command cost of this function.
|
||||||
*/
|
*/
|
||||||
static CommandCost Unsafe(StringID err_message, CommandCallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple<Targs...> args)
|
template <typename Tcallback>
|
||||||
|
static CommandCost Unsafe(StringID err_message, Tcallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple<Targs...> args)
|
||||||
{
|
{
|
||||||
return Execute(err_message, callback, my_cmd, estimate_only, false, location, std::move(args));
|
return Execute(err_message, reinterpret_cast<CommandCallback *>(callback), my_cmd, estimate_only, false, location, std::move(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -242,7 +259,8 @@ protected:
|
||||||
((SetClientIdHelper(std::get<Tindices>(values))), ...);
|
((SetClientIdHelper(std::get<Tindices>(values))), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, std::tuple<Targs...> args)
|
template <typename Tcallback>
|
||||||
|
static bool InternalPost(StringID err_message, Tcallback *callback, bool my_cmd, bool network_command, std::tuple<Targs...> args)
|
||||||
{
|
{
|
||||||
/* Where to show the message? */
|
/* Where to show the message? */
|
||||||
TileIndex tile{};
|
TileIndex tile{};
|
||||||
|
@ -253,7 +271,8 @@ protected:
|
||||||
return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args));
|
return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, TileIndex tile, std::tuple<Targs...> args)
|
template <typename Tcallback>
|
||||||
|
static bool InternalPost(StringID err_message, Tcallback *callback, bool my_cmd, bool network_command, TileIndex tile, std::tuple<Targs...> args)
|
||||||
{
|
{
|
||||||
auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags<Tcmd>(), tile, err_message, network_command);
|
auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags<Tcmd>(), tile, err_message, network_command);
|
||||||
if (err) return false;
|
if (err) return false;
|
||||||
|
@ -261,7 +280,7 @@ protected:
|
||||||
/* Only set client IDs when the command does not come from the network. */
|
/* 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...>{});
|
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);
|
CommandCost res = Execute(err_message, reinterpret_cast<CommandCallback *>(callback), my_cmd, estimate_only, network_command, tile, args);
|
||||||
InternalPostResult(res, tile, estimate_only, only_sending, err_message, my_cmd);
|
InternalPostResult(res, tile, estimate_only, only_sending, err_message, my_cmd);
|
||||||
|
|
||||||
if (!estimate_only && !only_sending && callback != nullptr) {
|
if (!estimate_only && !only_sending && callback != nullptr) {
|
||||||
|
@ -360,20 +379,21 @@ struct CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...), false> : Com
|
||||||
* @param location Tile location for user feedback.
|
* @param location Tile location for user feedback.
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
*/
|
*/
|
||||||
static inline bool Post(StringID err_message, TileIndex location, Targs... args) { return Post(err_message, nullptr, location, std::forward<Targs>(args)...); }
|
static inline bool Post(StringID err_message, TileIndex location, Targs... args) { return Post<CommandCallback>(err_message, nullptr, location, std::forward<Targs>(args)...); }
|
||||||
/**
|
/**
|
||||||
* Shortcut for Post when not using a callback.
|
* Shortcut for Post when not using a callback.
|
||||||
* @param callback A callback function to call after the command is finished
|
* @param callback A callback function to call after the command is finished
|
||||||
* @param location Tile location for user feedback.
|
* @param location Tile location for user feedback.
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
*/
|
*/
|
||||||
static inline bool Post(CommandCallback *callback, TileIndex location, Targs... args) { return Post((StringID)0, callback, location, std::forward<Targs>(args)...); }
|
template <typename Tcallback>
|
||||||
|
static inline bool Post(Tcallback *callback, TileIndex location, Targs... args) { return Post((StringID)0, callback, location, std::forward<Targs>(args)...); }
|
||||||
/**
|
/**
|
||||||
* Shortcut for Post when not using a callback or an error message.
|
* Shortcut for Post when not using a callback or an error message.
|
||||||
* @param location Tile location for user feedback.
|
* @param location Tile location for user feedback.
|
||||||
* @param args Parameters for the command*
|
* @param args Parameters for the command*
|
||||||
*/
|
*/
|
||||||
static inline bool Post(TileIndex location, Targs... args) { return Post((StringID)0, nullptr, location, std::forward<Targs>(args)...); }
|
static inline bool Post(TileIndex location, Targs... args) { return Post<CommandCallback>((StringID)0, nullptr, location, std::forward<Targs>(args)...); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post variant that takes a TileIndex (for error window location and text effects) for
|
* Post variant that takes a TileIndex (for error window location and text effects) for
|
||||||
|
@ -384,12 +404,16 @@ struct CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...), false> : Com
|
||||||
* @param args Parameters for the command
|
* @param args Parameters for the command
|
||||||
* @return \c true if the command succeeded, else \c false.
|
* @return \c true if the command succeeded, else \c false.
|
||||||
*/
|
*/
|
||||||
static inline bool Post(StringID err_message, CommandCallback *callback, TileIndex location, Targs... args)
|
template <typename Tcallback>
|
||||||
|
static inline bool Post(StringID err_message, Tcallback *callback, TileIndex location, Targs... args)
|
||||||
{
|
{
|
||||||
return CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...), true>::InternalPost(err_message, callback, true, false, location, std::forward_as_tuple(args...));
|
return CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...), true>::InternalPost(err_message, callback, true, false, location, std::forward_as_tuple(args...));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
template <Commands Tcmd>
|
template <Commands Tcmd>
|
||||||
using Command = CommandHelper<Tcmd, typename CommandTraits<Tcmd>::ProcType, std::is_same_v<TileIndex, std::tuple_element_t<0, typename CommandTraits<Tcmd>::Args>>>;
|
using Command = CommandHelper<Tcmd, typename CommandTraits<Tcmd>::ProcType, std::is_same_v<TileIndex, std::tuple_element_t<0, typename CommandTraits<Tcmd>::Args>>>;
|
||||||
|
|
|
@ -840,7 +840,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
||||||
* the server will give us a client-id and let us in */
|
* the server will give us a client-id and let us in */
|
||||||
_network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
|
_network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
|
||||||
ShowJoinStatusWindow();
|
ShowJoinStatusWindow();
|
||||||
Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
|
Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* take control over an existing company */
|
/* take control over an existing company */
|
||||||
|
|
|
@ -53,55 +53,95 @@
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
/** Table with all the callbacks we'll use for conversion*/
|
/** Typed list of all possible callbacks. */
|
||||||
static CommandCallback * const _callback_table[] = {
|
static constexpr auto _callback_tuple = std::make_tuple(
|
||||||
/* 0x00 */ nullptr,
|
(CommandCallback *)nullptr, // Make sure this is actually a pointer-to-function.
|
||||||
/* 0x01 */ CcBuildPrimaryVehicle,
|
&CcBuildPrimaryVehicle,
|
||||||
/* 0x02 */ CcBuildAirport,
|
&CcBuildAirport,
|
||||||
/* 0x03 */ CcBuildBridge,
|
&CcBuildBridge,
|
||||||
/* 0x04 */ CcPlaySound_CONSTRUCTION_WATER,
|
&CcPlaySound_CONSTRUCTION_WATER,
|
||||||
/* 0x05 */ CcBuildDocks,
|
&CcBuildDocks,
|
||||||
/* 0x06 */ CcFoundTown,
|
&CcFoundTown,
|
||||||
/* 0x07 */ CcBuildRoadTunnel,
|
&CcBuildRoadTunnel,
|
||||||
/* 0x08 */ CcBuildRailTunnel,
|
&CcBuildRailTunnel,
|
||||||
/* 0x09 */ CcBuildWagon,
|
&CcBuildWagon,
|
||||||
/* 0x0A */ CcRoadDepot,
|
&CcRoadDepot,
|
||||||
/* 0x0B */ CcRailDepot,
|
&CcRailDepot,
|
||||||
/* 0x0C */ CcPlaceSign,
|
&CcPlaceSign,
|
||||||
/* 0x0D */ CcPlaySound_EXPLOSION,
|
&CcPlaySound_EXPLOSION,
|
||||||
/* 0x0E */ CcPlaySound_CONSTRUCTION_OTHER,
|
&CcPlaySound_CONSTRUCTION_OTHER,
|
||||||
/* 0x0F */ CcPlaySound_CONSTRUCTION_RAIL,
|
&CcPlaySound_CONSTRUCTION_RAIL,
|
||||||
/* 0x10 */ CcStation,
|
&CcStation,
|
||||||
/* 0x11 */ CcTerraform,
|
&CcTerraform,
|
||||||
/* 0x12 */ CcAI,
|
&CcAI,
|
||||||
/* 0x13 */ CcCloneVehicle,
|
&CcCloneVehicle,
|
||||||
/* 0x14 */ nullptr,
|
&CcCreateGroup,
|
||||||
/* 0x15 */ CcCreateGroup,
|
&CcFoundRandomTown,
|
||||||
/* 0x16 */ CcFoundRandomTown,
|
&CcRoadStop,
|
||||||
/* 0x17 */ CcRoadStop,
|
&CcBuildIndustry,
|
||||||
/* 0x18 */ CcBuildIndustry,
|
&CcStartStopVehicle,
|
||||||
/* 0x19 */ CcStartStopVehicle,
|
&CcGame,
|
||||||
/* 0x1A */ CcGame,
|
&CcAddVehicleNewGroup
|
||||||
/* 0x1B */ CcAddVehicleNewGroup,
|
);
|
||||||
};
|
|
||||||
|
#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
|
||||||
|
/*
|
||||||
|
* We cast specialized function pointers to a generic one, but don't use the
|
||||||
|
* converted value to call the function, which is safe, except that GCC
|
||||||
|
* helpfully thinks it is not.
|
||||||
|
*
|
||||||
|
* "Any pointer to function can be converted to a pointer to a different function type.
|
||||||
|
* Calling the function through a pointer to a different function type is undefined,
|
||||||
|
* but converting such pointer back to pointer to the original function type yields
|
||||||
|
* the pointer to the original function." */
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Helpers to generate the callback table from the callback list. */
|
||||||
|
|
||||||
|
inline constexpr size_t _callback_tuple_size = std::tuple_size_v<decltype(_callback_tuple)>;
|
||||||
|
|
||||||
|
template <size_t... i>
|
||||||
|
inline auto MakeCallbackTable(std::index_sequence<i...>) noexcept
|
||||||
|
{
|
||||||
|
return std::array<CommandCallback *, sizeof...(i)>{{ reinterpret_cast<CommandCallback *>(reinterpret_cast<void(*)()>(std::get<i>(_callback_tuple)))... }}; // MingW64 fails linking when casting a pointer to its own type. To work around, cast it to some other type first.
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Type-erased table of callbacks. */
|
||||||
|
static auto _callback_table = MakeCallbackTable(std::make_index_sequence<_callback_tuple_size>{});
|
||||||
|
|
||||||
|
|
||||||
/* Helpers to generate the command dispatch table from the command traits. */
|
/* Helpers to generate the command dispatch table from the command traits. */
|
||||||
|
|
||||||
template <Commands Tcmd> static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data);
|
template <Commands Tcmd> static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data);
|
||||||
template <Commands Tcmd> static void UnpackNetworkCommand(const CommandPacket *cp);
|
template <Commands Tcmd, size_t cb> static void UnpackNetworkCommand(const CommandPacket *cp);
|
||||||
template <Commands Tcmd> static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id);
|
template <Commands Tcmd> static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id);
|
||||||
|
using UnpackNetworkCommandProc = void (*)(const CommandPacket *);
|
||||||
|
using UnpackDispatchT = std::array<UnpackNetworkCommandProc, _callback_tuple_size>;
|
||||||
struct CommandDispatch {
|
struct CommandDispatch {
|
||||||
CommandDataBuffer(*Sanitize)(const CommandDataBuffer &);
|
CommandDataBuffer(*Sanitize)(const CommandDataBuffer &);
|
||||||
void (*ReplaceClientId)(CommandPacket &, ClientID);
|
void (*ReplaceClientId)(CommandPacket &, ClientID);
|
||||||
void (*Unpack)(const CommandPacket *);
|
UnpackDispatchT Unpack;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, T... i>
|
template <Commands Tcmd, size_t... i>
|
||||||
inline constexpr auto MakeDispatchTable(std::integer_sequence<T, i...>) noexcept
|
constexpr UnpackDispatchT MakeUnpackNetworkCommand(std::index_sequence<i...>) noexcept
|
||||||
{
|
{
|
||||||
return std::array<CommandDispatch, sizeof...(i)>{{ { &SanitizeCmdStrings<static_cast<Commands>(i)>, &NetworkReplaceCommandClientId<static_cast<Commands>(i)>, &UnpackNetworkCommand<static_cast<Commands>(i)> }... }};
|
return UnpackDispatchT{{ {&UnpackNetworkCommand<Tcmd, i>}... }};
|
||||||
}
|
}
|
||||||
static constexpr auto _cmd_dispatch = MakeDispatchTable(std::make_integer_sequence<std::underlying_type_t<Commands>, CMD_END>{});
|
|
||||||
|
template <typename T, T... i, size_t... j>
|
||||||
|
inline constexpr auto MakeDispatchTable(std::integer_sequence<T, i...>, std::index_sequence<j...>) noexcept
|
||||||
|
{
|
||||||
|
return std::array<CommandDispatch, sizeof...(i)>{{ { &SanitizeCmdStrings<static_cast<Commands>(i)>, &NetworkReplaceCommandClientId<static_cast<Commands>(i)>, MakeUnpackNetworkCommand<static_cast<Commands>(i)>(std::make_index_sequence<_callback_tuple_size>{}) }... }};
|
||||||
|
}
|
||||||
|
/** Command dispatch table. */
|
||||||
|
static constexpr auto _cmd_dispatch = MakeDispatchTable(std::make_integer_sequence<std::underlying_type_t<Commands>, CMD_END>{}, std::make_index_sequence<_callback_tuple_size>{});
|
||||||
|
|
||||||
|
#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,6 +219,20 @@ static CommandQueue _local_wait_queue;
|
||||||
static CommandQueue _local_execution_queue;
|
static CommandQueue _local_execution_queue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the callback index of a callback pointer.
|
||||||
|
* @param callback Address of callback to search for.
|
||||||
|
* @return Callback index or std::numeric_limits<size_t>::max() if the function wasn't found in the callback list.
|
||||||
|
*/
|
||||||
|
static size_t FindCallbackIndex(CommandCallback *callback)
|
||||||
|
{
|
||||||
|
if (auto it = std::find(std::cbegin(_callback_table), std::cend(_callback_table), callback); it != std::cend(_callback_table)) {
|
||||||
|
return static_cast<size_t>(std::distance(std::cbegin(_callback_table), it));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::numeric_limits<size_t>::max();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a DoCommand to be send over the network
|
* Prepare a DoCommand to be send over the network
|
||||||
* @param cmd The command to execute (a CMD_* value)
|
* @param cmd The command to execute (a CMD_* value)
|
||||||
|
@ -259,7 +313,9 @@ void NetworkExecuteLocalCommandQueue()
|
||||||
|
|
||||||
/* We can execute this command */
|
/* We can execute this command */
|
||||||
_current_company = cp->company;
|
_current_company = cp->company;
|
||||||
_cmd_dispatch[cp->cmd].Unpack(cp);
|
size_t cb_index = FindCallbackIndex(cp->callback);
|
||||||
|
assert(cb_index < _callback_tuple_size);
|
||||||
|
_cmd_dispatch[cp->cmd].Unpack[cb_index](cp);
|
||||||
|
|
||||||
queue.Pop();
|
queue.Pop();
|
||||||
delete cp;
|
delete cp;
|
||||||
|
@ -354,7 +410,7 @@ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *c
|
||||||
cp->data = _cmd_dispatch[cp->cmd].Sanitize(p->Recv_buffer());
|
cp->data = _cmd_dispatch[cp->cmd].Sanitize(p->Recv_buffer());
|
||||||
|
|
||||||
byte callback = p->Recv_uint8();
|
byte callback = p->Recv_uint8();
|
||||||
if (callback >= lengthof(_callback_table)) return "invalid callback";
|
if (callback >= _callback_table.size()) return "invalid callback";
|
||||||
|
|
||||||
cp->callback = _callback_table[callback];
|
cp->callback = _callback_table[callback];
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -373,16 +429,12 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
|
||||||
p->Send_uint32(cp->tile);
|
p->Send_uint32(cp->tile);
|
||||||
p->Send_buffer(cp->data);
|
p->Send_buffer(cp->data);
|
||||||
|
|
||||||
byte callback = 0;
|
size_t callback = FindCallbackIndex(cp->callback);
|
||||||
while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
|
if (callback > UINT8_MAX) {
|
||||||
callback++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback == lengthof(_callback_table)) {
|
|
||||||
Debug(net, 0, "Unknown callback for command; no callback sent (command: {})", cp->cmd);
|
Debug(net, 0, "Unknown callback for command; no callback sent (command: {})", cp->cmd);
|
||||||
callback = 0; // _callback_table[0] == nullptr
|
callback = 0; // _callback_table[0] == nullptr
|
||||||
}
|
}
|
||||||
p->Send_uint8 (callback);
|
p->Send_uint8 ((uint8)callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to process a single ClientID argument. */
|
/** Helper to process a single ClientID argument. */
|
||||||
|
@ -455,9 +507,15 @@ CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data)
|
||||||
return EndianBufferWriter<CommandDataBuffer>::FromValue(args);
|
return EndianBufferWriter<CommandDataBuffer>::FromValue(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Commands Tcmd>
|
/**
|
||||||
void UnpackNetworkCommand(const CommandPacket *cp)
|
* Unpack a generic command packet into its actual typed components.
|
||||||
|
* @tparam Tcmd Command type to be unpacked.
|
||||||
|
* @tparam Tcb Index into the callback list.
|
||||||
|
* @param cp Command packet to unpack.
|
||||||
|
*/
|
||||||
|
template <Commands Tcmd, size_t Tcb>
|
||||||
|
void UnpackNetworkCommand(const CommandPacket* cp)
|
||||||
{
|
{
|
||||||
auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp->data);
|
auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp->data);
|
||||||
Command<Tcmd>::PostFromNet(cp->err_msg, cp->callback, cp->my_cmd, cp->tile, args);
|
Command<Tcmd>::PostFromNet(cp->err_msg, std::get<Tcb>(_callback_tuple), cp->my_cmd, cp->tile, args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1538,7 +1538,7 @@ private:
|
||||||
if (_network_server) {
|
if (_network_server) {
|
||||||
Command<CMD_COMPANY_CTRL>::Post(CCA_NEW, INVALID_COMPANY, CRR_NONE, _network_own_client_id);
|
Command<CMD_COMPANY_CTRL>::Post(CCA_NEW, INVALID_COMPANY, CRR_NONE, _network_own_client_id);
|
||||||
} else {
|
} else {
|
||||||
Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
|
Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2081,7 +2081,7 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
|
||||||
/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
|
/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
|
||||||
ci->client_playas = c->index;
|
ci->client_playas = c->index;
|
||||||
NetworkUpdateClientInfo(ci->client_id);
|
NetworkUpdateClientInfo(ci->client_id);
|
||||||
Command<CMD_RENAME_PRESIDENT>::SendNet(STR_NULL, nullptr, c->index, ci->client_name);
|
Command<CMD_RENAME_PRESIDENT>::SendNet(STR_NULL, c->index, ci->client_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Announce new company on network. */
|
/* Announce new company on network. */
|
||||||
|
|
|
@ -198,7 +198,7 @@ CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, ClientID us
|
||||||
/* We need to circumvent the "prevention" from this command being executed
|
/* 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
|
* 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. */
|
* 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, static_cast<ClientID>(user) });
|
Command<CMD_CLEAR_ORDER_BACKUP>::Unsafe<CommandCallback>(STR_NULL, nullptr, true, false, ob->tile, CommandTraits<CMD_CLEAR_ORDER_BACKUP>::Args{ ob->tile, static_cast<ClientID>(user) });
|
||||||
} else {
|
} else {
|
||||||
/* The command came from the game logic, i.e. the clearing of a tile.
|
/* 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. */
|
* In that case we have no need to actually sync this, just do it. */
|
||||||
|
|
|
@ -1600,7 +1600,7 @@ void SyncCompanySettings()
|
||||||
const SettingDesc *sd = GetSettingDesc(desc);
|
const SettingDesc *sd = GetSettingDesc(desc);
|
||||||
uint32 old_value = (uint32)sd->AsIntSetting()->Read(new_object);
|
uint32 old_value = (uint32)sd->AsIntSetting()->Read(new_object);
|
||||||
uint32 new_value = (uint32)sd->AsIntSetting()->Read(old_object);
|
uint32 new_value = (uint32)sd->AsIntSetting()->Read(old_object);
|
||||||
if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, nullptr, _local_company, sd->GetName(), new_value);
|
if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue