examples/systems/
system_sync_point.rs

1use crate::z_ignore_test_common::*;
2
3use flecs_ecs::prelude::*;
4#[derive(Component)]
5pub struct PositionSP {
6    x: f32,
7    y: f32,
8}
9
10#[derive(Component)]
11pub struct VelocitySP {
12    x: f32,
13    y: f32,
14}
15
16fn main() {
17    let world = World::new();
18
19    // System that sets velocity using ecs_set for entities with PositionSP.
20    // While systems are progressing, operations like ecs_set are deferred until
21    // it is safe to merge. By default this merge happens at the end of the
22    // frame, but we can annotate systems to give the scheduler more information
23    // about what it's doing, which allows it to insert sync points earlier.
24    //
25    // Note that sync points are never necessary/inserted for systems that write
26    // components provided by their signature, as these writes directly happen
27    // in the ECS storage and are never deferred.
28    //
29    // .inout_none() for PositionSP tells the scheduler that while we
30    // want to match entities with PositionSP, we're not interested in reading or
31    // writing the component value.
32
33    world
34        .system_named::<()>("SetVelocitySP")
35        .with::<&PositionSP>()
36        .set_inout_none()
37        .write::<VelocitySP>() // VelocitySP is written, but shouldn't be matched
38        .each_entity(|e, ()| {
39            e.set(VelocitySP { x: 1.0, y: 2.0 });
40        });
41
42    // This system reads VelocitySP, which causes the insertion of a sync point.
43    world
44        .system_named::<(&mut PositionSP, &VelocitySP)>("Move")
45        .each(|(p, v)| {
46            p.x += v.x;
47            p.y += v.y;
48        });
49
50    // Print resulting PositionSP
51    world
52        .system_named::<&PositionSP>("PrintPositionSP")
53        .each_entity(|e, p| {
54            println!("{}: {{ {}, {} }}", e.name(), p.x, p.y);
55        });
56
57    // Create a few test entities for a PositionSP, VelocitySP query
58    world
59        .entity_named("e1")
60        .set(PositionSP { x: 10.0, y: 20.0 })
61        .set(VelocitySP { x: 1.0, y: 2.0 });
62
63    world
64        .entity_named("e2")
65        .set(PositionSP { x: 10.0, y: 20.0 })
66        .set(VelocitySP { x: 3.0, y: 4.0 });
67
68    // Run systems. Debug logging enables us to see the generated schedule.
69    // NOTE flecs C / flecs_ecs_sys needs to be build in debug mode to see the logging.
70    // use the feature flag "sys_build_debug" to enable debug build of flecs C.
71    set_log_level(1);
72    world.progress();
73    set_log_level(-1);
74
75    // Output:
76    // info: pipeline rebuild
77    // info: | schedule: threading: 0, staging: 1:
78    // info: | | system SetVelocitySP
79    // info: | | merge
80    // info: | schedule: threading: 0, staging: 1:
81    // info: | | system Move
82    // info: | | system PrintPositionSP
83    // info: | | merge
84    // e1: { 11, 22 }
85    // e2: { 11, 22 }
86
87    // The "merge" lines indicate sync points.
88    //
89    // Removing `.write::<VelocitySP>()` from the system will remove the first
90    // sync point from the schedule.
91}
92
93#[cfg(feature = "flecs_nightly_tests")]
94#[test]
95#[ignore = "`set_log_level` is not safe in parallel tests"]
96fn test() {
97    let output_capture = OutputCapture::capture().unwrap();
98    main();
99    output_capture.test("system_sync_point".to_string());
100}