@@ -71,9 +71,9 @@ class Wrapped {
71
71
static GDExtensionBool property_get_revert_bind (GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false ; }
72
72
static void to_string_bind (GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {}
73
73
74
+ // The only reason this has to be held here, is when we return results of `_get_property_list` to Godot, we pass
75
+ // pointers to strings in this list. They have to remain valid to pass the bridge, until the list is freed by Godot...
74
76
::godot::List<::godot::PropertyInfo> plist_owned;
75
- GDExtensionPropertyInfo *plist = nullptr ;
76
- uint32_t plist_size = 0 ;
77
77
78
78
void _postinitialize ();
79
79
@@ -95,9 +95,19 @@ class Wrapped {
95
95
GodotObject *_owner = nullptr ;
96
96
};
97
97
98
+ namespace internal {
99
+
100
+ GDExtensionPropertyInfo *create_c_property_list (const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size);
101
+ void free_c_property_list (GDExtensionPropertyInfo *plist);
102
+
103
+ } // namespace internal
104
+
98
105
} // namespace godot
99
106
100
- #define GDCLASS (m_class, m_inherits ) \
107
+ // Use this on top of your own classes.
108
+ // Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
109
+ // every line of the macro different
110
+ #define GDCLASS (m_class, m_inherits ) /* **********************************************************************************************************************************************/ \
101
111
private: \
102
112
void operator =(const m_class &p_rval) {} \
103
113
friend class ::godot::ClassDB; \
@@ -209,40 +219,29 @@ public:
209
219
return false ; \
210
220
} \
211
221
\
222
+ static inline bool has_get_property_list () { \
223
+ return m_class::_get_get_property_list () && m_class::_get_get_property_list () != m_inherits::_get_get_property_list (); \
224
+ } \
225
+ \
212
226
static const GDExtensionPropertyInfo *get_property_list_bind (GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
213
- if (p_instance && m_class::_get_get_property_list ()) { \
214
- if (m_class::_get_get_property_list () != m_inherits::_get_get_property_list ()) { \
215
- m_class *cls = reinterpret_cast <m_class *>(p_instance); \
216
- ERR_FAIL_COND_V_MSG (!cls->plist_owned .is_empty () || cls->plist != nullptr || cls->plist_size != 0 , nullptr , " Internal error, property list was not freed by engine!" ); \
217
- cls->_get_property_list (&cls->plist_owned ); \
218
- cls->plist = reinterpret_cast <GDExtensionPropertyInfo *>(memalloc (sizeof (GDExtensionPropertyInfo) * cls->plist_owned .size ())); \
219
- cls->plist_size = 0 ; \
220
- for (const ::godot::PropertyInfo &E : cls->plist_owned ) { \
221
- cls->plist [cls->plist_size ].type = static_cast <GDExtensionVariantType>(E.type ); \
222
- cls->plist [cls->plist_size ].name = E.name ._native_ptr (); \
223
- cls->plist [cls->plist_size ].hint = E.hint ; \
224
- cls->plist [cls->plist_size ].hint_string = E.hint_string ._native_ptr (); \
225
- cls->plist [cls->plist_size ].class_name = E.class_name ._native_ptr (); \
226
- cls->plist [cls->plist_size ].usage = E.usage ; \
227
- cls->plist_size ++; \
228
- } \
229
- if (r_count) \
230
- *r_count = cls->plist_size ; \
231
- return cls->plist ; \
232
- } \
233
- return m_inherits::get_property_list_bind (p_instance, r_count); \
227
+ if (!p_instance) { \
228
+ if (r_count) \
229
+ *r_count = 0 ; \
230
+ return nullptr ; \
234
231
} \
235
- return nullptr ; \
232
+ m_class *cls = reinterpret_cast <m_class *>(p_instance); \
233
+ ::godot::List<::godot::PropertyInfo> &plist_cpp = cls->plist_owned ; \
234
+ ERR_FAIL_COND_V_MSG (!plist_cpp.is_empty (), nullptr , " Internal error, property list was not freed by engine!" ); \
235
+ cls->_get_property_list (&plist_cpp); \
236
+ return ::godot::internal::create_c_property_list (plist_cpp, r_count); \
236
237
} \
237
238
\
238
239
static void free_property_list_bind (GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) { \
239
240
if (p_instance) { \
240
241
m_class *cls = reinterpret_cast <m_class *>(p_instance); \
241
- ERR_FAIL_COND_MSG (cls->plist == nullptr , " Internal error, property list double free!" ); \
242
- memfree (cls->plist ); \
243
- cls->plist = nullptr ; \
244
- cls->plist_size = 0 ; \
245
242
cls->plist_owned .clear (); \
243
+ /* TODO `GDExtensionClassFreePropertyList` is ill-defined, we need a non-const pointer to free this. */ \
244
+ ::godot::internal::free_c_property_list (const_cast <GDExtensionPropertyInfo *>(p_list)); \
246
245
} \
247
246
} \
248
247
\
0 commit comments