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