use crate::{App, Plugin};
use alloc::{vec, vec::Vec};
use bevy_ecs::{
resource::Resource,
schedule::{
ExecutorKind, InternedScheduleLabel, IntoScheduleConfigs, Schedule, ScheduleLabel,
SystemSet,
},
system::Local,
world::{Mut, World},
};
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct Main;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct PreStartup;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct Startup;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct PostStartup;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct First;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct PreUpdate;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct RunFixedMainLoop;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct FixedFirst;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct FixedPreUpdate;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct FixedUpdate;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct FixedPostUpdate;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct FixedLast;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct FixedMain;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct Update;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct SpawnScene;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct PostUpdate;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct Last;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub struct Animation;
#[derive(Resource, Debug)]
pub struct MainScheduleOrder {
pub labels: Vec<InternedScheduleLabel>,
pub startup_labels: Vec<InternedScheduleLabel>,
}
impl Default for MainScheduleOrder {
fn default() -> Self {
Self {
labels: vec![
First.intern(),
PreUpdate.intern(),
RunFixedMainLoop.intern(),
Update.intern(),
SpawnScene.intern(),
PostUpdate.intern(),
Last.intern(),
],
startup_labels: vec![PreStartup.intern(), Startup.intern(), PostStartup.intern()],
}
}
}
impl MainScheduleOrder {
pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {
let index = self
.labels
.iter()
.position(|current| (**current).eq(&after))
.unwrap_or_else(|| panic!("Expected {after:?} to exist"));
self.labels.insert(index + 1, schedule.intern());
}
pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {
let index = self
.labels
.iter()
.position(|current| (**current).eq(&before))
.unwrap_or_else(|| panic!("Expected {before:?} to exist"));
self.labels.insert(index, schedule.intern());
}
pub fn insert_startup_after(
&mut self,
after: impl ScheduleLabel,
schedule: impl ScheduleLabel,
) {
let index = self
.startup_labels
.iter()
.position(|current| (**current).eq(&after))
.unwrap_or_else(|| panic!("Expected {after:?} to exist"));
self.startup_labels.insert(index + 1, schedule.intern());
}
pub fn insert_startup_before(
&mut self,
before: impl ScheduleLabel,
schedule: impl ScheduleLabel,
) {
let index = self
.startup_labels
.iter()
.position(|current| (**current).eq(&before))
.unwrap_or_else(|| panic!("Expected {before:?} to exist"));
self.startup_labels.insert(index, schedule.intern());
}
}
impl Main {
pub fn run_main(world: &mut World, mut run_at_least_once: Local<bool>) {
if !*run_at_least_once {
world.resource_scope(|world, order: Mut<MainScheduleOrder>| {
for &label in &order.startup_labels {
let _ = world.try_run_schedule(label);
}
});
*run_at_least_once = true;
}
world.resource_scope(|world, order: Mut<MainScheduleOrder>| {
for &label in &order.labels {
let _ = world.try_run_schedule(label);
}
});
}
}
pub struct MainSchedulePlugin;
impl Plugin for MainSchedulePlugin {
fn build(&self, app: &mut App) {
let mut main_schedule = Schedule::new(Main);
main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
let mut fixed_main_schedule = Schedule::new(FixedMain);
fixed_main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
let mut fixed_main_loop_schedule = Schedule::new(RunFixedMainLoop);
fixed_main_loop_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
app.add_schedule(main_schedule)
.add_schedule(fixed_main_schedule)
.add_schedule(fixed_main_loop_schedule)
.init_resource::<MainScheduleOrder>()
.init_resource::<FixedMainScheduleOrder>()
.add_systems(Main, Main::run_main)
.add_systems(FixedMain, FixedMain::run_fixed_main)
.configure_sets(
RunFixedMainLoop,
(
RunFixedMainLoopSystem::BeforeFixedMainLoop,
RunFixedMainLoopSystem::FixedMainLoop,
RunFixedMainLoopSystem::AfterFixedMainLoop,
)
.chain(),
);
#[cfg(feature = "bevy_debug_stepping")]
{
use bevy_ecs::schedule::{IntoScheduleConfigs, Stepping};
app.add_systems(Main, Stepping::begin_frame.before(Main::run_main));
}
}
}
#[derive(Resource, Debug)]
pub struct FixedMainScheduleOrder {
pub labels: Vec<InternedScheduleLabel>,
}
impl Default for FixedMainScheduleOrder {
fn default() -> Self {
Self {
labels: vec![
FixedFirst.intern(),
FixedPreUpdate.intern(),
FixedUpdate.intern(),
FixedPostUpdate.intern(),
FixedLast.intern(),
],
}
}
}
impl FixedMainScheduleOrder {
pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {
let index = self
.labels
.iter()
.position(|current| (**current).eq(&after))
.unwrap_or_else(|| panic!("Expected {after:?} to exist"));
self.labels.insert(index + 1, schedule.intern());
}
pub fn insert_before(&mut self, before: impl ScheduleLabel, schedule: impl ScheduleLabel) {
let index = self
.labels
.iter()
.position(|current| (**current).eq(&before))
.unwrap_or_else(|| panic!("Expected {before:?} to exist"));
self.labels.insert(index, schedule.intern());
}
}
impl FixedMain {
pub fn run_fixed_main(world: &mut World) {
world.resource_scope(|world, order: Mut<FixedMainScheduleOrder>| {
for &label in &order.labels {
let _ = world.try_run_schedule(label);
}
});
}
}
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, SystemSet)]
pub enum RunFixedMainLoopSystem {
BeforeFixedMainLoop,
FixedMainLoop,
AfterFixedMainLoop,
}