Skip to content

Commit a9d4f55

Browse files
Implement StateSet
1 parent d5a7330 commit a9d4f55

File tree

2 files changed

+374
-0
lines changed

2 files changed

+374
-0
lines changed

crates/bevy_ecs/src/schedule/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod executor;
22
mod executor_parallel;
33
mod stage;
44
mod state;
5+
mod state_set;
56
mod system_container;
67
mod system_descriptor;
78
mod system_set;
@@ -10,6 +11,7 @@ pub use executor::*;
1011
pub use executor_parallel::*;
1112
pub use stage::*;
1213
pub use state::*;
14+
pub use state_set::*;
1315
pub use system_container::*;
1416
pub use system_descriptor::*;
1517
pub use system_set::*;
Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
use std::{
2+
any::TypeId,
3+
marker::PhantomData,
4+
mem::{discriminant, Discriminant},
5+
};
6+
7+
use bevy_utils::HashMap;
8+
9+
use crate::{
10+
ArchetypeComponent, IntoSystem, ResMut, Resource, ShouldRun, System, SystemDescriptor,
11+
SystemId, SystemSet, SystemStage, TypeAccess,
12+
};
13+
#[derive(Debug)]
14+
pub struct SetState<T: Clone> {
15+
transition: Option<StateTransition<T>>,
16+
stack: Vec<T>,
17+
scheduled: Option<ScheduledOperation<T>>,
18+
}
19+
20+
#[derive(Debug)]
21+
enum StateTransition<T: Clone> {
22+
ExitingToResume(T, T),
23+
ExitingFull(T, T),
24+
Entering(T, T),
25+
Resuming(T, T),
26+
Pausing(T, T),
27+
}
28+
29+
#[derive(Debug)]
30+
pub enum ScheduledOperation<T: Clone> {
31+
Next(T),
32+
Pop,
33+
Push(T),
34+
}
35+
36+
impl<T: Clone + Resource> SetState<T> {
37+
fn on_update(d: Discriminant<T>) -> impl System<In = (), Out = ShouldRun> {
38+
Wrapper::<T, OnUpdate>::new(d)
39+
}
40+
41+
fn on_enter(d: Discriminant<T>) -> impl System<In = (), Out = ShouldRun> {
42+
Wrapper::<T, OnEnter>::new(d)
43+
}
44+
45+
fn on_exit(d: Discriminant<T>) -> impl System<In = (), Out = ShouldRun> {
46+
Wrapper::<T, OnExit>::new(d)
47+
}
48+
49+
fn on_pause(d: Discriminant<T>) -> impl System<In = (), Out = ShouldRun> {
50+
Wrapper::<T, OnExit>::new(d)
51+
}
52+
53+
fn on_resume(d: Discriminant<T>) -> impl System<In = (), Out = ShouldRun> {
54+
Wrapper::<T, OnExit>::new(d)
55+
}
56+
57+
pub fn schedule_operation(
58+
&mut self,
59+
val: ScheduledOperation<T>,
60+
) -> Option<ScheduledOperation<T>> {
61+
self.scheduled.replace(val)
62+
}
63+
64+
pub fn new(val: T) -> Self {
65+
Self {
66+
stack: vec![val],
67+
transition: None,
68+
scheduled: None,
69+
}
70+
}
71+
72+
pub fn current(&self) -> &T {
73+
self.stack.last().unwrap()
74+
}
75+
}
76+
77+
trait Comparer<T: Clone> {
78+
fn compare(d: Discriminant<T>, s: &SetState<T>) -> bool;
79+
}
80+
81+
struct OnUpdate;
82+
impl<T: Clone> Comparer<T> for OnUpdate {
83+
fn compare(d: Discriminant<T>, s: &SetState<T>) -> bool {
84+
discriminant(s.stack.last().unwrap()) == d && s.transition.is_none()
85+
}
86+
}
87+
struct OnEnter;
88+
impl<T: Clone> Comparer<T> for OnEnter {
89+
fn compare(d: Discriminant<T>, s: &SetState<T>) -> bool {
90+
s.transition
91+
.as_ref()
92+
.map_or(false, |transition| match transition {
93+
StateTransition::Entering(_, entering) => discriminant(entering) == d,
94+
_ => false,
95+
})
96+
}
97+
}
98+
struct OnExit;
99+
impl<T: Clone> Comparer<T> for OnExit {
100+
fn compare(d: Discriminant<T>, s: &SetState<T>) -> bool {
101+
s.transition
102+
.as_ref()
103+
.map_or(false, |transition| match transition {
104+
StateTransition::ExitingToResume(exiting, _)
105+
| StateTransition::ExitingFull(exiting, _) => discriminant(exiting) == d,
106+
_ => false,
107+
})
108+
}
109+
}
110+
struct OnPause;
111+
impl<T: Clone> Comparer<T> for OnPause {
112+
fn compare(d: Discriminant<T>, s: &SetState<T>) -> bool {
113+
s.transition
114+
.as_ref()
115+
.map_or(false, |transition| match transition {
116+
StateTransition::Pausing(pausing, _) => discriminant(pausing) == d,
117+
_ => false,
118+
})
119+
}
120+
}
121+
struct OnResume;
122+
impl<T: Clone> Comparer<T> for OnResume {
123+
fn compare(d: Discriminant<T>, s: &SetState<T>) -> bool {
124+
s.transition
125+
.as_ref()
126+
.map_or(false, |transition| match transition {
127+
StateTransition::Resuming(_, resuming) => discriminant(resuming) == d,
128+
_ => false,
129+
})
130+
}
131+
}
132+
133+
impl<T: Clone + Resource, C: Comparer<T>> Wrapper<T, C> {
134+
fn new(discriminant: Discriminant<T>) -> Self {
135+
let mut resource_access = TypeAccess::default();
136+
resource_access.add_read(std::any::TypeId::of::<SetState<T>>());
137+
Self {
138+
discriminant,
139+
exit_flag: false,
140+
resource_access,
141+
id: SystemId::new(),
142+
archetype_access: Default::default(),
143+
component_access: Default::default(),
144+
marker: Default::default(),
145+
}
146+
}
147+
}
148+
149+
struct Wrapper<T: Clone + Resource, C: Comparer<T>> {
150+
discriminant: Discriminant<T>,
151+
exit_flag: bool,
152+
resource_access: TypeAccess<TypeId>,
153+
id: SystemId,
154+
archetype_access: TypeAccess<ArchetypeComponent>,
155+
component_access: TypeAccess<TypeId>,
156+
marker: PhantomData<C>,
157+
}
158+
159+
impl<T: Clone + Resource, C: Comparer<T> + Resource> System for Wrapper<T, C> {
160+
type In = ();
161+
type Out = ShouldRun;
162+
163+
fn name(&self) -> std::borrow::Cow<'static, str> {
164+
std::borrow::Cow::Owned(format!(
165+
"State checker for state {}",
166+
std::any::type_name::<T>()
167+
))
168+
}
169+
170+
fn id(&self) -> crate::SystemId {
171+
self.id
172+
}
173+
174+
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
175+
&self.archetype_access
176+
}
177+
178+
fn resource_access(&self) -> &TypeAccess<TypeId> {
179+
&self.resource_access
180+
}
181+
182+
fn component_access(&self) -> &TypeAccess<TypeId> {
183+
&self.component_access
184+
}
185+
186+
fn is_non_send(&self) -> bool {
187+
false
188+
}
189+
190+
unsafe fn run_unsafe(
191+
&mut self,
192+
_input: Self::In,
193+
_world: &crate::World,
194+
resources: &crate::Resources,
195+
) -> Option<Self::Out> {
196+
let state = &*resources.get::<SetState<T>>().unwrap();
197+
if state.transition.is_some() {
198+
self.exit_flag = false;
199+
}
200+
if self.exit_flag {
201+
self.exit_flag = false;
202+
Some(ShouldRun::No)
203+
} else {
204+
self.exit_flag = true;
205+
Some(if C::compare(self.discriminant, state) {
206+
ShouldRun::YesAndCheckAgain
207+
} else {
208+
ShouldRun::NoAndCheckAgain
209+
})
210+
}
211+
}
212+
213+
fn update_access(&mut self, _world: &crate::World) {}
214+
215+
fn apply_buffers(&mut self, _world: &mut crate::World, _resources: &mut crate::Resources) {}
216+
217+
fn initialize(&mut self, _world: &mut crate::World, _resources: &mut crate::Resources) {}
218+
}
219+
220+
pub struct StateSetBuilder<T: Clone + Resource> {
221+
on_update: HashMap<Discriminant<T>, SystemSet>,
222+
on_enter: HashMap<Discriminant<T>, SystemSet>,
223+
on_exit: HashMap<Discriminant<T>, SystemSet>,
224+
on_pause: HashMap<Discriminant<T>, SystemSet>,
225+
on_resume: HashMap<Discriminant<T>, SystemSet>,
226+
}
227+
228+
impl<T: Clone + Resource> Default for StateSetBuilder<T> {
229+
fn default() -> Self {
230+
Self {
231+
on_update: Default::default(),
232+
on_enter: Default::default(),
233+
on_exit: Default::default(),
234+
on_pause: Default::default(),
235+
on_resume: Default::default(),
236+
}
237+
}
238+
}
239+
240+
impl<T: Clone + Resource> StateSetBuilder<T> {
241+
pub fn add_on_update(&mut self, v: T, system: impl Into<SystemDescriptor>) -> &mut Self {
242+
self.on_update
243+
.entry(discriminant(&v))
244+
.or_default()
245+
.add_system(system);
246+
self
247+
}
248+
249+
pub fn add_on_enter(&mut self, v: T, system: impl Into<SystemDescriptor>) -> &mut Self {
250+
self.on_enter
251+
.entry(discriminant(&v))
252+
.or_default()
253+
.add_system(system);
254+
self
255+
}
256+
257+
pub fn add_on_exit(&mut self, v: T, system: impl Into<SystemDescriptor>) -> &mut Self {
258+
self.on_exit
259+
.entry(discriminant(&v))
260+
.or_default()
261+
.add_system(system);
262+
self
263+
}
264+
265+
pub fn add_on_pause(&mut self, v: T, system: impl Into<SystemDescriptor>) -> &mut Self {
266+
self.on_pause
267+
.entry(discriminant(&v))
268+
.or_default()
269+
.add_system(system);
270+
self
271+
}
272+
273+
pub fn add_on_resume(&mut self, v: T, system: impl Into<SystemDescriptor>) -> &mut Self {
274+
self.on_resume
275+
.entry(discriminant(&v))
276+
.or_default()
277+
.add_system(system);
278+
self
279+
}
280+
281+
pub fn with_on_update(mut self, v: T, system: impl Into<SystemDescriptor>) -> Self {
282+
self.add_on_update(v, system);
283+
self
284+
}
285+
286+
pub fn with_on_enter(mut self, v: T, system: impl Into<SystemDescriptor>) -> Self {
287+
self.add_on_enter(v, system);
288+
self
289+
}
290+
291+
pub fn with_on_exit(mut self, v: T, system: impl Into<SystemDescriptor>) -> Self {
292+
self.add_on_exit(v, system);
293+
self
294+
}
295+
296+
pub fn with_on_pause(mut self, v: T, system: impl Into<SystemDescriptor>) -> Self {
297+
self.add_on_pause(v, system);
298+
self
299+
}
300+
301+
pub fn with_on_resume(mut self, v: T, system: impl Into<SystemDescriptor>) -> Self {
302+
self.add_on_resume(v, system);
303+
self
304+
}
305+
306+
pub fn finalize(self, stage: &mut SystemStage) {
307+
fn state_cleaner<T: Clone + Resource>(mut state: ResMut<SetState<T>>) -> ShouldRun {
308+
match state.scheduled.take() {
309+
Some(ScheduledOperation::Next(next)) => {
310+
if state.stack.len() == 1 {
311+
let previous =
312+
std::mem::replace(state.stack.last_mut().unwrap(), next.clone());
313+
state.transition = Some(StateTransition::ExitingFull(previous, next));
314+
} else {
315+
state.scheduled = Some(ScheduledOperation::Next(next));
316+
match state.transition.take() {
317+
Some(StateTransition::ExitingToResume(p, n)) => {
318+
state.transition = Some(StateTransition::Resuming(p, n));
319+
}
320+
_ => {
321+
state.transition = Some(StateTransition::ExitingToResume(
322+
state.stack.pop().unwrap(),
323+
state.stack.last().unwrap().clone(),
324+
));
325+
}
326+
}
327+
}
328+
}
329+
Some(ScheduledOperation::Push(next)) => {
330+
let last = state.stack.last().unwrap().clone();
331+
state.stack.push(next.clone());
332+
state.transition = Some(StateTransition::Pausing(last, next));
333+
}
334+
Some(ScheduledOperation::Pop) => {
335+
state.transition = Some(StateTransition::ExitingToResume(
336+
state.stack.pop().unwrap(),
337+
state.stack.last().unwrap().clone(),
338+
));
339+
}
340+
None => match state.transition.take() {
341+
Some(StateTransition::ExitingFull(p, n))
342+
| Some(StateTransition::Pausing(p, n)) => {
343+
state.transition = Some(StateTransition::Entering(p, n));
344+
}
345+
Some(StateTransition::ExitingToResume(p, n)) => {
346+
state.transition = Some(StateTransition::Resuming(p, n));
347+
}
348+
_ => return ShouldRun::Yes,
349+
},
350+
};
351+
ShouldRun::YesAndCheckAgain
352+
}
353+
354+
for (val, set) in self.on_enter.into_iter() {
355+
stage.add_system_set(set.with_run_criteria(SetState::<T>::on_enter(val)));
356+
}
357+
for (val, set) in self.on_update.into_iter() {
358+
stage.add_system_set(set.with_run_criteria(SetState::<T>::on_update(val)));
359+
}
360+
for (val, set) in self.on_exit.into_iter() {
361+
stage.add_system_set(set.with_run_criteria(SetState::<T>::on_exit(val)));
362+
}
363+
for (val, set) in self.on_pause.into_iter() {
364+
stage.add_system_set(set.with_run_criteria(SetState::<T>::on_pause(val)));
365+
}
366+
for (val, set) in self.on_resume.into_iter() {
367+
stage.add_system_set(set.with_run_criteria(SetState::<T>::on_resume(val)));
368+
}
369+
370+
stage.add_system_set(SystemSet::default().with_run_criteria(state_cleaner::<T>.system()));
371+
}
372+
}

0 commit comments

Comments
 (0)