@@ -91,12 +91,19 @@ impl Plugin for ScenePlugin {
9191 app. world_mut ( )
9292 . register_component_hooks :: < SceneRoot > ( )
9393 . on_remove ( |mut world, context| {
94+ let Some ( handle) = world. get :: < SceneRoot > ( context. entity ) else {
95+ return ;
96+ } ;
97+ let id = handle. id ( ) ;
9498 if let Some ( & SceneInstance ( scene_instance) ) =
9599 world. get :: < SceneInstance > ( context. entity )
96100 {
97101 let Some ( mut scene_spawner) = world. get_resource_mut :: < SceneSpawner > ( ) else {
98102 return ;
99103 } ;
104+ if let Some ( instance_ids) = scene_spawner. spawned_scenes . get_mut ( & id) {
105+ instance_ids. remove ( & scene_instance) ;
106+ }
100107 scene_spawner. unregister_instance ( scene_instance) ;
101108 }
102109 } ) ;
@@ -107,3 +114,299 @@ impl Plugin for ScenePlugin {
107114impl Plugin for ScenePlugin {
108115 fn build ( & self , _: & mut App ) { }
109116}
117+
118+ #[ cfg( test) ]
119+ mod tests {
120+ use bevy_app:: App ;
121+ use bevy_asset:: { AssetPlugin , Assets } ;
122+ use bevy_ecs:: {
123+ component:: Component ,
124+ hierarchy:: { ChildOf , Children } ,
125+ reflect:: { AppTypeRegistry , ReflectComponent } ,
126+ world:: World ,
127+ } ;
128+ use bevy_reflect:: Reflect ;
129+
130+ use crate :: {
131+ DynamicScene , DynamicSceneBuilder , DynamicSceneRoot , Scene , ScenePlugin , SceneRoot ,
132+ } ;
133+
134+ #[ derive( Component , Reflect , PartialEq , Debug ) ]
135+ #[ reflect( Component ) ]
136+ struct Circle {
137+ radius : f32 ,
138+ }
139+
140+ #[ derive( Component , Reflect , PartialEq , Debug ) ]
141+ #[ reflect( Component ) ]
142+ struct Rectangle {
143+ width : f32 ,
144+ height : f32 ,
145+ }
146+
147+ #[ derive( Component , Reflect , PartialEq , Debug ) ]
148+ #[ reflect( Component ) ]
149+ struct Triangle {
150+ base : f32 ,
151+ height : f32 ,
152+ }
153+
154+ #[ derive( Component , Reflect ) ]
155+ #[ reflect( Component ) ]
156+ struct FinishLine ;
157+
158+ #[ test]
159+ fn scene_spawns_and_respawns_after_change ( ) {
160+ let mut app = App :: new ( ) ;
161+
162+ app. add_plugins ( ( AssetPlugin :: default ( ) , ScenePlugin ) )
163+ . register_type :: < Circle > ( )
164+ . register_type :: < Rectangle > ( )
165+ . register_type :: < Triangle > ( )
166+ . register_type :: < FinishLine > ( ) ;
167+
168+ let scene_handle = app
169+ . world_mut ( )
170+ . resource_mut :: < Assets < Scene > > ( )
171+ . reserve_handle ( ) ;
172+
173+ let scene_entity = app. world_mut ( ) . spawn ( SceneRoot ( scene_handle. clone ( ) ) ) . id ( ) ;
174+ app. update ( ) ;
175+
176+ assert ! ( app. world( ) . entity( scene_entity) . get:: <Children >( ) . is_none( ) ) ;
177+
178+ let mut scene_1 = Scene {
179+ world : World :: new ( ) ,
180+ } ;
181+ let root = scene_1. world . spawn_empty ( ) . id ( ) ;
182+ scene_1. world . spawn ( (
183+ Rectangle {
184+ width : 10.0 ,
185+ height : 5.0 ,
186+ } ,
187+ FinishLine ,
188+ ChildOf ( root) ,
189+ ) ) ;
190+ scene_1. world . spawn ( ( Circle { radius : 7.0 } , ChildOf ( root) ) ) ;
191+
192+ app. world_mut ( )
193+ . resource_mut :: < Assets < Scene > > ( )
194+ . insert ( & scene_handle, scene_1) ;
195+
196+ app. update ( ) ;
197+
198+ let child_root = app
199+ . world ( )
200+ . entity ( scene_entity)
201+ . get :: < Children > ( )
202+ . and_then ( |children| children. first ( ) . cloned ( ) )
203+ . expect ( "There should be exactly one child on the scene root" ) ;
204+ let children = app
205+ . world ( )
206+ . entity ( child_root)
207+ . get :: < Children > ( )
208+ . expect ( "The child of the scene root should itself have 2 children" ) ;
209+ assert_eq ! ( children. len( ) , 2 ) ;
210+
211+ let finish_line = app. world ( ) . entity ( children[ 0 ] ) ;
212+ assert_eq ! ( finish_line. archetype( ) . component_count( ) , 3 ) ;
213+ let ( rectangle, _, child_of) =
214+ finish_line. components :: < ( & Rectangle , & FinishLine , & ChildOf ) > ( ) ;
215+ assert_eq ! (
216+ rectangle,
217+ & Rectangle {
218+ width: 10.0 ,
219+ height: 5.0 ,
220+ }
221+ ) ;
222+ assert_eq ! ( child_of. 0 , child_root) ;
223+
224+ let circle = app. world ( ) . entity ( children[ 1 ] ) ;
225+ assert_eq ! ( circle. archetype( ) . component_count( ) , 2 ) ;
226+ let ( circle, child_of) = circle. components :: < ( & Circle , & ChildOf ) > ( ) ;
227+ assert_eq ! ( circle, & Circle { radius: 7.0 } ) ;
228+ assert_eq ! ( child_of. 0 , child_root) ;
229+
230+ // Now that we know our scene contains exactly what we expect, we will change the scene
231+ // asset and ensure it contains the new scene results.
232+
233+ let mut scene_2 = Scene {
234+ world : World :: new ( ) ,
235+ } ;
236+ let root = scene_2. world . spawn_empty ( ) . id ( ) ;
237+ scene_2. world . spawn ( (
238+ Triangle {
239+ base : 1.0 ,
240+ height : 2.0 ,
241+ } ,
242+ ChildOf ( root) ,
243+ ) ) ;
244+
245+ app. world_mut ( )
246+ . resource_mut :: < Assets < Scene > > ( )
247+ . insert ( & scene_handle, scene_2) ;
248+
249+ app. update ( ) ;
250+ app. update ( ) ;
251+
252+ let child_root = app
253+ . world ( )
254+ . entity ( scene_entity)
255+ . get :: < Children > ( )
256+ . and_then ( |children| children. first ( ) . cloned ( ) )
257+ . expect ( "There should be exactly one child on the scene root" ) ;
258+ let children = app
259+ . world ( )
260+ . entity ( child_root)
261+ . get :: < Children > ( )
262+ . expect ( "The child of the scene root should itself have 2 children" ) ;
263+ assert_eq ! ( children. len( ) , 1 ) ;
264+
265+ let triangle = app. world ( ) . entity ( children[ 0 ] ) ;
266+ assert_eq ! ( triangle. archetype( ) . component_count( ) , 2 ) ;
267+ let ( triangle, child_of) = triangle. components :: < ( & Triangle , & ChildOf ) > ( ) ;
268+ assert_eq ! (
269+ triangle,
270+ & Triangle {
271+ base: 1.0 ,
272+ height: 2.0 ,
273+ }
274+ ) ;
275+ assert_eq ! ( child_of. 0 , child_root) ;
276+ }
277+
278+ #[ test]
279+ fn dynamic_scene_spawns_and_respawns_after_change ( ) {
280+ let mut app = App :: new ( ) ;
281+
282+ app. add_plugins ( ( AssetPlugin :: default ( ) , ScenePlugin ) )
283+ . register_type :: < Circle > ( )
284+ . register_type :: < Rectangle > ( )
285+ . register_type :: < Triangle > ( )
286+ . register_type :: < FinishLine > ( ) ;
287+
288+ let scene_handle = app
289+ . world_mut ( )
290+ . resource_mut :: < Assets < DynamicScene > > ( )
291+ . reserve_handle ( ) ;
292+
293+ let scene_entity = app
294+ . world_mut ( )
295+ . spawn ( DynamicSceneRoot ( scene_handle. clone ( ) ) )
296+ . id ( ) ;
297+ app. update ( ) ;
298+
299+ assert ! ( app. world( ) . entity( scene_entity) . get:: <Children >( ) . is_none( ) ) ;
300+
301+ let create_dynamic_scene = |mut scene : Scene , world : & World | {
302+ scene
303+ . world
304+ . insert_resource ( world. resource :: < AppTypeRegistry > ( ) . clone ( ) ) ;
305+ DynamicSceneBuilder :: from_world ( & scene. world )
306+ . extract_entities ( scene. world . iter_entities ( ) . map ( |entity| entity. id ( ) ) )
307+ . build ( )
308+ } ;
309+
310+ let mut scene_1 = Scene {
311+ world : World :: new ( ) ,
312+ } ;
313+ let root = scene_1. world . spawn_empty ( ) . id ( ) ;
314+ scene_1. world . spawn ( (
315+ Rectangle {
316+ width : 10.0 ,
317+ height : 5.0 ,
318+ } ,
319+ FinishLine ,
320+ ChildOf ( root) ,
321+ ) ) ;
322+ scene_1. world . spawn ( ( Circle { radius : 7.0 } , ChildOf ( root) ) ) ;
323+
324+ let scene_1 = create_dynamic_scene ( scene_1, app. world ( ) ) ;
325+ app. world_mut ( )
326+ . resource_mut :: < Assets < DynamicScene > > ( )
327+ . insert ( & scene_handle, scene_1) ;
328+
329+ app. update ( ) ;
330+
331+ let child_root = app
332+ . world ( )
333+ . entity ( scene_entity)
334+ . get :: < Children > ( )
335+ . and_then ( |children| children. first ( ) . cloned ( ) )
336+ . expect ( "There should be exactly one child on the scene root" ) ;
337+ let children = app
338+ . world ( )
339+ . entity ( child_root)
340+ . get :: < Children > ( )
341+ . expect ( "The child of the scene root should itself have 2 children" ) ;
342+ assert_eq ! ( children. len( ) , 2 ) ;
343+
344+ let finish_line = app. world ( ) . entity ( children[ 0 ] ) ;
345+ assert_eq ! ( finish_line. archetype( ) . component_count( ) , 3 ) ;
346+ let ( rectangle, _, child_of) =
347+ finish_line. components :: < ( & Rectangle , & FinishLine , & ChildOf ) > ( ) ;
348+ assert_eq ! (
349+ rectangle,
350+ & Rectangle {
351+ width: 10.0 ,
352+ height: 5.0 ,
353+ }
354+ ) ;
355+ assert_eq ! ( child_of. 0 , child_root) ;
356+
357+ let circle = app. world ( ) . entity ( children[ 1 ] ) ;
358+ assert_eq ! ( circle. archetype( ) . component_count( ) , 2 ) ;
359+ let ( circle, child_of) = circle. components :: < ( & Circle , & ChildOf ) > ( ) ;
360+ assert_eq ! ( circle, & Circle { radius: 7.0 } ) ;
361+ assert_eq ! ( child_of. 0 , child_root) ;
362+
363+ // Now that we know our scene contains exactly what we expect, we will change the scene
364+ // asset and ensure it contains the new scene results.
365+
366+ let mut scene_2 = Scene {
367+ world : World :: new ( ) ,
368+ } ;
369+ let root = scene_2. world . spawn_empty ( ) . id ( ) ;
370+ scene_2. world . spawn ( (
371+ Triangle {
372+ base : 1.0 ,
373+ height : 2.0 ,
374+ } ,
375+ ChildOf ( root) ,
376+ ) ) ;
377+
378+ let scene_2 = create_dynamic_scene ( scene_2, app. world ( ) ) ;
379+
380+ app. world_mut ( )
381+ . resource_mut :: < Assets < DynamicScene > > ( )
382+ . insert ( & scene_handle, scene_2) ;
383+
384+ app. update ( ) ;
385+ app. update ( ) ;
386+
387+ let child_root = app
388+ . world ( )
389+ . entity ( scene_entity)
390+ . get :: < Children > ( )
391+ . and_then ( |children| children. first ( ) . cloned ( ) )
392+ . expect ( "There should be exactly one child on the scene root" ) ;
393+ let children = app
394+ . world ( )
395+ . entity ( child_root)
396+ . get :: < Children > ( )
397+ . expect ( "The child of the scene root should itself have 2 children" ) ;
398+ assert_eq ! ( children. len( ) , 1 ) ;
399+
400+ let triangle = app. world ( ) . entity ( children[ 0 ] ) ;
401+ assert_eq ! ( triangle. archetype( ) . component_count( ) , 2 ) ;
402+ let ( triangle, child_of) = triangle. components :: < ( & Triangle , & ChildOf ) > ( ) ;
403+ assert_eq ! (
404+ triangle,
405+ & Triangle {
406+ base: 1.0 ,
407+ height: 2.0 ,
408+ }
409+ ) ;
410+ assert_eq ! ( child_of. 0 , child_root) ;
411+ }
412+ }
0 commit comments