@@ -8,18 +8,19 @@ use std::{cell::RefCell, collections::HashSet, ffi::c_void};
88
99use godot:: classes:: {
1010 notify:: ObjectNotification , object:: ConnectFlags , ClassDb , Engine , IScriptExtension , Object ,
11- Script , ScriptExtension , ScriptLanguage , WeakRef ,
11+ Script , ScriptExtension , ScriptLanguage ,
1212} ;
13- use godot:: global:: { godot_error, godot_print, godot_warn} ;
13+ use godot:: global:: { godot_error, godot_print, godot_warn, PropertyUsageFlags } ;
1414use godot:: meta:: { MethodInfo , PropertyInfo , ToGodot } ;
1515use godot:: obj:: script:: create_script_instance;
16- use godot:: obj:: { EngineEnum , InstanceId , WithBaseField } ;
16+ use godot:: obj:: { EngineBitfield , EngineEnum , InstanceId , WithBaseField } ;
1717use godot:: prelude:: {
1818 godot_api, Array , Base , Callable , Dictionary , GString , Gd , GodotClass , StringName , Variant ,
1919 VariantArray ,
2020} ;
2121
2222use crate :: apply:: Apply ;
23+ use crate :: static_script_registry:: RustScriptPropertyInfo ;
2324
2425use super :: rust_script_instance:: GodotScriptObject ;
2526use super :: {
@@ -38,11 +39,12 @@ pub(crate) struct RustScript {
3839 #[ var( get = get_class_name, set = set_class_name, usage_flags = [ STORAGE ] ) ]
3940 class_name : GString ,
4041
42+ /// dummy property that stores the onwer ids when the extension gets reloaded by the engine.
4143 #[ var( get = owner_ids, set = set_owner_ids, usage_flags = [ STORAGE ] ) ]
4244 #[ allow( dead_code) ]
4345 owner_ids : Array < i64 > ,
4446
45- owners : RefCell < Vec < Gd < WeakRef > > > ,
47+ owners : RefCell < HashSet < InstanceId > > ,
4648 base : Base < ScriptExtension > ,
4749}
4850
@@ -86,13 +88,7 @@ impl RustScript {
8688 fn owner_ids ( & self ) -> Array < i64 > {
8789 let owners = self . owners . borrow ( ) ;
8890
89- let set: HashSet < _ > = owners
90- . iter ( )
91- . filter_map ( |item| item. get_ref ( ) . to :: < Option < Gd < Object > > > ( ) )
92- . map ( |obj| obj. instance_id ( ) . to_i64 ( ) )
93- . collect ( ) ;
94-
95- set. into_iter ( ) . collect ( )
91+ owners. iter ( ) . map ( |id| id. to_i64 ( ) ) . collect ( )
9692 }
9793
9894 #[ func]
@@ -103,18 +99,10 @@ impl RustScript {
10399 }
104100
105101 if !self . owners . borrow ( ) . is_empty ( ) {
106- godot_warn ! ( "over writing existing owners of rust script" ) ;
102+ godot_warn ! ( "overwriting existing owners of rust script" ) ;
107103 }
108104
109- * self . owners . borrow_mut ( ) = ids
110- . iter_shared ( )
111- . map ( InstanceId :: from_i64)
112- . filter_map ( |id| {
113- let result: Option < Gd < Object > > = Gd :: try_from_instance_id ( id) . ok ( ) ;
114- result
115- } )
116- . map ( |gd_ref| godot:: global:: weakref ( & gd_ref. to_variant ( ) ) . to ( ) )
117- . collect ( ) ;
105+ * self . owners . borrow_mut ( ) = ids. iter_shared ( ) . map ( InstanceId :: from_i64) . collect ( ) ;
118106 }
119107
120108 #[ func]
@@ -140,6 +128,14 @@ impl RustScript {
140128
141129 base. call ( "_init" , & [ ] ) ;
142130 }
131+
132+ fn map_property_info_list < R > ( & self , f : impl Fn ( & RustScriptPropertyInfo ) -> R ) -> Vec < R > {
133+ let reg = SCRIPT_REGISTRY . read ( ) . expect ( "unable to obtain read lock" ) ;
134+
135+ reg. get ( & self . str_class_name ( ) )
136+ . map ( |class| class. properties ( ) . iter ( ) . map ( f) . collect ( ) )
137+ . unwrap_or_default ( )
138+ }
143139}
144140
145141#[ godot_api]
@@ -188,9 +184,7 @@ impl IScriptExtension for RustScript {
188184 }
189185
190186 unsafe fn instance_create ( & self , mut for_object : Gd < Object > ) -> * mut c_void {
191- self . owners
192- . borrow_mut ( )
193- . push ( godot:: global:: weakref ( & for_object. to_variant ( ) ) . to ( ) ) ;
187+ self . owners . borrow_mut ( ) . insert ( for_object. instance_id ( ) ) ;
194188
195189 let data = self . create_remote_instance ( for_object. clone ( ) ) ;
196190 let instance = RustScriptInstance :: new ( data, for_object. clone ( ) , self . to_gd ( ) ) ;
@@ -210,9 +204,7 @@ impl IScriptExtension for RustScript {
210204 }
211205
212206 unsafe fn placeholder_instance_create ( & self , for_object : Gd < Object > ) -> * mut c_void {
213- self . owners
214- . borrow_mut ( )
215- . push ( godot:: global:: weakref ( & for_object. to_variant ( ) ) . to ( ) ) ;
207+ self . owners . borrow_mut ( ) . insert ( for_object. instance_id ( ) ) ;
216208
217209 let placeholder = RustScriptPlaceholder :: new ( self . to_gd ( ) ) ;
218210
@@ -393,24 +385,58 @@ impl IScriptExtension for RustScript {
393385 }
394386
395387 // godot script reload hook
396- fn reload ( & mut self , _keep_state : bool ) -> godot:: global:: Error {
388+ fn reload (
389+ & mut self ,
390+ // before 4.4 the engine does not correctly pass the keep_state flag
391+ #[ cfg_attr( before_api = "4.4" , expect( unused_variables) ) ] keep_state : bool ,
392+ ) -> godot:: global:: Error {
393+ #[ cfg( before_api = "4.4" ) ]
394+ let keep_state = true ;
395+
397396 let owners = self . owners . borrow ( ) . clone ( ) ;
397+ let exported_properties_list = if keep_state {
398+ self . map_property_info_list ( |prop| {
399+ ( prop. usage & PropertyUsageFlags :: EDITOR . ord ( ) != 0 ) . then_some ( prop. property_name )
400+ } )
401+ } else {
402+ Vec :: with_capacity ( 0 )
403+ } ;
398404
399- owners. iter ( ) . for_each ( |owner | {
400- let mut object: Gd < Object > = match owner . get_ref ( ) . try_to ( ) {
405+ owners. iter ( ) . for_each ( |owner_id | {
406+ let mut object: Gd < Object > = match Gd :: try_from_instance_id ( * owner_id ) {
401407 Ok ( owner) => owner,
402408 Err ( err) => {
403409 godot_warn ! ( "Failed to get script owner: {:?}" , err) ;
404410 return ;
405411 }
406412 } ;
407413
414+ let property_backup: Vec < _ > = if keep_state {
415+ exported_properties_list
416+ . iter ( )
417+ . flatten ( )
418+ . map ( |key| {
419+ let value = object. get ( * key) ;
420+
421+ ( * key, value)
422+ } )
423+ . collect ( )
424+ } else {
425+ Vec :: with_capacity ( 0 )
426+ } ;
427+
408428 // clear script to destroy script instance.
409429 object. set_script ( & Variant :: nil ( ) ) ;
410430
411431 self . downgrade_gd ( |self_gd| {
412432 // re-assign script to create new instance.
413433 object. set_script ( & self_gd. to_variant ( ) ) ;
434+
435+ if keep_state {
436+ property_backup. into_iter ( ) . for_each ( |( key, value) | {
437+ object. set ( key, & value) ;
438+ } ) ;
439+ }
414440 } )
415441 } ) ;
416442
@@ -424,7 +450,7 @@ impl IScriptExtension for RustScript {
424450 self . str_class_name( )
425451 ) ;
426452
427- self . reload ( false ) ;
453+ self . reload ( true ) ;
428454 }
429455 }
430456
0 commit comments