Update: Translations from eints
[openttd-github.git] / src / script / api / script_object.hpp
blob28cac81d59f4db748443fbe841e6bd61dc95bed3
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file script_object.hpp Main object, on which all objects depend. */
10 #ifndef SCRIPT_OBJECT_HPP
11 #define SCRIPT_OBJECT_HPP
13 #include "../../misc/countedptr.hpp"
14 #include "../../road_type.h"
15 #include "../../rail_type.h"
16 #include "../../string_func.h"
17 #include "../../command_func.h"
18 #include "../../core/random_func.hpp"
20 #include "script_types.hpp"
21 #include "script_log_types.hpp"
22 #include "../script_suspend.hpp"
23 #include "../squirrel.hpp"
25 #include <utility>
27 /**
28 * The callback function for Mode-classes.
30 typedef bool (ScriptModeProc)();
32 /**
33 * The callback function for Async Mode-classes.
35 typedef bool (ScriptAsyncModeProc)();
37 /**
38 * Uper-parent object of all API classes. You should never use this class in
39 * your script, as it doesn't publish any public functions. It is used
40 * internally to have a common place to handle general things, like internal
41 * command processing, and command-validation checks.
42 * @api none
44 class ScriptObject : public SimpleCountedObject {
45 friend class ScriptInstance;
46 friend class ScriptController;
47 friend class TestScriptController;
48 protected:
49 /**
50 * A class that handles the current active instance. By instantiating it at
51 * the beginning of a function with the current active instance, it remains
52 * active till the scope of the variable closes. It then automatically
53 * reverts to the active instance it was before instantiating.
55 class ActiveInstance {
56 friend class ScriptObject;
57 public:
58 ActiveInstance(ScriptInstance *instance);
59 ~ActiveInstance();
60 private:
61 ScriptInstance *last_active; ///< The active instance before we go instantiated.
62 ScriptAllocatorScope alc_scope; ///< Keep the correct allocator for the script instance activated
64 static ScriptInstance *active; ///< The global current active instance.
67 public:
68 /**
69 * Store the latest result of a DoCommand per company.
70 * @param res The result of the last command.
72 static void SetLastCommandRes(bool res);
74 /**
75 * Store the extra data return by the last DoCommand.
76 * @param data Extra data return by the command.
78 static void SetLastCommandResData(CommandDataBuffer data);
80 /**
81 * Get the currently active instance.
82 * @return The instance.
84 static class ScriptInstance *GetActiveInstance();
86 /**
87 * Get a reference of the randomizer that brings this script random values.
88 * @param owner The owner/script to get the randomizer for. This defaults to ScriptObject::GetRootCompany()
90 static Randomizer &GetRandomizer(Owner owner = ScriptObject::GetRootCompany());
92 /**
93 * Initialize/reset the script random states. The state of the scripts are
94 * based on the current _random seed, but _random does not get changed.
96 static void InitializeRandomizers();
98 protected:
99 template<Commands TCmd, typename T> struct ScriptDoCommandHelper;
102 * Templated wrapper that exposes the command parameter arguments
103 * on the various DoCommand calls.
104 * @tparam Tcmd The command-id to execute.
105 * @tparam Tret Return type of the command.
106 * @tparam Targs The command parameter types.
108 template <Commands Tcmd, typename Tret, typename... Targs>
109 struct ScriptDoCommandHelper<Tcmd, Tret(*)(DoCommandFlag, Targs...)> {
110 static bool Do(Script_SuspendCallbackProc *callback, Targs... args)
112 return Execute(callback, std::forward_as_tuple(args...));
115 static bool Do(Targs... args)
117 return Execute(nullptr, std::forward_as_tuple(args...));
120 private:
121 static bool Execute(Script_SuspendCallbackProc *callback, std::tuple<Targs...> args);
124 template <Commands Tcmd>
125 using Command = ScriptDoCommandHelper<Tcmd, typename ::CommandTraits<Tcmd>::ProcType>;
128 * Store the latest command executed by the script.
130 static void SetLastCommand(const CommandDataBuffer &data, Commands cmd);
133 * Check if it's the latest command executed by the script.
135 static bool CheckLastCommand(const CommandDataBuffer &data, Commands cmd);
138 * Sets the DoCommand costs counter to a value.
140 static void SetDoCommandCosts(Money value);
143 * Increase the current value of the DoCommand costs counter.
145 static void IncreaseDoCommandCosts(Money value);
148 * Get the current DoCommand costs counter.
150 static Money GetDoCommandCosts();
153 * Set the DoCommand last error.
155 static void SetLastError(ScriptErrorType last_error);
158 * Get the DoCommand last error.
160 static ScriptErrorType GetLastError();
163 * Set the road type.
165 static void SetRoadType(RoadType road_type);
168 * Get the road type.
170 static RoadType GetRoadType();
173 * Set the rail type.
175 static void SetRailType(RailType rail_type);
178 * Get the rail type.
180 static RailType GetRailType();
183 * Set the current mode of your script to this proc.
185 static void SetDoCommandMode(ScriptModeProc *proc, ScriptObject *instance);
188 * Get the current mode your script is currently under.
190 static ScriptModeProc *GetDoCommandMode();
193 * Get the instance of the current mode your script is currently under.
195 static ScriptObject *GetDoCommandModeInstance();
198 * Set the current async mode of your script to this proc.
200 static void SetDoCommandAsyncMode(ScriptAsyncModeProc *proc, ScriptObject *instance);
203 * Get the current async mode your script is currently under.
205 static ScriptModeProc *GetDoCommandAsyncMode();
208 * Get the instance of the current async mode your script is currently under.
210 static ScriptObject *GetDoCommandAsyncModeInstance();
213 * Set the delay of the DoCommand.
215 static void SetDoCommandDelay(uint ticks);
218 * Get the delay of the DoCommand.
220 static uint GetDoCommandDelay();
223 * Get the latest result of a DoCommand.
225 static bool GetLastCommandRes();
228 * Get the extra return data from the last DoCommand.
230 static const CommandDataBuffer &GetLastCommandResData();
233 * Store a allow_do_command per company.
234 * @param allow The new allow.
236 static void SetAllowDoCommand(bool allow);
239 * Get the internal value of allow_do_command. This can differ
240 * from CanSuspend() if the reason we are not allowed
241 * to execute a DoCommand is in squirrel and not the API.
242 * In that case use this function to restore the previous value.
243 * @return True iff DoCommands are allowed in the current scope.
245 static bool GetAllowDoCommand();
248 * Set the current company to execute commands for or request
249 * information about.
250 * @param company The new company.
252 static void SetCompany(CompanyID company);
255 * Get the current company we are executing commands for or
256 * requesting information about.
257 * @return The current company.
259 static CompanyID GetCompany();
262 * Get the root company, the company that the script really
263 * runs under / for.
264 * @return The root company.
266 static CompanyID GetRootCompany();
269 * Set the cost of the last command.
271 static void SetLastCost(Money last_cost);
274 * Get the cost of the last command.
276 static Money GetLastCost();
279 * Set a variable that can be used by callback functions to pass information.
281 static void SetCallbackVariable(int index, int value);
284 * Get the variable that is used by callback functions to pass information.
286 static int GetCallbackVariable(int index);
289 * Can we suspend the script at this moment?
291 static bool CanSuspend();
294 * Get the pointer to store event data in.
296 static void *&GetEventPointer();
299 * Get the pointer to store log message in.
301 static ScriptLogTypes::LogData &GetLogData();
304 * Get an allocated string with all control codes stripped off.
306 static std::string GetString(StringID string);
308 private:
309 /* Helper functions for DoCommand. */
310 static std::tuple<bool, bool, bool, bool> DoCommandPrep();
311 static bool DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only, bool asynchronous);
312 static CommandCallbackData *GetDoCommandCallback();
313 static Randomizer random_states[OWNER_END]; ///< Random states for each of the scripts (game script uses OWNER_DEITY)
316 namespace ScriptObjectInternal {
317 /** Validate a single string argument coming from network. */
318 template <class T>
319 static inline void SanitizeSingleStringHelper(T &data)
321 if constexpr (std::is_same_v<std::string, T>) {
322 /* The string must be valid, i.e. not contain special codes. Since some
323 * can be made with GSText, make sure the control codes are removed. */
324 data = ::StrMakeValid(data, SVS_NONE);
328 /** Helper function to perform validation on command data strings. */
329 template<class Ttuple, size_t... Tindices>
330 static inline void SanitizeStringsHelper(Ttuple &values, std::index_sequence<Tindices...>)
332 ((SanitizeSingleStringHelper(std::get<Tindices>(values))), ...);
335 /** Helper to process a single ClientID argument. */
336 template <class T>
337 static inline void SetClientIdHelper(T &data)
339 if constexpr (std::is_same_v<ClientID, T>) {
340 if (data == INVALID_CLIENT_ID) data = (ClientID)UINT32_MAX;
344 /** Set all invalid ClientID's to the proper value. */
345 template<class Ttuple, size_t... Tindices>
346 static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
348 ((SetClientIdHelper(std::get<Tindices>(values))), ...);
351 /** Remove the first element of a tuple. */
352 template <template <typename...> typename Tt, typename T1, typename... Ts>
353 static inline Tt<Ts...> RemoveFirstTupleElement(const Tt<T1, Ts...> &tuple)
355 return std::apply([](auto &&, const auto&... args) { return std::tie(args...); }, tuple);
359 template <Commands Tcmd, typename Tret, typename... Targs>
360 bool ScriptObject::ScriptDoCommandHelper<Tcmd, Tret(*)(DoCommandFlag, Targs...)>::Execute(Script_SuspendCallbackProc *callback, std::tuple<Targs...> args)
362 auto [err, estimate_only, asynchronous, networking] = ScriptObject::DoCommandPrep();
363 if (err) return false;
365 if ((::GetCommandFlags<Tcmd>() & CMD_STR_CTRL) == 0) {
366 ScriptObjectInternal::SanitizeStringsHelper(args, std::index_sequence_for<Targs...>{});
369 TileIndex tile{};
370 if constexpr (std::is_same_v<TileIndex, std::tuple_element_t<0, decltype(args)>>) {
371 tile = std::get<0>(args);
374 /* Do not even think about executing out-of-bounds tile-commands. */
375 if (tile != 0 && (tile >= Map::Size() || (!IsValidTile(tile) && (GetCommandFlags<Tcmd>() & CMD_ALL_TILES) == 0))) return false;
377 /* Only set ClientID parameters when the command does not come from the network. */
378 if constexpr ((::GetCommandFlags<Tcmd>() & CMD_CLIENT_ID) != 0) ScriptObjectInternal::SetClientIds(args, std::index_sequence_for<Targs...>{});
380 /* Store the command for command callback validation. */
381 if (!estimate_only && networking) ScriptObject::SetLastCommand(EndianBufferWriter<CommandDataBuffer>::FromValue(args), Tcmd);
383 /* Try to perform the command. */
384 Tret res = ::Command<Tcmd>::Unsafe((StringID)0, networking ? ScriptObject::GetDoCommandCallback() : nullptr, false, estimate_only, tile, args);
386 if constexpr (std::is_same_v<Tret, CommandCost>) {
387 return ScriptObject::DoCommandProcessResult(res, callback, estimate_only, asynchronous);
388 } else {
389 ScriptObject::SetLastCommandResData(EndianBufferWriter<CommandDataBuffer>::FromValue(ScriptObjectInternal::RemoveFirstTupleElement(res)));
390 return ScriptObject::DoCommandProcessResult(std::get<0>(res), callback, estimate_only, asynchronous);
395 * Internally used class to automate the ScriptObject reference counting.
396 * @api -all
398 template <typename T>
399 class ScriptObjectRef {
400 private:
401 T *data; ///< The reference counted object.
402 public:
404 * Create the reference counter for the given ScriptObject instance.
405 * @param data The underlying object.
407 ScriptObjectRef(T *data) : data(data)
409 this->data->AddRef();
412 /* No copy constructor. */
413 ScriptObjectRef(const ScriptObjectRef<T> &ref) = delete;
415 /* Move constructor. */
416 ScriptObjectRef(ScriptObjectRef<T> &&ref) noexcept : data(std::exchange(ref.data, nullptr))
420 /* No copy assignment. */
421 ScriptObjectRef& operator=(const ScriptObjectRef<T> &other) = delete;
423 /* Move assignment. */
424 ScriptObjectRef& operator=(ScriptObjectRef<T> &&other) noexcept
426 std::swap(this->data, other.data);
427 return *this;
431 * Release the reference counted object.
433 ~ScriptObjectRef()
435 if (this->data != nullptr) this->data->Release();
439 * Dereferencing this reference returns a reference to the reference
440 * counted object
441 * @return Reference to the underlying object.
443 T &operator*()
445 return *this->data;
449 * The arrow operator on this reference returns the reference counted object.
450 * @return Pointer to the underlying object.
452 T *operator->()
454 return this->data;
458 #endif /* SCRIPT_OBJECT_HPP */