1 //
2 //
3 
4 #ifndef FS2_OPEN_ADE_API_H_H
5 #define FS2_OPEN_ADE_API_H_H
6 
7 #include "globalincs/version.h"
8 
9 #include "scripting/ade.h"
10 #include "scripting/ade_args.h"
11 #include "scripting/ade_doc.h"
12 
13 namespace scripting {
14 
15 const size_t INVALID_ID = (size_t) -1; // Use -1 to get highest possible unsigned number
16 
17 /**
18  * @ingroup ade_api
19  */
20 class ade_lib_handle {
21   protected:
22 	size_t LibIdx;
23 
24   public:
25 	ade_lib_handle() = default;
26 
GetIdx()27 	size_t GetIdx() const { return LibIdx; }
28 };
29 
30 /**
31  * @ingroup ade_api
32  */
33 template <class StoreType>
34 class ade_obj : public ade_lib_handle {
lua_destructor(lua_State * L)35 	static int lua_destructor(lua_State* L)
36 	{
37 		auto* obj =
38 		    static_cast<ade_obj<StoreType>*>(lua_touserdata(L, lua_upvalueindex(ADE_DESTRUCTOR_OBJ_UPVALUE_INDEX)));
39 		StoreType* value = nullptr;
40 		if (!ade_get_args(L, "o", obj->GetPtr(&value))) {
41 			return 0;
42 		}
43 
44 		if (value == nullptr) {
45 			return 0;
46 		}
47 
48 		value->~StoreType();
49 		return 0;
50 	}
51 
52   public:
53 	ade_obj(const char* in_name, const char* in_desc, const ade_lib_handle* in_deriv = nullptr)
54 	{
55 		ade_table_entry ate;
56 
57 		// WMC - object metadata are uninstanced library types
58 		ate.Name = in_name;
59 		if (in_deriv != nullptr) {
60 			ate.DerivatorIdx = in_deriv->GetIdx();
61 		}
62 		ate.Type        = 'o';
63 		ate.Description = in_desc;
64 
65 		if (!std::is_trivially_destructible<StoreType>::value) {
66 			// If this type is not trivial then we need to have a destructor
67 			// This is mildly dangerous since "this" will only remain valid if it was constructed statically. Since this
68 			// value is only used once at program startup it should be relatively safe
69 			ate.Destructor_upvalue = static_cast<void*>(this);
70 			ate.Destructor         = lua_destructor;
71 		}
72 
73 		LibIdx = ade_manager::getInstance()->addTableEntry(ate);
74 	}
75 
76 	// WMC - Use this to store object data for return, or for setting as a global
Set(StoreType && obj)77 	ade_odata_setter<StoreType> Set(StoreType&& obj) const
78 	{
79 		return ade_odata_setter<StoreType>(LibIdx, std::move(obj));
80 	}
Set(const StoreType & obj)81 	ade_odata_setter<StoreType> Set(const StoreType& obj) const
82 	{
83 		return ade_odata_setter<StoreType>(LibIdx, obj);
84 	}
85 
86 	// WMC - Use this to copy object data, for modification or whatever
Get(StoreType * ptr)87 	ade_odata_getter<StoreType> Get(StoreType* ptr) const { return ade_odata_getter<StoreType>(LibIdx, ptr); }
88 
89 	// WMC - Use this to get a pointer to Lua object data.
90 	// Use >ONLY< when:
91 	// 1 - You are setting the data of an object (ie 'x' component of vector)
92 	// 2 - To speed up read-only calcs (ie computing dot product of vectors)
93 	// 3 - To get a reference to a move-only type stored in Lua memory
GetPtr(StoreType ** ptr)94 	ade_odata_ptr_getter<StoreType> GetPtr(StoreType** ptr) const
95 	{
96 		return ade_odata_ptr_getter<StoreType>(LibIdx, ptr);
97 	}
98 };
99 
100 /**
101  * @warning Utility macro. DO NOT USE!
102  */
103 #define ADE_OBJ_DERIV_IMPL(field, type, name, desc, deriv)                                                             \
104 	const ::scripting::ade_obj<type>& SCP_TOKEN_CONCAT(get_, field)()                                                  \
105 	{                                                                                                                  \
106 		static ::scripting::ade_obj<type> obj(name, desc, deriv);                                                      \
107 		return obj;                                                                                                    \
108 	}                                                                                                                  \
109 	const ::scripting::ade_obj<type>& field = SCP_TOKEN_CONCAT(get_, field)()
110 
111 /**
112  * @brief Define an API object
113  *
114  * An object is similar to a C++ class. Use this if you want to return a special type from a function that should be
115  * able to do more on its own.
116  *
117  * @param field The name of the field by which the class should be accessible
118  * @param type The type of the data the class contains
119  * @param name The name the class should have in the documentation
120  * @param desc Documentation about what this class is
121  *
122  * @ingroup ade_api
123  */
124 #define ADE_OBJ(field, type, name, desc) ADE_OBJ_DERIV_IMPL(field, type, name, desc, nullptr)
125 
126 /**
127  * @brief Define an API object that derives from another
128  *
129  * This is the same as ADE_OBJ but this allows to derive this class from another
130  *
131  * @param field The name of the field by which the class should be accessible
132  * @param type The type of the data the class contains
133  * @param name The name the class should have in the documentation
134  * @param desc Documentation about what this class is
135  * @param deriv The class to derive from. This should be the name of the class field (e.g. l_Object)
136  *
137  * @ingroup ade_api
138  */
139 #define ADE_OBJ_DERIV(field, type, name, desc, deriv)                                                                  \
140 	ADE_OBJ_DERIV_IMPL(field, type, name, desc, &SCP_TOKEN_CONCAT(get_, deriv)())
141 
142 /**
143  * @brief Declare an API object but don't define it
144  *
145  * You should use this in headers if the class should be able to be used by other files
146  *
147  * @param field The name of the field
148  * @param type The type of the contained value
149  *
150  * @ingroup ade_api
151  */
152 #define DECLARE_ADE_OBJ(field, type)                                                                                   \
153 	extern const ::scripting::ade_obj<type>& SCP_TOKEN_CONCAT(get_, field)();                                          \
154 	extern const ::scripting::ade_obj<type>& field
155 
156 /**
157  * Library class
158  * This is what you define a variable of to make new libraries
159  *
160  * @ingroup ade_api
161  */
162 class ade_lib : public ade_lib_handle {
163   public:
164 	explicit ade_lib(const char* in_name, const ade_lib_handle* parent = nullptr, const char* in_shortname = nullptr,
165 	                 const char* in_desc = nullptr);
166 
167 	const char* GetName() const;
168 };
169 /**
170  * @warning Utility macro. DO NOT USE!
171  */
172 #define ADE_LIB_IMPL(field, name, short_name, desc, parent)                                                            \
173 	const ::scripting::ade_lib& SCP_TOKEN_CONCAT(get_, field)()                                                        \
174 	{                                                                                                                  \
175 		static ::scripting::ade_lib lib(name, parent, short_name, desc);                                               \
176 		return lib;                                                                                                    \
177 	}                                                                                                                  \
178 	const ::scripting::ade_lib& field = SCP_TOKEN_CONCAT(get_, field)()
179 
180 /**
181  * @brief Define an API library
182  *
183  * A library is similar to a C++ namespace or a class with static functions. It can be used to group multiple functions
184  * together that serve a similar pupose
185  *
186  * @param field The name of the field by which the class should be ac
187  * @param name The name the class should have in the documentationcessible
188  * @param short_name The short name of the library, makes writing scripts easier
189  * @param desc Documentation about what this class is
190  *
191  * @ingroup ade_api
192  */
193 #define ADE_LIB(field, name, short_name, desc) ADE_LIB_IMPL(field, name, short_name, desc, nullptr)
194 
195 /**
196  * @brief Define an API library which is the child of another library
197  *
198  * A library is similar to a C++ namespace or a class with static functions. It can be used to group multiple functions
199  * together that serve a similar pupose.
200  *
201  * A sublibrary is basically a nested namespace
202  *
203  * @param field The name of the field by which the class should be ac
204  * @param name The name the class should have in the documentationcessible
205  * @param short_name The short name of the library, makes writing scripts easier
206  * @param desc Documentation about what this class is
207  * @param parent The parent library, this should be the field name, e.g. l_Base
208  *
209  * @ingroup ade_api
210  */
211 #define ADE_LIB_DERIV(field, name, short_name, desc, parent)                                                           \
212 	ADE_LIB_IMPL(field, name, short_name, desc, &SCP_TOKEN_CONCAT(get_, parent)())
213 
214 /**
215  * @brief Declare an API library but don't define it
216  *
217  * You should use this in headers if the library should be able to be used by other files
218  *
219  * @param field The name of the field, must match the name in the source file
220  *
221  * @ingroup ade_api
222  */
223 #define DECLARE_ADE_LIB(field)                                                                                         \
224 	extern const ::scripting::ade_lib& SCP_TOKEN_CONCAT(get_, field)();                                                \
225 	extern const ::scripting::ade_lib& field;                                                                          \
226 	static const ::scripting::ade_lib* SCP_TOKEN_CONCAT(field, reference_dummy) USED_VARIABLE = &(field)
227 
228 /**
229  * @ingroup ade_api
230  */
231 class ade_func : public ade_lib_handle {
232   public:
233 	ade_func(const char* name,
234 		lua_CFunction func,
235 		const ade_lib_handle& parent,
236 		ade_overload_list args,
237 		const char* desc,
238 		const char* ret_type,
239 		const char* ret_desc,
240 		const gameversion::version& deprecation_version,
241 		const char* deprecation_message);
242 };
243 
244 /**
245  * @brief Declare an API function
246  *
247  * Immediately after this macro the function body should follow.
248  *
249  * @param name The name of the function, this may not be a string
250  * @param parent The library or object containing this function
251  * @param args Documentation for parameters of the function
252  * @param desc Description of what the function does
253  * @param ret_type The type of the returned value
254  * @param ret_desc Documentation for the returned value
255  *
256  * @ingroup ade_api
257  */
258 #define ADE_FUNC(name, parent, args, desc, ret_type, ret_desc)                                                         \
259 	static int parent##_##name##_f(lua_State* L);                                                                      \
260 	::scripting::ade_func parent##_##name(#name, parent##_##name##_f, parent, args, desc, ret_type, ret_desc,          \
261 	                                      ::gameversion::version(), nullptr);                                          \
262 	static int parent##_##name##_f(lua_State* L)
263 
264 /**
265  * @brief Declare a deprecated API function
266  *
267  * Immediately after this macro the function body should follow. This function is marked as deprecated and will be
268  * handled specially if the targetted engine version is higher than the specified version.
269  *
270  * @param name The name of the function, this may not be a string
271  * @param parent The library or object containing this function
272  * @param args Documentation for parameters of the function
273  * @param desc Description of what the function does
274  * @param ret_type The type of the returned value
275  * @param ret_desc Documentation for the returned value
276  * @param deprecate_version Version starting from which this function is deprecated.
277  * @param deprecated_msg Message for the deprecation notice. May be nullptr.
278  *
279  * @ingroup ade_api
280  */
281 #define ADE_FUNC_DEPRECATED(name, parent, args, desc, ret_type, ret_desc, deprecate_version, deprecated_msg)           \
282 	static int parent##_##name##_f(lua_State* L);                                                                      \
283 	::scripting::ade_func parent##_##name(#name, parent##_##name##_f, parent, args, desc, ret_type, ret_desc,          \
284 	                                      deprecate_version, deprecated_msg);                                          \
285 	static int parent##_##name##_f(lua_State* L)
286 
287 /**
288  * @ingroup ade_api
289  */
290 class ade_virtvar : public ade_lib_handle {
291   public:
292 	ade_virtvar(const char* name,
293 		lua_CFunction func,
294 		const ade_lib_handle& parent,
295 		const char* args,
296 		const char* desc,
297 		const char* ret_type,
298 		const char* ret_desc,
299 		const gameversion::version& deprecation_version,
300 		const char* deprecation_message);
301 };
302 
303 /**
304  * @brief Declare an API variable
305  *
306  * Use this to handle forms of type vec.x and vec['x']. Basically an indexer for a specific variable. Format string
307  * should be "o*%", where * is indexing value, and % is the value to set to when LUA_SETTTING_VAR is set
308  *
309  * @param name The name of the variable, this may not be a string
310  * @param parent The library or object containing this field
311  * @param args Documentation for the type of the value that may be assigned
312  * @param desc Description of what the variable does
313  * @param ret_type The type of the returned value
314  * @param ret_desc Documentation for the returned value
315  *
316  * @ingroup ade_api
317  */
318 #define ADE_VIRTVAR(name, parent, args, desc, ret_type, ret_desc)                                                      \
319 	static int parent##_##name##_f(lua_State* L);                                                                      \
320 	::scripting::ade_virtvar parent##_##name(#name, parent##_##name##_f, parent, args, desc, ret_type, ret_desc,       \
321 	                                         ::gameversion::version(), nullptr);                                       \
322 	static int parent##_##name##_f(lua_State* L)
323 
324 /**
325  * @brief Declare a deprecated API variable
326  *
327  * Use this to handle forms of type vec.x and vec['x']. Basically an indexer for a specific variable. Format string
328  * should be "o*%", where * is indexing value, and % is the value to set to when LUA_SETTTING_VAR is set
329  *
330  * @param name The name of the variable, this may not be a string
331  * @param parent The library or object containing this field
332  * @param args Documentation for the type of the value that may be assigned
333  * @param desc Description of what the variable does
334  * @param ret_type The type of the returned value
335  * @param ret_desc Documentation for the returned value
336  * @param deprecate_version Version starting from which this function is deprecated.
337  * @param deprecated_msg Message for the deprecation notice. May be nullptr.
338  *
339  * @ingroup ade_api
340  */
341 #define ADE_VIRTVAR_DEPRECATED(name, parent, args, desc, ret_type, ret_desc, deprecate_version, deprecated_msg)        \
342 	static int parent##_##name##_f(lua_State* L);                                                                      \
343 	::scripting::ade_virtvar parent##_##name(#name, parent##_##name##_f, parent, args, desc, ret_type, ret_desc,       \
344 	                                         deprecate_version, deprecated_msg);                                       \
345 	static int parent##_##name##_f(lua_State* L)
346 
347 /**
348  * @ingroup ade_api
349  */
350 class ade_indexer : public ade_lib_handle {
351   public:
352 	ade_indexer(lua_CFunction func,
353 		const ade_lib_handle& parent,
354 		ade_overload_list overloads,
355 		const char* desc,
356 		const char* ret_type,
357 		const char* ret_desc);
358 };
359 
360 /**
361  * @brief Declare an indexer of an object
362  *
363  * Use this with objects to deal with forms such as vec.x, vec['x'], vec[0]. Format string should be "o*%", where * is
364  * indexing value, and % is the value to set to when LUA_SETTTING_VAR is set
365  *
366  * @param parent The library or object containing the indexer
367  * @param args Documentation for the type of the value that may be assigned
368  * @param desc Description of what the variable does
369  * @param ret_type The type of the returned value
370  * @param ret_desc Documentation for the returned value
371  *
372  * @ingroup ade_api
373  */
374 #define ADE_INDEXER(parent, args, desc, ret_type, ret_desc)                                                            \
375 	static int parent##___indexer_f(lua_State* L);                                                                     \
376 	::scripting::ade_indexer parent##___indexer(parent##___indexer_f, parent, args, desc, ret_type, ret_desc);         \
377 	static int parent##___indexer_f(lua_State* L)
378 
379 //*************************Lua return values*************************
380 /**
381  * @brief Return the Lua @c nil value
382  *
383  * @ingroup ade_api
384  */
385 #define ADE_RETURN_NIL				0
386 
387 /**
388  * @brief Return @c true from an API function
389  *
390  * @ingroup ade_api
391  */
392 #define ADE_RETURN_TRUE				ade_set_args(L, "b", true)
393 
394 /**
395  * @brief Return @c false from an API function
396  *
397  * @ingroup ade_api
398  */
399 #define ADE_RETURN_FALSE			ade_set_args(L, "b", false)
400 
401 }
402 
403 #endif //FS2_OPEN_ADE_API_H_H
404