use bevy_app::prelude::*;
use bevy_ecs::{intern::Interned, prelude::*, schedule::ScheduleLabel};
use crate::bindings::wasvy::ecs::app::Schedule as WitSchedule;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModSchedule {
ModStartup,
PreUpdate,
Update,
PostUpdate,
FixedPreUpdate,
FixedUpdate,
FixedPostUpdate,
Custom {
name: String,
schedule: Interned<dyn ScheduleLabel>,
},
}
impl ModSchedule {
pub fn new_custom(name: impl ToString, schedule: impl ScheduleLabel) -> Self {
let name = name.to_string();
let schedule = schedule.intern();
Self::Custom { name, schedule }
}
pub fn schedule_label(&self) -> Interned<dyn ScheduleLabel> {
match self {
Self::ModStartup => ModStartup.intern(),
Self::PreUpdate => PreUpdate.intern(),
Self::Update => Update.intern(),
Self::PostUpdate => PostUpdate.intern(),
Self::FixedPreUpdate => FixedPreUpdate.intern(),
Self::FixedUpdate => FixedUpdate.intern(),
Self::FixedPostUpdate => FixedPostUpdate.intern(),
Self::Custom { schedule, .. } => *schedule,
}
}
}
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub(crate) struct ModStartup;
impl ModStartup {
pub(crate) fn new_schedule() -> Schedule {
Schedule::new(Self)
}
pub(crate) fn run(world: &mut World) {
let mut schedules = world
.get_resource_mut::<Schedules>()
.expect("running in an App");
let mut schedule = schedules
.insert(Self::new_schedule())
.expect("ModStartup schedule be added the App by ModloaderPlugin");
schedule.run(world);
}
}
#[derive(Resource, Debug, Clone)]
pub struct ModSchedules(pub Vec<ModSchedule>);
impl Default for ModSchedules {
fn default() -> Self {
Self(vec![
ModSchedule::ModStartup,
ModSchedule::PreUpdate,
ModSchedule::Update,
ModSchedule::PostUpdate,
ModSchedule::FixedPreUpdate,
ModSchedule::FixedUpdate,
ModSchedule::FixedPostUpdate,
])
}
}
impl ModSchedules {
pub fn empty() -> Self {
Self(Vec::new())
}
pub fn push(&mut self, schedule: ModSchedule) {
assert!(
!self.0.contains(&schedule),
"Duplicate schedule {:?} added to ModloaderPlugin",
&schedule
);
self.0.push(schedule);
}
pub(crate) fn evaluate(&self, schedule: &WitSchedule) -> Option<ModSchedule> {
let schedule_or_custom_name = match schedule {
WitSchedule::ModStartup => Either::Left(ModSchedule::ModStartup),
WitSchedule::PreUpdate => Either::Left(ModSchedule::PreUpdate),
WitSchedule::Update => Either::Left(ModSchedule::Update),
WitSchedule::PostUpdate => Either::Left(ModSchedule::PostUpdate),
WitSchedule::FixedPreUpdate => Either::Left(ModSchedule::FixedPreUpdate),
WitSchedule::FixedUpdate => Either::Left(ModSchedule::FixedUpdate),
WitSchedule::FixedPostUpdate => Either::Left(ModSchedule::FixedPostUpdate),
WitSchedule::Custom(custom_name) => Either::Right(custom_name),
};
match schedule_or_custom_name {
Either::Left(schedule) => {
if self.0.contains(&schedule) {
Some(schedule)
} else {
None
}
}
Either::Right(custom_name) => self
.0
.iter()
.find(|schedule| match schedule {
ModSchedule::Custom { name, .. } => name == custom_name,
_ => false,
})
.cloned(),
}
}
}
enum Either<L, R> {
Left(L),
Right(R),
}