@@ -39,6 +39,9 @@ static LOADED_CLASSES: Mutex<Option<HashMap<InitLevel, Vec<ClassName>>>> = Mutex
39
39
pub struct ClassPlugin {
40
40
pub class_name : ClassName ,
41
41
pub component : PluginComponent ,
42
+
43
+ // Init-level is per ClassPlugin and not per PluginComponent, because all components of all classes are mixed together in one
44
+ // huge linker list. There is no per-class aggregation going on, so this allows to easily filter relevant classes.
42
45
pub init_level : Option < InitLevel > ,
43
46
}
44
47
@@ -60,11 +63,11 @@ impl fmt::Debug for ErasedRegisterFn {
60
63
/// Represents the data part of a [`ClassPlugin`] instance.
61
64
#[ derive( Clone , Debug ) ]
62
65
pub enum PluginComponent {
63
- /// Class definition itself, must always be available
66
+ /// Class definition itself, must always be available.
64
67
ClassDef {
65
68
base_class_name : ClassName ,
66
69
67
- /// Godot low-level`create` function, wired up to library-generated `init`
70
+ /// Godot low-level `create` function, wired up to library-generated `init`.
68
71
generated_create_fn : Option <
69
72
unsafe extern "C" fn (
70
73
_class_userdata : * mut std:: ffi:: c_void , //
@@ -78,6 +81,9 @@ pub enum PluginComponent {
78
81
) -> sys:: GDExtensionClassInstancePtr ,
79
82
> ,
80
83
84
+ /// Callback to library-generated function which registers properties in the `struct` definition.
85
+ register_properties_fn : ErasedRegisterFn ,
86
+
81
87
free_fn : unsafe extern "C" fn (
82
88
_class_user_data : * mut std:: ffi:: c_void ,
83
89
instance : sys:: GDExtensionClassInstancePtr ,
@@ -86,18 +92,18 @@ pub enum PluginComponent {
86
92
87
93
/// Collected from `#[godot_api] impl MyClass`
88
94
UserMethodBinds {
89
- /// Callback to library-generated function which registers functions in the `impl`
95
+ /// Callback to library-generated function which registers functions and constants in the `impl` block.
90
96
///
91
97
/// Always present since that's the entire point of this `impl` block.
92
- generated_register_fn : ErasedRegisterFn ,
98
+ register_methods_constants_fn : ErasedRegisterFn ,
93
99
} ,
94
100
95
101
/// Collected from `#[godot_api] impl GodotExt for MyClass`
96
102
UserVirtuals {
97
- /// Callback to user-defined `register_class` function
103
+ /// Callback to user-defined `register_class` function.
98
104
user_register_fn : Option < ErasedRegisterFn > ,
99
105
100
- /// Godot low-level`create` function, wired up to the user's `init`
106
+ /// Godot low-level `create` function, wired up to the user's `init`.
101
107
user_create_fn : Option <
102
108
unsafe extern "C" fn (
103
109
_class_userdata : * mut std:: ffi:: c_void , //
@@ -111,7 +117,7 @@ pub enum PluginComponent {
111
117
) -> sys:: GDExtensionClassInstancePtr ,
112
118
> ,
113
119
114
- /// User-defined `to_string` function
120
+ /// User-defined `to_string` function.
115
121
user_to_string_fn : Option <
116
122
unsafe extern "C" fn (
117
123
p_instance : sys:: GDExtensionClassInstancePtr ,
@@ -120,7 +126,7 @@ pub enum PluginComponent {
120
126
) ,
121
127
> ,
122
128
123
- /// User-defined `on_notification` function
129
+ /// User-defined `on_notification` function.
124
130
#[ cfg( before_api = "4.2" ) ]
125
131
user_on_notification_fn : Option <
126
132
unsafe extern "C" fn (
@@ -137,7 +143,7 @@ pub enum PluginComponent {
137
143
) ,
138
144
> ,
139
145
140
- /// Callback for other virtuals
146
+ /// Callback for other virtuals.
141
147
get_virtual_fn : unsafe extern "C" fn (
142
148
p_userdata : * mut std:: os:: raw:: c_void ,
143
149
p_name : sys:: GDExtensionConstStringNamePtr ,
@@ -154,8 +160,12 @@ pub enum PluginComponent {
154
160
struct ClassRegistrationInfo {
155
161
class_name : ClassName ,
156
162
parent_class_name : Option < ClassName > ,
157
- generated_register_fn : Option < ErasedRegisterFn > ,
163
+ // Following functions are stored separately, since their order matters.
164
+ register_methods_constants_fn : Option < ErasedRegisterFn > ,
165
+ register_properties_fn : Option < ErasedRegisterFn > ,
158
166
user_register_fn : Option < ErasedRegisterFn > ,
167
+
168
+ /// Godot low-level class creation parameters.
159
169
#[ cfg( before_api = "4.2" ) ]
160
170
godot_params : sys:: GDExtensionClassCreationInfo ,
161
171
#[ cfg( since_api = "4.2" ) ]
@@ -208,7 +218,8 @@ pub fn register_class<
208
218
register_class_raw ( ClassRegistrationInfo {
209
219
class_name : T :: class_name ( ) ,
210
220
parent_class_name : Some ( T :: Base :: class_name ( ) ) ,
211
- generated_register_fn : None ,
221
+ register_methods_constants_fn : None ,
222
+ register_properties_fn : None ,
212
223
user_register_fn : Some ( ErasedRegisterFn {
213
224
raw : callbacks:: register_class_by_builder :: < T > ,
214
225
} ) ,
@@ -232,13 +243,15 @@ pub fn auto_register_classes(init_level: InitLevel) {
232
243
233
244
crate :: private:: iterate_plugins ( |elem : & ClassPlugin | {
234
245
//out!("* Plugin: {elem:#?}");
246
+
247
+ // Filter per ClassPlugin and not PluginComponent, because all components of all classes are mixed together in one huge list.
235
248
match elem. init_level {
236
249
None => {
237
250
log:: godot_error!( "Unknown initialization level for class {}" , elem. class_name) ;
238
251
return ;
239
252
}
240
253
Some ( elem_init_level) if elem_init_level != init_level => return ,
241
- _ => ( ) ,
254
+ _ => { /* Nothing */ }
242
255
}
243
256
244
257
let name = elem. class_name ;
@@ -304,6 +317,7 @@ fn fill_class_info(component: PluginComponent, c: &mut ClassRegistrationInfo) {
304
317
base_class_name,
305
318
generated_create_fn,
306
319
generated_recreate_fn,
320
+ register_properties_fn,
307
321
free_fn,
308
322
} => {
309
323
c. parent_class_name = Some ( base_class_name) ;
@@ -335,12 +349,13 @@ fn fill_class_info(component: PluginComponent, c: &mut ClassRegistrationInfo) {
335
349
assert ! ( generated_recreate_fn. is_none( ) ) ; // not used
336
350
337
351
c. godot_params . free_instance_func = Some ( free_fn) ;
352
+ c. register_properties_fn = Some ( register_properties_fn) ;
338
353
}
339
354
340
355
PluginComponent :: UserMethodBinds {
341
- generated_register_fn ,
356
+ register_methods_constants_fn ,
342
357
} => {
343
- c. generated_register_fn = Some ( generated_register_fn ) ;
358
+ c. register_methods_constants_fn = Some ( register_methods_constants_fn ) ;
344
359
}
345
360
346
361
PluginComponent :: UserVirtuals {
@@ -433,11 +448,18 @@ fn register_class_raw(info: ClassRegistrationInfo) {
433
448
//let mut class_builder = crate::builder::ClassBuilder::<?>::new();
434
449
let mut class_builder = 0 ; // TODO dummy argument; see callbacks
435
450
436
- // First call generated (proc-macro) registration function, then user-defined one.
437
- // This mimics the intuition that proc-macros are running "before" normal runtime code.
438
- if let Some ( register_fn) = info. generated_register_fn {
451
+ // Order of the following registrations is crucial:
452
+ // 1. Methods and constants.
453
+ // 2. Properties (they may depend on get/set methods).
454
+ // 3. User-defined registration function (intuitively, user expects their own code to run after proc-macro generated code).
455
+ if let Some ( register_fn) = info. register_methods_constants_fn {
456
+ ( register_fn. raw ) ( & mut class_builder) ;
457
+ }
458
+
459
+ if let Some ( register_fn) = info. register_properties_fn {
439
460
( register_fn. raw ) ( & mut class_builder) ;
440
461
}
462
+
441
463
if let Some ( register_fn) = info. user_register_fn {
442
464
( register_fn. raw ) ( & mut class_builder) ;
443
465
}
@@ -639,7 +661,11 @@ pub mod callbacks {
639
661
T :: __godot_register_class ( & mut class_builder) ;
640
662
}
641
663
642
- pub fn register_user_binds < T : cap:: ImplementsGodotApi + cap:: ImplementsGodotExports > (
664
+ pub fn register_user_properties < T : cap:: ImplementsGodotExports > ( _class_builder : & mut dyn Any ) {
665
+ T :: __register_exports ( ) ;
666
+ }
667
+
668
+ pub fn register_user_methods_constants < T : cap:: ImplementsGodotApi > (
643
669
_class_builder : & mut dyn Any ,
644
670
) {
645
671
// let class_builder = class_builder
@@ -649,7 +675,6 @@ pub mod callbacks {
649
675
//T::register_methods(class_builder);
650
676
T :: __register_methods ( ) ;
651
677
T :: __register_constants ( ) ;
652
- T :: __register_exports ( ) ;
653
678
}
654
679
}
655
680
@@ -662,7 +687,8 @@ fn default_registration_info(class_name: ClassName) -> ClassRegistrationInfo {
662
687
ClassRegistrationInfo {
663
688
class_name,
664
689
parent_class_name : None ,
665
- generated_register_fn : None ,
690
+ register_methods_constants_fn : None ,
691
+ register_properties_fn : None ,
666
692
user_register_fn : None ,
667
693
godot_params : default_creation_info ( ) ,
668
694
init_level : InitLevel :: Scene ,
0 commit comments