@@ -261,19 +261,29 @@ fn main() {
261
261
//
262
262
// SYSTEM EXECUTION ORDER
263
263
//
264
- // By default, all systems run in parallel. This is efficient, but sometimes order matters.
264
+ // Each system belongs to a `Stage`, which controls the execution strategy and broad order of the systems within each tick.
265
+ // Startup stages (which startup systems are registered in) will always complete before ordinary stages begin,
266
+ // and every system in a stage must complete before the next stage advances.
267
+ // Once every stage has concluded, the main loop is complete and begins again.
268
+ //
269
+ // By default, all systems run in parallel, except when they require mutable access to a piece of data.
270
+ // This is efficient, but sometimes order matters.
265
271
// For example, we want our "game over" system to execute after all other systems to ensure we don't
266
272
// accidentally run the game for an extra round.
267
273
//
268
- // First, if a system writes a component or resource (ComMut / ResMut), it will force a synchronization.
269
- // Any systems that access the data type and were registered BEFORE the system will need to finish first.
270
- // Any systems that were registered _after_ the system will need to wait for it to finish. This is a great
271
- // default that makes everything "just work" as fast as possible without us needing to think about it ... provided
272
- // we don't care about execution order. If we do care, one option would be to use the rules above to force a synchronization
273
- // at the right time. But that is complicated and error prone!
274
+ // Rather than splitting each of your systems into separate stages, you should force an explicit ordering between them
275
+ // by giving the relevant systems a label with `.label`, then using the `.before` or `.after` methods.
276
+ // Systems will not be scheduled until all of the systems that they have an "ordering dependency" on have completed.
277
+ //
278
+ // Doing that will, in just about all cases, lead to better performance compared to
279
+ // splitting systems between stages, because it gives the scheduling algorithm more
280
+ // opportunities to run systems in parallel.
281
+ // Stages are still necessary, however: end of a stage is a hard sync point
282
+ // (meaning, no systems are running) where `Commands` issued by systems are processed.
283
+ // This is required because commands can perform operations that are incompatible with
284
+ // having systems in flight, such as spawning or deleting entities,
285
+ // adding or removing resources, etc.
274
286
//
275
- // This is where "stages" come in. A "stage" is a group of systems that execute (in parallel). Stages are executed in order,
276
- // and the next stage won't start until all systems in the current stage have finished.
277
287
// add_system(system) adds systems to the UPDATE stage by default
278
288
// However we can manually specify the stage if we want to. The following is equivalent to add_system(score_system)
279
289
. add_system_to_stage ( stage:: UPDATE , score_system. system ( ) )
@@ -285,11 +295,22 @@ fn main() {
285
295
. add_stage_after ( stage:: UPDATE , "after_round" , SystemStage :: parallel ( ) )
286
296
. add_system_to_stage ( "before_round" , new_round_system. system ( ) )
287
297
. add_system_to_stage ( "before_round" , new_player_system. system ( ) )
288
- . add_system_to_stage ( "after_round" , score_check_system. system ( ) )
289
- . add_system_to_stage ( "after_round" , game_over_system. system ( ) )
290
- // score_check_system will run before game_over_system because score_check_system modifies GameState and game_over_system
291
- // reads GameState. This works, but it's a bit confusing. In practice, it would be clearer to create a new stage that runs
292
- // before "after_round"
298
+ // We can ensure that game_over system runs after score_check_system using explicit ordering constraints
299
+ // First, we label the system we want to refer to using `.label`
300
+ // Then, we use either `.before` or `.after` to describe the order we want the relationship
301
+ . add_system_to_stage (
302
+ "after_round" ,
303
+ score_check_system. system ( ) . label ( "score_check" ) ,
304
+ )
305
+ . add_system_to_stage (
306
+ "after_round" ,
307
+ game_over_system. system ( ) . after ( "score_check" ) ,
308
+ )
309
+ // We can check our systems for execution order ambiguities by examining the output produced in the console
310
+ // by adding the following Resource to our App :)
311
+ // Be aware that not everything reported by this checker is a potential problem, you'll have to make
312
+ // that judgement yourself.
313
+ . insert_resource ( ReportExecutionOrderAmbiguities )
293
314
// This call to run() starts the app we just built!
294
315
. run ( ) ;
295
316
}
0 commit comments