OpenTTD Source 20241224-master-gee860a5c8e
squirrel_helper.hpp
Go to the documentation of this file.
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 */
7
10#ifndef SQUIRREL_HELPER_HPP
11#define SQUIRREL_HELPER_HPP
12
13#include "squirrel.hpp"
14#include "../core/alloc_func.hpp"
15#include "../economy_type.h"
16#include "../string_func.h"
17#include "../tile_type.h"
19
20template <class CL, ScriptType ST> const char *GetClassName();
21
25namespace SQConvert {
30 template <typename T> struct Return;
31
32 template <> struct Return<uint8_t> { static inline int Set(HSQUIRRELVM vm, uint8_t res) { sq_pushinteger(vm, (int32_t)res); return 1; } };
33 template <> struct Return<uint16_t> { static inline int Set(HSQUIRRELVM vm, uint16_t res) { sq_pushinteger(vm, (int32_t)res); return 1; } };
34 template <> struct Return<uint32_t> { static inline int Set(HSQUIRRELVM vm, uint32_t res) { sq_pushinteger(vm, (int32_t)res); return 1; } };
35 template <> struct Return<int8_t> { static inline int Set(HSQUIRRELVM vm, int8_t res) { sq_pushinteger(vm, res); return 1; } };
36 template <> struct Return<int16_t> { static inline int Set(HSQUIRRELVM vm, int16_t res) { sq_pushinteger(vm, res); return 1; } };
37 template <> struct Return<int32_t> { static inline int Set(HSQUIRRELVM vm, int32_t res) { sq_pushinteger(vm, res); return 1; } };
38 template <> struct Return<int64_t> { static inline int Set(HSQUIRRELVM vm, int64_t res) { sq_pushinteger(vm, res); return 1; } };
39 template <> struct Return<Money> { static inline int Set(HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } };
40 template <> struct Return<TileIndex> { static inline int Set(HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32_t)res.base()); return 1; } };
41 template <> struct Return<bool> { static inline int Set(HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } };
42 template <> struct Return<char *> { /* Do not use char *, use std::optional<std::string> instead. */ };
43 template <> struct Return<const char *> { /* Do not use const char *, use std::optional<std::string> instead. */ };
44 template <> struct Return<void *> { static inline int Set(HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } };
45 template <> struct Return<HSQOBJECT> { static inline int Set(HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } };
46
47 template <> struct Return<std::optional<std::string>> {
48 static inline int Set(HSQUIRRELVM vm, std::optional<std::string> res)
49 {
50 if (res.has_value()) {
51 sq_pushstring(vm, res.value(), -1);
52 } else {
53 sq_pushnull(vm);
54 }
55 return 1;
56 }
57 };
58
63 template <typename T> struct Param;
64
65 template <> struct Param<uint8_t> { static inline uint8_t Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
66 template <> struct Param<uint16_t> { static inline uint16_t Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
67 template <> struct Param<uint32_t> { static inline uint32_t Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
68 template <> struct Param<int8_t> { static inline int8_t Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
69 template <> struct Param<int16_t> { static inline int16_t Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
70 template <> struct Param<int32_t> { static inline int32_t Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
71 template <> struct Param<int64_t> { static inline int64_t Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
72 template <> struct Param<TileIndex> { static inline TileIndex Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32_t)(int32_t)tmp); } };
73 template <> struct Param<Money> { static inline Money Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
74 template <> struct Param<bool> { static inline bool Get(HSQUIRRELVM vm, int index) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } };
75 template <> struct Param<const char *> { /* Do not use const char *, use std::string& instead. */ };
76 template <> struct Param<void *> { static inline void *Get(HSQUIRRELVM vm, int index) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } };
77
78 template <> struct Param<const std::string &> {
79 static inline const std::string Get(HSQUIRRELVM vm, int index)
80 {
81 /* Convert what-ever there is as parameter to a string */
82 sq_tostring(vm, index);
83
84 const SQChar *tmp;
85 sq_getstring(vm, -1, &tmp);
86 std::string result = StrMakeValid(tmp);
87 sq_poptop(vm);
88 return result;
89 }
90 };
91
92 template <typename Titem>
93 struct Param<Array<Titem> &&> {
94 static inline Array<Titem> Get(HSQUIRRELVM vm, int index)
95 {
96 /* Sanity check of the size. */
97 if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large");
98
99 SQObject obj;
100 sq_getstackobj(vm, index, &obj);
101 sq_pushobject(vm, obj);
102 sq_pushnull(vm);
103
104 Array<Titem> data;
105
106 while (SQ_SUCCEEDED(sq_next(vm, -2))) {
107 data.emplace_back(Param<Titem>::Get(vm, -1));
108 sq_pop(vm, 2);
109 }
110 sq_pop(vm, 2);
111
112 return data;
113 }
114 };
115
121 template <typename Tfunc> struct HelperT;
122
126 template <typename Tretval, typename... Targs>
127 struct HelperT<Tretval (*)(Targs...)> {
128 static int SQCall(void *instance, Tretval(*func)(Targs...), HSQUIRRELVM vm)
129 {
130 return SQCall(instance, func, vm, std::index_sequence_for<Targs...>{});
131 }
132
133 private:
134 template <size_t... i>
135 static int SQCall(void *, Tretval(*func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
136 {
137 if constexpr (std::is_void_v<Tretval>) {
138 (*func)(
139 Param<Targs>::Get(vm, 2 + i)...
140 );
141 return 0;
142 } else {
143 Tretval ret = (*func)(
144 Param<Targs>::Get(vm, 2 + i)...
145 );
146 return Return<Tretval>::Set(vm, ret);
147 }
148 }
149 };
150
154 template <class Tcls, typename Tretval, typename... Targs>
155 struct HelperT<Tretval(Tcls:: *)(Targs...)> {
156 static int SQCall(Tcls *instance, Tretval(Tcls:: *func)(Targs...), HSQUIRRELVM vm)
157 {
158 return SQCall(instance, func, vm, std::index_sequence_for<Targs...>{});
159 }
160
161 static Tcls *SQConstruct(Tcls *instance, Tretval(Tcls:: *func)(Targs...), HSQUIRRELVM vm)
162 {
163 return SQConstruct(instance, func, vm, std::index_sequence_for<Targs...>{});
164 }
165
166 private:
167 template <size_t... i>
168 static int SQCall(Tcls *instance, Tretval(Tcls:: *func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
169 {
170 if constexpr (std::is_void_v<Tretval>) {
171 (instance->*func)(
172 Param<Targs>::Get(vm, 2 + i)...
173 );
174 return 0;
175 } else {
176 Tretval ret = (instance->*func)(
177 Param<Targs>::Get(vm, 2 + i)...
178 );
179 return Return<Tretval>::Set(vm, ret);
180 }
181 }
182
183 template <size_t... i>
184 static Tcls *SQConstruct(Tcls *, Tretval(Tcls:: *)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
185 {
186 Tcls *inst = new Tcls(
187 Param<Targs>::Get(vm, 2 + i)...
188 );
189
190 return inst;
191 }
192 };
193
194
200 template <typename Tcls, typename Tmethod, ScriptType Ttype>
201 inline SQInteger DefSQNonStaticCallback(HSQUIRRELVM vm)
202 {
203 /* Find the amount of params we got */
204 int nparam = sq_gettop(vm);
205 SQUserPointer ptr = nullptr;
206 SQUserPointer real_instance = nullptr;
207 HSQOBJECT instance;
208
209 /* Get the 'SQ' instance of this class */
210 Squirrel::GetInstance(vm, &instance);
211
212 /* Protect against calls to a non-static method in a static way */
213 sq_pushroottable(vm);
214 const char *className = GetClassName<Tcls, Ttype>();
215 sq_pushstring(vm, className, -1);
216 sq_get(vm, -2);
217 sq_pushobject(vm, instance);
218 if (sq_instanceof(vm) != SQTrue) return sq_throwerror(vm, "class method is non-static");
219 sq_pop(vm, 3);
220
221 /* Get the 'real' instance of this class */
222 sq_getinstanceup(vm, 1, &real_instance, nullptr);
223 /* Get the real function pointer */
224 sq_getuserdata(vm, nparam, &ptr, nullptr);
225 if (real_instance == nullptr) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call");
226 /* Remove the userdata from the stack */
227 sq_pop(vm, 1);
228
229 try {
230 /* Delegate it to a template that can handle this specific function */
231 return HelperT<Tmethod>::SQCall((Tcls *)real_instance, *(Tmethod *)ptr, vm);
232 } catch (SQInteger &e) {
233 return e;
234 }
235 }
236
242 template <typename Tcls, typename Tmethod, ScriptType Ttype>
243 inline SQInteger DefSQAdvancedNonStaticCallback(HSQUIRRELVM vm)
244 {
245 /* Find the amount of params we got */
246 int nparam = sq_gettop(vm);
247 SQUserPointer ptr = nullptr;
248 SQUserPointer real_instance = nullptr;
249 HSQOBJECT instance;
250
251 /* Get the 'SQ' instance of this class */
252 Squirrel::GetInstance(vm, &instance);
253
254 /* Protect against calls to a non-static method in a static way */
255 sq_pushroottable(vm);
256 const char *className = GetClassName<Tcls, Ttype>();
257 sq_pushstring(vm, className, -1);
258 sq_get(vm, -2);
259 sq_pushobject(vm, instance);
260 if (sq_instanceof(vm) != SQTrue) return sq_throwerror(vm, "class method is non-static");
261 sq_pop(vm, 3);
262
263 /* Get the 'real' instance of this class */
264 sq_getinstanceup(vm, 1, &real_instance, nullptr);
265 /* Get the real function pointer */
266 sq_getuserdata(vm, nparam, &ptr, nullptr);
267 if (real_instance == nullptr) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call");
268 /* Remove the userdata from the stack */
269 sq_pop(vm, 1);
270
271 /* Call the function, which its only param is always the VM */
272 return (SQInteger)(((Tcls *)real_instance)->*(*(Tmethod *)ptr))(vm);
273 }
274
280 template <typename Tcls, typename Tmethod>
281 inline SQInteger DefSQStaticCallback(HSQUIRRELVM vm)
282 {
283 /* Find the amount of params we got */
284 int nparam = sq_gettop(vm);
285 SQUserPointer ptr = nullptr;
286
287 /* Get the real function pointer */
288 sq_getuserdata(vm, nparam, &ptr, nullptr);
289
290 try {
291 /* Delegate it to a template that can handle this specific function */
292 return HelperT<Tmethod>::SQCall((Tcls *)nullptr, *(Tmethod *)ptr, vm);
293 } catch (SQInteger &e) {
294 return e;
295 }
296 }
297
298
304 template <typename Tcls, typename Tmethod>
305 inline SQInteger DefSQAdvancedStaticCallback(HSQUIRRELVM vm)
306 {
307 /* Find the amount of params we got */
308 int nparam = sq_gettop(vm);
309 SQUserPointer ptr = nullptr;
310
311 /* Get the real function pointer */
312 sq_getuserdata(vm, nparam, &ptr, nullptr);
313 /* Remove the userdata from the stack */
314 sq_pop(vm, 1);
315
316 /* Call the function, which its only param is always the VM */
317 return (SQInteger)(*(*(Tmethod *)ptr))(vm);
318 }
319
324 template <typename Tcls>
325 static SQInteger DefSQDestructorCallback(SQUserPointer p, SQInteger)
326 {
327 /* Remove the real instance too */
328 if (p != nullptr) ((Tcls *)p)->Release();
329 return 0;
330 }
331
337 template <typename Tcls, typename Tmethod, int Tnparam>
338 inline SQInteger DefSQConstructorCallback(HSQUIRRELVM vm)
339 {
340 try {
341 /* Create the real instance */
342 Tcls *instance = HelperT<Tmethod>::SQConstruct((Tcls *)nullptr, (Tmethod)nullptr, vm);
343 sq_setinstanceup(vm, -Tnparam, instance);
344 sq_setreleasehook(vm, -Tnparam, DefSQDestructorCallback<Tcls>);
345 instance->AddRef();
346 return 0;
347 } catch (SQInteger &e) {
348 return e;
349 }
350 }
351
356 template <typename Tcls>
357 inline SQInteger DefSQAdvancedConstructorCallback(HSQUIRRELVM vm)
358 {
359 try {
360 /* Find the amount of params we got */
361 int nparam = sq_gettop(vm);
362
363 /* Create the real instance */
364 Tcls *instance = new Tcls(vm);
365 sq_setinstanceup(vm, -nparam, instance);
366 sq_setreleasehook(vm, -nparam, DefSQDestructorCallback<Tcls>);
367 instance->AddRef();
368 return 0;
369 } catch (SQInteger &e) {
370 return e;
371 }
372 }
373
374} // namespace SQConvert
375
376#endif /* SQUIRREL_HELPER_HPP */
static bool GetInstance(HSQUIRRELVM vm, HSQOBJECT *ptr, int pos=1)
Get the Squirrel-instance pointer.
Definition squirrel.hpp:200
The Squirrel convert routines.
SQInteger DefSQAdvancedConstructorCallback(HSQUIRRELVM vm)
A general template to handle creating of an instance with a complex constructor.
static SQInteger DefSQDestructorCallback(SQUserPointer p, SQInteger)
A general template for the destructor of SQ instances.
SQInteger DefSQAdvancedStaticCallback(HSQUIRRELVM vm)
A general template for all static advanced method callbacks from Squirrel.
SQInteger DefSQConstructorCallback(HSQUIRRELVM vm)
A general template to handle creating of instance with any amount of params.
SQInteger DefSQAdvancedNonStaticCallback(HSQUIRRELVM vm)
A general template for all non-static advanced method callbacks from Squirrel.
SQInteger DefSQNonStaticCallback(HSQUIRRELVM vm)
A general template for all non-static method callbacks from Squirrel.
SQInteger DefSQStaticCallback(HSQUIRRELVM vm)
A general template for all function/static method callbacks from Squirrel.
defines the Squirrel class
Helper structs for converting Squirrel data structures to C++.
std::vector< Titem > Array
Definition of a simple array.
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:107
Helper class to recognize the function type (retval type, args) and use the proper specialization for...
To get a param from squirrel, we use this helper class.
To return a value to squirrel, we use this helper class.
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.
Definition tile_type.h:87