Codechange: Template DoCommand to automagically reflect the parameters of the command proc.
When finished, this will allow each command handler to take individually different parameters, obliviating the need for bit-packing.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "command_type.h"
|
||||
#include "company_type.h"
|
||||
#include <vector>
|
||||
#include "tile_map.h"
|
||||
|
||||
/**
|
||||
* Define a default return value for a failed command.
|
||||
@@ -36,7 +37,6 @@ static const CommandCost CMD_ERROR = CommandCost(INVALID_STRING_ID);
|
||||
/** Storage buffer for serialized command data. */
|
||||
typedef std::vector<byte> CommandDataBuffer;
|
||||
|
||||
CommandCost DoCommand(DoCommandFlag flags, Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text = {});
|
||||
|
||||
bool DoCommandP(Commands cmd, StringID err_message, CommandCallback *callback, TileIndex tile, uint32 p1, uint32 p2, const std::string &text = {});
|
||||
bool DoCommandP(Commands cmd, StringID err_message, TileIndex tile, uint32 p1, uint32 p2, const std::string &text = {});
|
||||
@@ -58,12 +58,18 @@ const char *GetCommandName(Commands cmd);
|
||||
Money GetAvailableMoneyForCommand();
|
||||
bool IsCommandAllowedWhilePaused(Commands cmd);
|
||||
|
||||
template <Commands Tcmd>
|
||||
constexpr CommandFlags GetCommandFlags()
|
||||
{
|
||||
return CommandTraits<Tcmd>::flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the DC flags needed for DoCommand from the flags returned by GetCommandFlags
|
||||
* @param cmd_flags Flags from GetCommandFlags
|
||||
* @return flags for DoCommand
|
||||
*/
|
||||
static inline DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags)
|
||||
static constexpr inline DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags)
|
||||
{
|
||||
DoCommandFlag flags = DC_NONE;
|
||||
if (cmd_flags & CMD_NO_WATER) flags |= DC_NO_WATER;
|
||||
@@ -83,4 +89,67 @@ private:
|
||||
static int _counter;
|
||||
};
|
||||
|
||||
|
||||
template<Commands TCmd, typename T> struct CommandHelper;
|
||||
|
||||
class CommandHelperBase {
|
||||
protected:
|
||||
static void InternalDoBefore(bool top_level, bool test);
|
||||
static void InternalDoAfter(CommandCost &res, DoCommandFlag flags, bool top_level, bool test);
|
||||
};
|
||||
|
||||
/**
|
||||
* Templated wrapper that exposes the command parameter arguments
|
||||
* for the various Command::Do/Post calls.
|
||||
* @tparam Tcmd The command-id to execute.
|
||||
* @tparam Targs The command parameter types.
|
||||
*/
|
||||
template <Commands Tcmd, typename... Targs>
|
||||
struct CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...)> : protected CommandHelperBase {
|
||||
public:
|
||||
/**
|
||||
* This function executes a given command with the parameters from the #CommandProc parameter list.
|
||||
* Depending on the flags parameter it executes or tests a command.
|
||||
*
|
||||
* @note This function is to be called from the StateGameLoop or from within the execution of a Command.
|
||||
* This function must not be called from the context of a "player" (real person, AI, game script).
|
||||
* Use ::Post for commands directly triggered by "players".
|
||||
*
|
||||
* @param flags Flags for the command and how to execute the command
|
||||
* @param args Parameters for the command
|
||||
* @see CommandProc
|
||||
* @return the cost
|
||||
*/
|
||||
static CommandCost Do(DoCommandFlag flags, Targs... args)
|
||||
{
|
||||
if constexpr (std::is_same_v<TileIndex, std::tuple_element_t<0, std::tuple<Targs...>>>) {
|
||||
/* Do not even think about executing out-of-bounds tile-commands. */
|
||||
TileIndex tile = std::get<0>(std::make_tuple(args...));
|
||||
if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR;
|
||||
}
|
||||
|
||||
RecursiveCommandCounter counter{};
|
||||
|
||||
/* Only execute the test call if it's toplevel, or we're not execing. */
|
||||
if (counter.IsTopLevel() || !(flags & DC_EXEC)) {
|
||||
InternalDoBefore(counter.IsTopLevel(), true);
|
||||
CommandCost res = CommandTraits<Tcmd>::proc(flags & ~DC_EXEC, args...);
|
||||
InternalDoAfter(res, flags, counter.IsTopLevel(), true); // Can modify res.
|
||||
|
||||
if (res.Failed() || !(flags & DC_EXEC)) return res;
|
||||
}
|
||||
|
||||
/* Execute the command here. All cost-relevant functions set the expenses type
|
||||
* themselves to the cost object at some point. */
|
||||
InternalDoBefore(counter.IsTopLevel(), false);
|
||||
CommandCost res = CommandTraits<Tcmd>::proc(flags, args...);
|
||||
InternalDoAfter(res, flags, counter.IsTopLevel(), false);
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
template <Commands Tcmd>
|
||||
using Command = CommandHelper<Tcmd, typename CommandTraits<Tcmd>::ProcType>;
|
||||
|
||||
#endif /* COMMAND_FUNC_H */
|
||||
|
Reference in New Issue
Block a user