1
- use bevy:: { ecs:: { bundle:: Bundle , component:: Component , system:: { Commands , Query , Res } , entity:: Entity , event :: { Event , EventWriter } } , asset:: { Handle , Asset , Assets } , transform:: components:: Transform , reflect:: TypePath , math:: { Mat4 , Vec3 , Mat3 , Quat } , render:: { mesh:: Mesh , view:: Visibility , prelude:: SpatialBundle } , pbr:: { StandardMaterial , PbrBundle } , core:: Name , hierarchy:: BuildChildren , log:: warn} ;
1
+ use bevy:: { ecs:: { bundle:: Bundle , component:: Component , system:: { Commands , EntityCommands , Query , Res } , entity:: Entity , world :: { EntityRef , World } , query :: Without } , asset:: { Handle , Asset , Assets } , transform:: components:: Transform , reflect:: TypePath , math:: { Mat4 , Vec3 , Mat3 , Quat } , render:: { mesh:: Mesh , view:: Visibility , prelude:: SpatialBundle } , pbr:: { StandardMaterial , PbrBundle } , core:: Name , hierarchy:: { BuildChildren , Children } , log:: warn} ;
2
2
use dot_vox:: { SceneNode , Frame } ;
3
3
4
4
#[ derive( Bundle , Default ) ]
@@ -8,6 +8,14 @@ pub struct VoxelSceneBundle {
8
8
pub visibility : Visibility ,
9
9
}
10
10
11
+ #[ derive( Bundle , Default ) ]
12
+ pub struct VoxelSceneHookBundle {
13
+ pub scene : Handle < VoxelScene > ,
14
+ pub hook : VoxelSceneHook ,
15
+ pub transform : Transform ,
16
+ pub visibility : Visibility ,
17
+ }
18
+
11
19
#[ derive( Asset , TypePath , Debug ) ]
12
20
pub struct VoxelScene {
13
21
pub name : String ,
@@ -44,23 +52,35 @@ pub struct VoxelLayer {
44
52
pub name : Option < String > ,
45
53
}
46
54
47
- #[ derive( Event ) ]
48
- pub struct VoxelEntityReady {
49
- pub scene_name : String ,
50
- pub entity : Entity ,
51
- pub name : String ,
52
- pub layer_id : u32 ,
55
+ #[ derive( Component ) ]
56
+ pub struct VoxelSceneHook {
57
+ hook : Box < dyn Fn ( & EntityRef , & mut EntityCommands ) + Send + Sync + ' static > ,
58
+ }
59
+
60
+ impl VoxelSceneHook {
61
+ pub fn new < F : Fn ( & EntityRef , & mut EntityCommands ) + Send + Sync + ' static > ( hook : F ) -> Self {
62
+ Self {
63
+ hook : Box :: new ( hook) ,
64
+ }
65
+ }
66
+ }
67
+
68
+ impl Default for VoxelSceneHook {
69
+ fn default ( ) -> Self {
70
+ Self :: new ( |_, _| {
71
+ warn ! ( "Default VoxelSceneHook does nothing" )
72
+ } )
73
+ }
53
74
}
54
75
55
76
pub ( crate ) fn spawn_vox_scenes (
56
77
mut commands : Commands ,
57
78
query : Query < ( Entity , & Transform , & Visibility , & Handle < VoxelScene > ) > ,
58
79
vox_scenes : Res < Assets < VoxelScene > > ,
59
- mut event_writer : EventWriter < VoxelEntityReady > ,
60
80
) {
61
81
for ( root, transform, visibility, scene_handle) in query. iter ( ) {
62
82
if let Some ( scene) = vox_scenes. get ( scene_handle) {
63
- spawn_voxel_node_recursive ( & mut commands, & scene. root , root, scene, & mut event_writer ) ;
83
+ spawn_voxel_node_recursive ( & mut commands, & scene. root , root, scene) ;
64
84
commands. entity ( root)
65
85
. remove :: < Handle < VoxelScene > > ( )
66
86
. insert ( ( * transform, * visibility) ) ;
@@ -73,9 +93,11 @@ fn spawn_voxel_node_recursive(
73
93
voxel_node : & VoxelNode ,
74
94
entity : Entity ,
75
95
scene : & VoxelScene ,
76
- event_writer : & mut EventWriter < VoxelEntityReady > ,
77
96
) {
78
97
let mut entity_commands = commands. entity ( entity) ;
98
+ if let Some ( name) = & voxel_node. name {
99
+ entity_commands. insert ( Name :: new ( name. clone ( ) ) ) ;
100
+ }
79
101
if let Some ( model) = voxel_node. model_id . and_then ( |id| {
80
102
if let Some ( model) = scene. models . get ( id) {
81
103
Some ( model)
@@ -109,17 +131,34 @@ fn spawn_voxel_node_recursive(
109
131
for child in & voxel_node. children {
110
132
let mut child_entity = builder. spawn_empty ( ) ;
111
133
let id = child_entity. id ( ) ;
112
- spawn_voxel_node_recursive ( child_entity. commands ( ) , child, id, scene, event_writer ) ;
134
+ spawn_voxel_node_recursive ( child_entity. commands ( ) , child, id, scene) ;
113
135
}
114
136
} ) ;
115
- if let Some ( name) = & voxel_node. name {
116
- entity_commands. insert ( Name :: new ( name. clone ( ) ) ) ;
117
- event_writer. send ( VoxelEntityReady {
118
- scene_name : scene. name . clone ( ) ,
119
- entity,
120
- name : name. to_string ( ) ,
121
- layer_id : voxel_node. layer_id
122
- } ) ;
137
+ }
138
+
139
+ pub ( super ) fn run_hooks (
140
+ mut commands : Commands ,
141
+ world : & World ,
142
+ query : Query < ( Entity , & VoxelSceneHook ) , Without < Handle < VoxelScene > > > ,
143
+ ) {
144
+ for ( entity, scene_hook) in query. iter ( ) {
145
+ run_hook_recursive ( & mut commands, world, entity, scene_hook) ;
146
+ commands. entity ( entity) . remove :: < VoxelSceneHook > ( ) ;
147
+ }
148
+ }
149
+
150
+ fn run_hook_recursive (
151
+ commands : & mut Commands ,
152
+ world : & World ,
153
+ entity : Entity ,
154
+ scene_hook : & VoxelSceneHook ,
155
+ ) {
156
+ let entity_ref = world. entity ( entity) ;
157
+ let mut entity_commands = commands. entity ( entity) ;
158
+ ( scene_hook. hook ) ( & entity_ref, & mut entity_commands) ;
159
+ let Some ( children) = entity_ref. get :: < Children > ( ) else { return } ;
160
+ for child in children. as_ref ( ) {
161
+ run_hook_recursive ( commands, world, * child, scene_hook) ;
123
162
}
124
163
}
125
164
@@ -221,7 +260,7 @@ fn transform_from_frame(frame: &Frame) -> Mat4 {
221
260
222
261
#[ cfg( test) ]
223
262
mod tests {
224
- use bevy:: { app:: App , asset:: { AssetPlugin , AssetServer , LoadState , AssetApp } , MinimalPlugins , render:: texture:: ImagePlugin , hierarchy:: Children , reflect :: Enum } ;
263
+ use bevy:: { app:: App , asset:: { AssetPlugin , AssetServer , LoadState , AssetApp } , MinimalPlugins , render:: texture:: ImagePlugin , hierarchy:: Children } ;
225
264
use crate :: VoxScenePlugin ;
226
265
use super :: * ;
227
266
@@ -293,21 +332,26 @@ mod tests {
293
332
let mut app = App :: new ( ) ;
294
333
let handle = setup_and_load_voxel_scene ( & mut app, "test.vox#outer-group/inner-group" ) . await ;
295
334
app. update ( ) ;
296
-
335
+
297
336
assert_eq ! ( app. world. resource:: <AssetServer >( ) . load_state( handle. clone( ) ) , LoadState :: Loaded ) ;
298
- let entity = app. world . spawn ( VoxelSceneBundle {
337
+ let entity = app. world . spawn ( VoxelSceneHookBundle {
299
338
scene : handle,
339
+ hook : VoxelSceneHook :: new ( move |entity, _| {
340
+ let Some ( name) = entity. get :: < Name > ( ) else { return } ;
341
+ let expected_names: [ & ' static str ; 3 ] = [ "outer-group/inner-group" , "outer-group/inner-group/dice" , "outer-group/inner-group/walls" ] ;
342
+ assert ! ( expected_names. contains( & name. as_str( ) ) ) ;
343
+ } ) ,
300
344
..Default :: default ( )
301
345
} ) . id ( ) ;
302
346
app. update ( ) ;
303
-
304
347
assert ! ( app. world. get:: <Handle <VoxelScene >>( entity) . is_none( ) ) ;
305
348
assert_eq ! ( app. world. query:: <& VoxelLayer >( ) . iter( & app. world) . len( ) , 5 , "5 voxel nodes spawned in this scene slice" ) ;
306
349
assert_eq ! ( app. world. query:: <& Name >( ) . iter( & app. world) . len( ) , 3 , "But only 3 of the voxel nodes are named" ) ;
307
350
assert_eq ! ( app. world. get:: <Name >( entity) . expect( "Name component" ) . as_str( ) , "outer-group/inner-group" ) ;
308
351
let children = app. world . get :: < Children > ( entity) . expect ( "children of inner-group" ) . as_ref ( ) ;
309
352
assert_eq ! ( children. len( ) , 4 , "inner-group has 4 children" ) ;
310
353
assert_eq ! ( app. world. get:: <Name >( * children. last( ) . expect( "last child" ) ) . expect( "Name component" ) . as_str( ) , "outer-group/inner-group/dice" ) ;
354
+ app. update ( ) ; // fire the hooks
311
355
}
312
356
313
357
/// `await` the response from this and then call `app.update()`
0 commit comments