Codechange: Template script command calls.

This commit is contained in:
Michael Lutz
2021-11-01 21:30:34 +01:00
parent eab18f06a4
commit 6691ee3b96
30 changed files with 310 additions and 185 deletions

View File

@@ -13,7 +13,8 @@
#include "../../misc/countedptr.hpp"
#include "../../road_type.h"
#include "../../rail_type.h"
#include "../../command_type.h"
#include "../../string_func.h"
#include "../../command_func.h"
#include "script_types.hpp"
#include "../script_suspend.hpp"
@@ -67,10 +68,32 @@ public:
static class ScriptInstance *GetActiveInstance();
protected:
template<Commands TCmd, typename T> struct ScriptDoCommandHelper;
/**
* Executes a raw DoCommand for the script.
* Templated wrapper that exposes the command parameter arguments
* on the various DoCommand calls.
* @tparam Tcmd The command-id to execute.
* @tparam Targs The command parameter types.
*/
static bool DoCommand(TileIndex tile, uint32 p1, uint32 p2, Commands cmd, const char *text = nullptr, Script_SuspendCallbackProc *callback = nullptr);
template <Commands Tcmd, typename... Targs>
struct ScriptDoCommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...)> {
static bool Do(Script_SuspendCallbackProc *callback, Targs... args)
{
return Execute(callback, std::forward_as_tuple(args...));
}
static bool Do(Targs... args)
{
return Execute(nullptr, std::forward_as_tuple(args...));
}
private:
static bool Execute(Script_SuspendCallbackProc *callback, std::tuple<Targs...> args);
};
template <Commands Tcmd>
using Command = ScriptDoCommandHelper<Tcmd, typename ::CommandTraits<Tcmd>::ProcType>;
/**
* Store the latest command executed by the script.
@@ -299,6 +322,58 @@ private:
* @param story_page_id The new StoryPageID.
*/
static void SetNewStoryPageElementID(StoryPageElementID story_page_element_id);
/* Helper functions for DoCommand. */
static std::tuple<bool, bool, bool> DoCommandPrep();
static bool DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only);
static CommandCallback *GetDoCommandCallback();
};
namespace ScriptObjectInternal {
/** Validate a single string argument coming from network. */
template <class T>
static inline void SanitizeSingleStringHelper(T &data)
{
if constexpr (std::is_same_v<std::string, T>) {
/* The string must be valid, i.e. not contain special codes. Since some
* can be made with GSText, make sure the control codes are removed. */
data = ::StrMakeValid(data, SVS_NONE);
}
}
/** Helper function to perform validation on command data strings. */
template<class Ttuple, size_t... Tindices>
static inline void SanitizeStringsHelper(Ttuple &values, std::index_sequence<Tindices...>)
{
((SanitizeSingleStringHelper(std::get<Tindices>(values))), ...);
}
}
template <Commands Tcmd, typename... Targs>
bool ScriptObject::ScriptDoCommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...)>::Execute(Script_SuspendCallbackProc *callback, std::tuple<Targs...> args)
{
auto [err, estimate_only, networking] = ScriptObject::DoCommandPrep();
if (err) return false;
if ((::GetCommandFlags<Tcmd>() & CMD_STR_CTRL) == 0) {
ScriptObjectInternal::SanitizeStringsHelper(args, std::index_sequence_for<Targs...>{});
}
TileIndex tile{};
if constexpr (std::is_same_v<TileIndex, std::tuple_element_t<0, decltype(args)>>) {
tile = std::get<0>(args);
}
/* Only set p2 when the command does not come from the network. */
if ((::GetCommandFlags<Tcmd>() & CMD_CLIENT_ID) != 0 && std::get<2>(args) == 0) std::get<2>(args) = UINT32_MAX;
/* Store the command for command callback validation. */
if (!estimate_only && networking) ScriptObject::SetLastCommand(tile, EndianBufferWriter<CommandDataBuffer>::FromValue(args), Tcmd);
/* Try to perform the command. */
CommandCost res = std::apply(&DoCommandPInternal, std::tuple_cat(std::make_tuple(Tcmd, (StringID)0, networking ? ScriptObject::GetDoCommandCallback() : nullptr, false, estimate_only, false), args));
return ScriptObject::DoCommandProcessResult(res, callback, estimate_only);
}
#endif /* SCRIPT_OBJECT_HPP */