use core::ops::Deref;
use bevy_ecs::{
change_detection::DetectChangesMut,
resource::Resource,
system::ResMut,
world::{FromWorld, World},
};
use super::{freely_mutable_state::FreelyMutableState, states::States};
#[cfg(feature = "bevy_reflect")]
use bevy_ecs::prelude::ReflectResource;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::prelude::ReflectDefault;
#[derive(Resource, Debug)]
#[cfg_attr(
feature = "bevy_reflect",
derive(bevy_reflect::Reflect),
reflect(Resource, Debug, PartialEq)
)]
pub struct State<S: States>(pub(crate) S);
impl<S: States> State<S> {
pub fn new(state: S) -> Self {
Self(state)
}
pub fn get(&self) -> &S {
&self.0
}
}
impl<S: States + FromWorld> FromWorld for State<S> {
fn from_world(world: &mut World) -> Self {
Self(S::from_world(world))
}
}
impl<S: States> PartialEq<S> for State<S> {
fn eq(&self, other: &S) -> bool {
self.get() == other
}
}
impl<S: States> Deref for State<S> {
type Target = S;
fn deref(&self) -> &Self::Target {
self.get()
}
}
#[derive(Resource, Debug, Default, Clone)]
#[cfg_attr(
feature = "bevy_reflect",
derive(bevy_reflect::Reflect),
reflect(Resource, Default, Debug)
)]
pub enum NextState<S: FreelyMutableState> {
#[default]
Unchanged,
Pending(S),
PendingIfNeq(S),
}
impl<S: FreelyMutableState> NextState<S> {
pub fn set(&mut self, state: S) {
*self = Self::Pending(state);
}
pub fn set_if_neq(&mut self, state: S) {
if !matches!(self, Self::Pending(s) if s == &state) {
*self = Self::PendingIfNeq(state);
}
}
pub fn reset(&mut self) {
*self = Self::Unchanged;
}
}
pub(crate) fn take_next_state<S: FreelyMutableState>(
next_state: Option<ResMut<NextState<S>>>,
) -> Option<(S, bool)> {
let mut next_state = next_state?;
match core::mem::take(next_state.bypass_change_detection()) {
NextState::Pending(x) => {
next_state.set_changed();
Some((x, true))
}
NextState::PendingIfNeq(x) => {
next_state.set_changed();
Some((x, false))
}
NextState::Unchanged => None,
}
}