@@ -39,6 +39,9 @@ static LOADED_CLASSES: Mutex<Option<HashMap<InitLevel, Vec<ClassName>>>> = Mutex
3939pub struct ClassPlugin {
4040 pub class_name : ClassName ,
4141 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.
4245 pub init_level : Option < InitLevel > ,
4346}
4447
@@ -60,11 +63,11 @@ impl fmt::Debug for ErasedRegisterFn {
6063/// Represents the data part of a [`ClassPlugin`] instance.
6164#[ derive( Clone , Debug ) ]
6265pub enum PluginComponent {
63- /// Class definition itself, must always be available
66+ /// Class definition itself, must always be available.
6467 ClassDef {
6568 base_class_name : ClassName ,
6669
67- /// Godot low-level`create` function, wired up to library-generated `init`
70+ /// Godot low-level `create` function, wired up to library-generated `init`.
6871 generated_create_fn : Option <
6972 unsafe extern "C" fn (
7073 _class_userdata : * mut std:: ffi:: c_void , //
@@ -78,6 +81,9 @@ pub enum PluginComponent {
7881 ) -> sys:: GDExtensionClassInstancePtr ,
7982 > ,
8083
84+ /// Callback to library-generated function which registers properties in the `struct` definition.
85+ register_properties_fn : ErasedRegisterFn ,
86+
8187 free_fn : unsafe extern "C" fn (
8288 _class_user_data : * mut std:: ffi:: c_void ,
8389 instance : sys:: GDExtensionClassInstancePtr ,
@@ -86,18 +92,18 @@ pub enum PluginComponent {
8692
8793 /// Collected from `#[godot_api] impl MyClass`
8894 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.
9096 ///
9197 /// Always present since that's the entire point of this `impl` block.
92- generated_register_fn : ErasedRegisterFn ,
98+ register_methods_constants_fn : ErasedRegisterFn ,
9399 } ,
94100
95101 /// Collected from `#[godot_api] impl GodotExt for MyClass`
96102 UserVirtuals {
97- /// Callback to user-defined `register_class` function
103+ /// Callback to user-defined `register_class` function.
98104 user_register_fn : Option < ErasedRegisterFn > ,
99105
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`.
101107 user_create_fn : Option <
102108 unsafe extern "C" fn (
103109 _class_userdata : * mut std:: ffi:: c_void , //
@@ -111,7 +117,7 @@ pub enum PluginComponent {
111117 ) -> sys:: GDExtensionClassInstancePtr ,
112118 > ,
113119
114- /// User-defined `to_string` function
120+ /// User-defined `to_string` function.
115121 user_to_string_fn : Option <
116122 unsafe extern "C" fn (
117123 p_instance : sys:: GDExtensionClassInstancePtr ,
@@ -120,7 +126,7 @@ pub enum PluginComponent {
120126 ) ,
121127 > ,
122128
123- /// User-defined `on_notification` function
129+ /// User-defined `on_notification` function.
124130 #[ cfg( before_api = "4.2" ) ]
125131 user_on_notification_fn : Option <
126132 unsafe extern "C" fn (
@@ -137,7 +143,7 @@ pub enum PluginComponent {
137143 ) ,
138144 > ,
139145
140- /// Callback for other virtuals
146+ /// Callback for other virtuals.
141147 get_virtual_fn : unsafe extern "C" fn (
142148 p_userdata : * mut std:: os:: raw:: c_void ,
143149 p_name : sys:: GDExtensionConstStringNamePtr ,
@@ -154,8 +160,12 @@ pub enum PluginComponent {
154160struct ClassRegistrationInfo {
155161 class_name : ClassName ,
156162 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 > ,
158166 user_register_fn : Option < ErasedRegisterFn > ,
167+
168+ /// Godot low-level class creation parameters.
159169 #[ cfg( before_api = "4.2" ) ]
160170 godot_params : sys:: GDExtensionClassCreationInfo ,
161171 #[ cfg( since_api = "4.2" ) ]
@@ -208,7 +218,8 @@ pub fn register_class<
208218 register_class_raw ( ClassRegistrationInfo {
209219 class_name : T :: class_name ( ) ,
210220 parent_class_name : Some ( T :: Base :: class_name ( ) ) ,
211- generated_register_fn : None ,
221+ register_methods_constants_fn : None ,
222+ register_properties_fn : None ,
212223 user_register_fn : Some ( ErasedRegisterFn {
213224 raw : callbacks:: register_class_by_builder :: < T > ,
214225 } ) ,
@@ -232,13 +243,15 @@ pub fn auto_register_classes(init_level: InitLevel) {
232243
233244 crate :: private:: iterate_plugins ( |elem : & ClassPlugin | {
234245 //out!("* Plugin: {elem:#?}");
246+
247+ // Filter per ClassPlugin and not PluginComponent, because all components of all classes are mixed together in one huge list.
235248 match elem. init_level {
236249 None => {
237250 log:: godot_error!( "Unknown initialization level for class {}" , elem. class_name) ;
238251 return ;
239252 }
240253 Some ( elem_init_level) if elem_init_level != init_level => return ,
241- _ => ( ) ,
254+ _ => { /* Nothing */ }
242255 }
243256
244257 let name = elem. class_name ;
@@ -304,6 +317,7 @@ fn fill_class_info(component: PluginComponent, c: &mut ClassRegistrationInfo) {
304317 base_class_name,
305318 generated_create_fn,
306319 generated_recreate_fn,
320+ register_properties_fn,
307321 free_fn,
308322 } => {
309323 c. parent_class_name = Some ( base_class_name) ;
@@ -335,12 +349,13 @@ fn fill_class_info(component: PluginComponent, c: &mut ClassRegistrationInfo) {
335349 assert ! ( generated_recreate_fn. is_none( ) ) ; // not used
336350
337351 c. godot_params . free_instance_func = Some ( free_fn) ;
352+ c. register_properties_fn = Some ( register_properties_fn) ;
338353 }
339354
340355 PluginComponent :: UserMethodBinds {
341- generated_register_fn ,
356+ register_methods_constants_fn ,
342357 } => {
343- c. generated_register_fn = Some ( generated_register_fn ) ;
358+ c. register_methods_constants_fn = Some ( register_methods_constants_fn ) ;
344359 }
345360
346361 PluginComponent :: UserVirtuals {
@@ -433,11 +448,18 @@ fn register_class_raw(info: ClassRegistrationInfo) {
433448 //let mut class_builder = crate::builder::ClassBuilder::<?>::new();
434449 let mut class_builder = 0 ; // TODO dummy argument; see callbacks
435450
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 {
439460 ( register_fn. raw ) ( & mut class_builder) ;
440461 }
462+
441463 if let Some ( register_fn) = info. user_register_fn {
442464 ( register_fn. raw ) ( & mut class_builder) ;
443465 }
@@ -639,7 +661,11 @@ pub mod callbacks {
639661 T :: __godot_register_class ( & mut class_builder) ;
640662 }
641663
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 > (
643669 _class_builder : & mut dyn Any ,
644670 ) {
645671 // let class_builder = class_builder
@@ -649,7 +675,6 @@ pub mod callbacks {
649675 //T::register_methods(class_builder);
650676 T :: __register_methods ( ) ;
651677 T :: __register_constants ( ) ;
652- T :: __register_exports ( ) ;
653678 }
654679}
655680
@@ -662,7 +687,8 @@ fn default_registration_info(class_name: ClassName) -> ClassRegistrationInfo {
662687 ClassRegistrationInfo {
663688 class_name,
664689 parent_class_name : None ,
665- generated_register_fn : None ,
690+ register_methods_constants_fn : None ,
691+ register_properties_fn : None ,
666692 user_register_fn : None ,
667693 godot_params : default_creation_info ( ) ,
668694 init_level : InitLevel :: Scene ,
0 commit comments