@@ -8,18 +8,19 @@ use std::{cell::RefCell, collections::HashSet, ffi::c_void};
8
8
9
9
use godot:: classes:: {
10
10
notify:: ObjectNotification , object:: ConnectFlags , ClassDb , Engine , IScriptExtension , Object ,
11
- Script , ScriptExtension , ScriptLanguage , WeakRef ,
11
+ Script , ScriptExtension , ScriptLanguage ,
12
12
} ;
13
- use godot:: global:: { godot_error, godot_print, godot_warn} ;
13
+ use godot:: global:: { godot_error, godot_print, godot_warn, PropertyUsageFlags } ;
14
14
use godot:: meta:: { MethodInfo , PropertyInfo , ToGodot } ;
15
15
use godot:: obj:: script:: create_script_instance;
16
- use godot:: obj:: { EngineEnum , InstanceId , WithBaseField } ;
16
+ use godot:: obj:: { EngineBitfield , EngineEnum , InstanceId , WithBaseField } ;
17
17
use godot:: prelude:: {
18
18
godot_api, Array , Base , Callable , Dictionary , GString , Gd , GodotClass , StringName , Variant ,
19
19
VariantArray ,
20
20
} ;
21
21
22
22
use crate :: apply:: Apply ;
23
+ use crate :: static_script_registry:: RustScriptPropertyInfo ;
23
24
24
25
use super :: rust_script_instance:: GodotScriptObject ;
25
26
use super :: {
@@ -38,11 +39,12 @@ pub(crate) struct RustScript {
38
39
#[ var( get = get_class_name, set = set_class_name, usage_flags = [ STORAGE ] ) ]
39
40
class_name : GString ,
40
41
42
+ /// dummy property that stores the onwer ids when the extension gets reloaded by the engine.
41
43
#[ var( get = owner_ids, set = set_owner_ids, usage_flags = [ STORAGE ] ) ]
42
44
#[ allow( dead_code) ]
43
45
owner_ids : Array < i64 > ,
44
46
45
- owners : RefCell < Vec < Gd < WeakRef > > > ,
47
+ owners : RefCell < HashSet < InstanceId > > ,
46
48
base : Base < ScriptExtension > ,
47
49
}
48
50
@@ -86,13 +88,7 @@ impl RustScript {
86
88
fn owner_ids ( & self ) -> Array < i64 > {
87
89
let owners = self . owners . borrow ( ) ;
88
90
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 ( )
96
92
}
97
93
98
94
#[ func]
@@ -103,18 +99,10 @@ impl RustScript {
103
99
}
104
100
105
101
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" ) ;
107
103
}
108
104
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 ( ) ;
118
106
}
119
107
120
108
#[ func]
@@ -140,6 +128,14 @@ impl RustScript {
140
128
141
129
base. call ( "_init" , & [ ] ) ;
142
130
}
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
+ }
143
139
}
144
140
145
141
#[ godot_api]
@@ -188,9 +184,7 @@ impl IScriptExtension for RustScript {
188
184
}
189
185
190
186
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 ( ) ) ;
194
188
195
189
let data = self . create_remote_instance ( for_object. clone ( ) ) ;
196
190
let instance = RustScriptInstance :: new ( data, for_object. clone ( ) , self . to_gd ( ) ) ;
@@ -210,9 +204,7 @@ impl IScriptExtension for RustScript {
210
204
}
211
205
212
206
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 ( ) ) ;
216
208
217
209
let placeholder = RustScriptPlaceholder :: new ( self . to_gd ( ) ) ;
218
210
@@ -393,24 +385,58 @@ impl IScriptExtension for RustScript {
393
385
}
394
386
395
387
// 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
+
397
396
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
+ } ;
398
404
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 ) {
401
407
Ok ( owner) => owner,
402
408
Err ( err) => {
403
409
godot_warn ! ( "Failed to get script owner: {:?}" , err) ;
404
410
return ;
405
411
}
406
412
} ;
407
413
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
+
408
428
// clear script to destroy script instance.
409
429
object. set_script ( & Variant :: nil ( ) ) ;
410
430
411
431
self . downgrade_gd ( |self_gd| {
412
432
// re-assign script to create new instance.
413
433
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
+ }
414
440
} )
415
441
} ) ;
416
442
@@ -424,7 +450,7 @@ impl IScriptExtension for RustScript {
424
450
self . str_class_name( )
425
451
) ;
426
452
427
- self . reload ( false ) ;
453
+ self . reload ( true ) ;
428
454
}
429
455
}
430
456
0 commit comments