limnus_default_schedulers/
lib.rs1use limnus_app::prelude::{App, Plugin};
7use limnus_clock::MonotonicTime;
8use limnus_default_stages::{
9 First, FixedFirst, FixedPostUpdate, FixedPreUpdate, FixedUpdate, PostUpdate, PreUpdate,
10 RenderFirst, RenderPostUpdate, RenderPreUpdate, RenderUpdate, Update,
11};
12use limnus_resource::prelude::Resource;
13use limnus_scheduler::Scheduler;
14use limnus_stage::Stages;
15use limnus_system_params::MsgAll;
16use limnus_system_state::State;
17use monotonic_time_rs::{Millis, MillisDuration};
18use std::any::TypeId;
19
20#[derive(Debug)]
21pub struct MainScheduler;
22impl Scheduler for MainScheduler {
23 fn schedule(&self, stages: &Stages, state: &mut State) {
24 let stage_ids = {
25 vec![
26 TypeId::of::<First>(),
27 TypeId::of::<PreUpdate>(),
28 TypeId::of::<Update>(),
29 TypeId::of::<PostUpdate>(),
30 ]
31 };
32
33 for &stage_id in &stage_ids {
34 stages
35 .get_by_id(&stage_id)
36 .expect("stage missing")
37 .run(state);
38 }
39 }
40}
41
42#[derive(Debug, Resource)]
43pub struct FixedSchedulerData {
44 pub consumed_up_to_time: Millis,
45 pub ticks_per_second: usize,
46}
47
48#[derive(Debug)]
49pub struct FixedScheduler;
50impl Scheduler for FixedScheduler {
51 fn schedule(&self, stages: &Stages, state: &mut State) {
52 let current_time = { state.resources().fetch::<MonotonicTime>().time };
53
54 let (mut consumed_time, ticks_per_second) = {
55 let data = state.resources().fetch::<FixedSchedulerData>();
56 (data.consumed_up_to_time, data.ticks_per_second)
57 };
58
59 let steps_to_perform = if consumed_time > current_time {
60 let time_ahead = consumed_time - current_time;
62 let exact_steps_ahead = (time_ahead.as_millis() * ticks_per_second as u64) / 1_000;
63 #[allow(clippy::bool_to_int_with_if)]
64 if exact_steps_ahead > 4 { 0 } else { 1 }
65 } else {
66 let time_debt = current_time - consumed_time;
68
69 let exact_steps_needed = (time_debt.as_millis() * ticks_per_second as u64) / 1_000;
70
71 if exact_steps_needed > 1 { 2 } else { 1 }
73 };
74
75 let stage_ids = {
76 vec![
77 TypeId::of::<FixedFirst>(),
78 TypeId::of::<FixedPreUpdate>(),
79 TypeId::of::<FixedUpdate>(),
80 TypeId::of::<FixedPostUpdate>(),
81 ]
82 };
83
84 let fixed_time_step_ms = 1000 / ticks_per_second;
85
86 for _ in 0..steps_to_perform {
87 for &stage_id in &stage_ids {
88 stages
89 .get_by_id(&stage_id)
90 .expect("stage missing")
91 .run(state);
92 }
93 consumed_time += MillisDuration::from_millis(fixed_time_step_ms as u64);
94 }
95
96 {
97 let fixed_scheduler_data = state.resources_mut().fetch_mut::<FixedSchedulerData>();
98 fixed_scheduler_data.consumed_up_to_time = consumed_time;
99 }
100 }
101}
102
103#[derive(Debug)]
104pub struct RenderScheduler;
105impl Scheduler for RenderScheduler {
106 fn schedule(&self, stages: &Stages, state: &mut State) {
107 let stage_ids = {
109 vec![
110 TypeId::of::<RenderFirst>(),
111 TypeId::of::<RenderPreUpdate>(),
112 TypeId::of::<RenderUpdate>(),
113 TypeId::of::<RenderPostUpdate>(),
114 ]
115 };
116
117 for &stage_id in &stage_ids {
118 stages
119 .get_by_id(&stage_id)
120 .expect("stage missing")
121 .run(state);
122 }
123 }
124}
125
126fn swap_messages(mut messages: MsgAll) {
127 messages.swap_all();
128}
129
130pub struct DefaultSchedulersPlugin;
131
132impl Plugin for DefaultSchedulersPlugin {
133 fn build(&self, app: &mut App) {
134 let time = { app.resources().fetch::<MonotonicTime>().time };
135
136 app.insert_resource(FixedSchedulerData {
137 consumed_up_to_time: time,
138 ticks_per_second: 60,
139 });
140
141 app.add_scheduler(MainScheduler);
142 app.add_scheduler(FixedScheduler);
143 app.add_scheduler(RenderScheduler);
144
145 app.add_system(First, swap_messages);
146 }
147}