use std::{any::TypeId, borrow::Cow, collections::HashMap};
use crate::{
archetype::Row,
exec_graph::{ExecGraph, ExecSystem, NodeIndex},
schedule_config::{
BaseConfig, NodeType, ScheduleLabel, SetConfig, StageLabel, SystemConfig, SystemSet,
},
system::BoxedSystem,
world::*,
};
use bevy_utils::intern::Interned;
use fixedbitset::FixedBitSet;
use pi_append_vec::SafeVec;
use pi_async_rt::prelude::{AsyncRuntime, AsyncRuntimeExt};
use pi_share::Share;
pub struct Schedule {
system_configs: Vec<(Interned<dyn StageLabel>, SystemConfig)>,
systems: Share<SafeVec<ExecSystem>>,
set_conditions: Share<SafeVec<BoxedSystem<bool>>>, schedule_graph:
HashMap<Interned<dyn ScheduleLabel>, HashMap<Interned<dyn StageLabel>, ExecGraph>>,
stage_sort: Vec<Interned<dyn StageLabel>>,
action: Vec<(Row, Row)>,
set: FixedBitSet,
set_configs: HashMap<Interned<dyn SystemSet>, BaseConfig>,
mian_config: BaseConfig,
add_listener: bool,
dirty_mark: bool,
}
impl Schedule {
pub fn new(add_listener: bool) -> Self {
Self {
system_configs: Vec::with_capacity(256),
systems: Share::new(SafeVec::default()),
set_conditions: Share::new(SafeVec::default()),
schedule_graph: Default::default(),
stage_sort: vec![
First.intern(),
PreUpdate.intern(),
Update.intern(),
PostUpdate.intern(),
Last.intern(),
],
action: Vec::with_capacity(256),
set: FixedBitSet::new(),
set_configs: HashMap::new(),
mian_config: BaseConfig {
sets: Default::default(),
schedules: vec![MainSchedule.intern()],
before: Vec::with_capacity(256),
after: Vec::with_capacity(256),
conditions: Vec::default(),
},
add_listener,
dirty_mark: false,
}
}
pub fn configure_set(&mut self, config: SetConfig) {
log::debug!(
"configure_set {:?}",
(
&config.set,
&config.config.sets,
&config.config.before,
&config.config.after
)
);
for in_set in config.config.sets.iter() {
if !self.set_configs.contains_key(in_set) {
self.set_configs.insert(*in_set, BaseConfig::default());
}
}
for set in config.config.after.iter() {
if let NodeType::Set(set) = set {
if !self.set_configs.contains_key(set) {
self.set_configs.insert(*set, BaseConfig::default());
}
}
}
for set in config.config.before.iter() {
if let NodeType::Set(set) = set {
if !self.set_configs.contains_key(set) {
self.set_configs.insert(*set, BaseConfig::default());
}
}
}
match self.set_configs.entry(config.set) {
std::collections::hash_map::Entry::Occupied(mut r) => {
let r = r.get_mut();
r.sets.extend_from_slice(config.config.sets.as_slice());
r.schedules
.extend_from_slice(config.config.schedules.as_slice());
r.before.extend_from_slice(config.config.before.as_slice());
r.after.extend_from_slice(config.config.after.as_slice());
}
std::collections::hash_map::Entry::Vacant(r) => {
r.insert(config.config);
}
}
}
pub fn add_system(
&mut self,
stage_label: Interned<dyn StageLabel>,
system_config: SystemConfig,
) {
self.system_configs.push((stage_label, system_config));
}
pub fn run<A: AsyncRuntime + AsyncRuntimeExt>(
&mut self,
world: &mut World,
rt: &A,
schedule: &Interned<dyn ScheduleLabel>,
) {
self.try_initialize(world);
let g = match self.schedule_graph.get_mut(schedule) {
Some(r) => r,
None => return,
};
#[cfg(feature = "trace")]
let update_span = tracing::warn_span!("update").entered();
world.increment_tick();
for stage in self.stage_sort.iter() {
if let Some(stage) = g.get_mut(stage) {
Self::run_graph(world, rt, stage, &self.systems, &self.set_conditions);
}
}
#[cfg(feature = "trace")]
let settle_by = tracing::warn_span!("settle_by").entered();
if schedule == &MainSchedule.intern() {
world.settle_by(&mut self.action, &mut self.set);
}
}
fn run_graph<A: AsyncRuntime + AsyncRuntimeExt>(
world: &mut World,
rt: &A,
g: &mut ExecGraph,
systems: &Share<SafeVec<ExecSystem>>,
set_conditions: &Share<SafeVec<BoxedSystem<bool>>>,
) {
#[cfg(feature = "trace")]
let run_span = tracing::warn_span!("run {:?}", name = &g.1).entered();
let w: &'static World = unsafe { std::mem::transmute(world) };
let g: &'static mut ExecGraph = unsafe { std::mem::transmute(g) };
let s: &'static Share<SafeVec<ExecSystem>> = unsafe { std::mem::transmute(systems) };
let c: &'static Share<SafeVec<BoxedSystem<bool>>> = unsafe { std::mem::transmute(set_conditions) };
let rt1 = rt.clone();
let _ = rt.block_on(async move {
let rt2 = rt1;
g.run(s, c, &rt2, w).await.unwrap();
#[cfg(feature = "trace")]
{
let _collect_span = tracing::warn_span!("settle").entered();
g.settle();
}
});
}
pub async fn async_run<A: AsyncRuntime + AsyncRuntimeExt>(
&mut self,
world: &mut World,
rt: &A,
schedule: &Interned<dyn ScheduleLabel>,
) {
self.try_initialize(world);
let g = self.schedule_graph.get_mut(schedule).unwrap();
for stage in self.stage_sort.iter() {
if let Some(stage) = g.get_mut(stage) {
Self::async_run_graph(world, rt, stage, &mut self.systems, &mut self.set_conditions).await;
}
}
if schedule == &MainSchedule.intern() {
world.settle_by(&mut self.action, &mut self.set);
}
}
async fn async_run_graph<A: AsyncRuntime + AsyncRuntimeExt>(
world: &mut World,
rt: &A,
g: &mut ExecGraph,
systems: &Share<SafeVec<ExecSystem>>,
set_conditions: &Share<SafeVec<BoxedSystem<bool>>>,
) {
let w: &'static World = unsafe { std::mem::transmute(world) };
let s: &'static Share<SafeVec<ExecSystem>> = unsafe { std::mem::transmute(&systems) };
let c: &'static Share<SafeVec<BoxedSystem<bool>>> = unsafe { std::mem::transmute(&set_conditions) };
g.run(s, c, rt, w).await.unwrap();
g.settle();
}
fn try_initialize(&mut self, world: &mut World) {
if self.system_configs.is_empty() {
return;
}
let mut temp_map = HashMap::default();
let mut temp_map2 = HashMap::default();
let mut system_configs = std::mem::take(&mut self.system_configs);
let mut temp_set_condition_index: HashMap<Interned<dyn SystemSet>, (usize/*start*/, usize/*len*/)> = HashMap::default();
let set_configs = &mut self.set_configs;
for (set, set_config) in set_configs.iter_mut() {
if set_config.conditions.is_empty() {
continue;
}
let conditions = std::mem::take(&mut set_config.conditions);
let index = (self.set_conditions.len(), conditions.len());
for condition in conditions.into_iter() {
self.set_conditions.insert(condition);
}
temp_set_condition_index.insert(set.clone(), (index.0, index.0 + index.1));
}
let rr = system_configs
.drain(..)
.map(|(stage_label, system_config)| {
(
stage_label,
self.add_system_config(
stage_label,
system_config,
&mut temp_map,
&mut temp_map2,
&temp_set_condition_index,
),
)
})
.collect::<Vec<(Interned<dyn StageLabel>, (BaseConfig, TypeId))>>();
self.link_set(&mut temp_map, &mut temp_map2, &temp_set_condition_index);
for (stage_label, (config, id)) in rr {
self.link_system_config(stage_label, id, config, &mut temp_map, &mut temp_map2, &temp_set_condition_index);
}
Share::get_mut(&mut self.systems).unwrap().settle(0);
for (_name, schedule) in self.schedule_graph.iter_mut() {
for (_, stage) in schedule.iter_mut() {
stage.initialize(self.systems.clone(), self.set_conditions.clone(), world, self.add_listener);
}
}
self.dirty_mark = false;
}
fn add_system_config(
&mut self,
stage_label: Interned<dyn StageLabel>,
mut system_config: SystemConfig,
temp_map: &mut HashMap<
Interned<dyn ScheduleLabel>,
HashMap<
Interned<dyn StageLabel>,
(
HashMap<TypeId, NodeIndex>,
HashMap<Interned<dyn SystemSet>, ((NodeIndex, bool), (NodeIndex, bool))>,
),
>,
>,
temp_map2: &mut HashMap<Interned<dyn SystemSet>, Vec<TypeId>>,
temp_set_condition_index: &HashMap<Interned<dyn SystemSet>, (usize, usize)>,
) -> (BaseConfig, TypeId) {
let sys = system_config.system;
let conditions = std::mem::take(&mut system_config.config.conditions);
let name = sys.name().clone();
let id = sys.id();
let index = self.systems.len();
let mut exec_system = ExecSystem {
system: sys,
conditions,
set_conditions: FixedBitSet::with_capacity(self.set_conditions.len()),
};
Self::init_system_set_condition(&system_config.config, &self.set_configs, temp_set_condition_index, &mut exec_system.set_conditions);
Self::add_system_config_inner(
None,
None,
&system_config.config,
&stage_label,
index,
&name,
id,
&mut self.schedule_graph,
temp_map,
temp_map2,
&self.set_configs,
);
Self::add_system_config_inner(
None,
None,
&self.mian_config,
&stage_label,
index,
&name,
id,
&mut self.schedule_graph,
temp_map,
temp_map2,
&self.set_configs,
);
self.systems.insert(exec_system);
(system_config.config, id)
}
fn add_system_config_inner(
set: Option<Interned<dyn SystemSet>>,
pre_set: Option<Interned<dyn SystemSet>>,
config: &BaseConfig,
stage_label: &Interned<dyn StageLabel>,
index: usize,
system_name: &Cow<'static, str>,
system_type_id: std::any::TypeId,
schedule_graph: &mut HashMap<
Interned<dyn ScheduleLabel>,
HashMap<Interned<dyn StageLabel>, ExecGraph>,
>,
temp_map: &mut HashMap<
Interned<dyn ScheduleLabel>,
HashMap<
Interned<dyn StageLabel>,
(
HashMap<TypeId, NodeIndex>,
HashMap<Interned<dyn SystemSet>, ((NodeIndex, bool), (NodeIndex, bool))>,
),
>,
>,
temp_map2: &mut HashMap<Interned<dyn SystemSet>, Vec<TypeId>>,
set_configs: &HashMap<Interned<dyn SystemSet>, BaseConfig>,
) {
if let Some(set) = set {
let set_map = match temp_map2.entry(set) {
std::collections::hash_map::Entry::Occupied(r) => r.into_mut(),
std::collections::hash_map::Entry::Vacant(r) => {
r.insert(vec![])
}
};
if pre_set.is_none() {
set_map.push(system_type_id);
}
}
if config.schedules.len() > 0 {
for schedule_label in config.schedules.iter() {
let schedule = match schedule_graph.entry(*schedule_label) {
std::collections::hash_map::Entry::Occupied(r) => r.into_mut(),
std::collections::hash_map::Entry::Vacant(r) => {
temp_map.insert(*schedule_label, Default::default());
r.insert(Default::default())
}
};
let map = temp_map.get_mut(schedule_label).unwrap();
let stage = match schedule.entry(stage_label.clone()) {
std::collections::hash_map::Entry::Occupied(r) => r.into_mut(),
std::collections::hash_map::Entry::Vacant(r) => {
map.insert(
stage_label.clone(),
(HashMap::default(), HashMap::default()),
);
r.insert(ExecGraph::new(format!(
"{:?}&{:?}",
schedule_label, stage_label
)))
}
};
let map = map.get_mut(stage_label).unwrap();
let node_index = stage.add_system(index, system_name.clone());
map.0.insert(system_type_id, node_index);
}
}
if config.sets.len() == 0 {
return;
}
for in_set in config.sets.iter() {
let config = match set_configs.get(in_set) {
Some(r) => r,
None => continue,
};
Self::add_system_config_inner(
Some(*in_set),
set,
config,
&stage_label,
index,
&system_name,
system_type_id,
schedule_graph,
temp_map,
temp_map2,
set_configs,
)
}
}
fn init_system_set_condition(
config: &BaseConfig,
set_configs: &HashMap<Interned<dyn SystemSet>, BaseConfig>,
temp_set_condition_index: &HashMap<Interned<dyn SystemSet>, (usize, usize)>,
sets_codition: &mut FixedBitSet,
) {
if config.sets.len() == 0 {
return;
}
for in_set in config.sets.iter() {
if let Some (condition_index) = temp_set_condition_index.get(in_set) {
for i in condition_index.0..condition_index.1 {
sets_codition.insert(i);
}
}
let config = match set_configs.get(in_set) {
Some(r) => r,
None => continue,
};
Self::init_system_set_condition(
config,
set_configs,
temp_set_condition_index,
sets_codition,
)
}
}
fn link_system_config(
&mut self,
stage_label: Interned<dyn StageLabel>,
id: TypeId,
config: BaseConfig,
temp_map: &mut HashMap<
Interned<dyn ScheduleLabel>,
HashMap<
Interned<dyn StageLabel>,
(
HashMap<TypeId, NodeIndex>,
HashMap<Interned<dyn SystemSet>, ((NodeIndex, bool), (NodeIndex, bool))>,
),
>,
>,
temp_map2: &mut HashMap<Interned<dyn SystemSet>, Vec<TypeId>>,
temp_set_condition_index: &HashMap<Interned<dyn SystemSet>, (usize, usize)>,
) {
Self::link_system_inner(
&config,
&config.before,
&config.after,
&stage_label,
id,
&mut self.schedule_graph,
temp_map,
temp_map2,
&self.set_configs,
temp_set_condition_index,
);
Self::link_system_inner(
&self.mian_config,
&config.before,
&config.after,
&stage_label,
id,
&mut self.schedule_graph,
temp_map,
temp_map2,
&self.set_configs,
temp_set_condition_index,
);
}
fn get_set_node(
set: Interned<dyn SystemSet>,
is_before: bool,
map: &mut HashMap<Interned<dyn SystemSet>, ((NodeIndex, bool), (NodeIndex, bool))>,
map2: &HashMap<TypeId, NodeIndex>,
map3: &HashMap<Interned<dyn SystemSet>, Vec<TypeId>>,
temp_set_condition_index: &HashMap<Interned<dyn SystemSet>, (usize, usize)>,
graph: &mut ExecGraph,
) -> NodeIndex {
let set_nodes = match map.entry(set.clone()) {
std::collections::hash_map::Entry::Occupied(r) => r.into_mut(),
std::collections::hash_map::Entry::Vacant(r) => {
let (start, end) = match temp_set_condition_index.get(&set) {
Some(r) => *r,
None => (0, 0),
};
let before_set_index = graph.add_set(start, end, format!("{:?}_before", set).into());
let after_set_index = graph.add_set(0, 0, format!("{:?}_after", set).into());
graph.add_edge(before_set_index, after_set_index);
r.insert(((before_set_index, false), (after_set_index, false)))
}
};
if is_before {
let r = set_nodes.0;
if !r.1 {
if let Some(m) = map3.get(&set) {
for i in m.iter() {
if let Some(i) = map2.get(i) {
graph.add_edge(r.0, *i);
}
}
}
}
r.0
} else {
let r = set_nodes.1;
if !r.1 {
if let Some(m) = map3.get(&set) {
for i in m.iter() {
if let Some(i) = map2.get(i) {
graph.add_edge(*i, r.0);
}
}
}
}
r.0
}
}
fn link_system_inner(
config: &BaseConfig,
before: &Vec<NodeType>,
after: &Vec<NodeType>,
stage_label: &Interned<dyn StageLabel>,
system_type_id: std::any::TypeId,
schedule_graph: &mut HashMap<
Interned<dyn ScheduleLabel>,
HashMap<Interned<dyn StageLabel>, ExecGraph>,
>,
temp_map: &mut HashMap<
Interned<dyn ScheduleLabel>,
HashMap<
Interned<dyn StageLabel>,
(
HashMap<TypeId, NodeIndex>,
HashMap<Interned<dyn SystemSet>, ((NodeIndex, bool), (NodeIndex, bool))>,
),
>,
>,
temp_map2: &mut HashMap<Interned<dyn SystemSet>, Vec<TypeId>>,
set_configs: &HashMap<Interned<dyn SystemSet>, BaseConfig>,
temp_set_condition_index: &HashMap<Interned<dyn SystemSet>, (usize, usize)>,
) {
if (before.len() > 0 || after.len() > 0) && config.schedules.len() > 0 {
for schedule_label in config.schedules.iter() {
let schedule = schedule_graph.get_mut(schedule_label).unwrap();
let map = temp_map.get_mut(schedule_label).unwrap();
let stage = schedule.get_mut(stage_label).unwrap();
let map = map.get_mut(stage_label).unwrap();
let node_index = map.0.get(&system_type_id).unwrap().clone();
if before.len() > 0 {
for before in before.iter() {
let before_index = match before {
NodeType::Set(set) => Self::get_set_node(
set.clone(),
true,
&mut map.1,
&map.0,
temp_map2,
temp_set_condition_index,
stage,
),
NodeType::System(r) => match map.0.get(r) {
Some(r) => r.clone(),
None => continue,
},
};
stage.add_edge(node_index, before_index);
}
}
if after.len() > 0 {
for after in after.iter() {
let after_index = match after {
NodeType::Set(set) => Self::get_set_node(
set.clone(),
false,
&mut map.1,
&map.0,
temp_map2,
temp_set_condition_index,
stage,
),
NodeType::System(r) => match map.0.get(r) {
Some(r) => r.clone(),
None => continue,
},
};
stage.add_edge(after_index, node_index);
}
}
}
}
if config.sets.len() == 0 {
return;
}
for in_set in config.sets.iter() {
let config = match set_configs.get(in_set) {
Some(r) => r,
None => continue,
};
Self::link_system_inner(
config,
before,
after,
&stage_label,
system_type_id,
schedule_graph,
temp_map,
temp_map2,
set_configs,
temp_set_condition_index,
)
}
}
fn link_set(
&mut self,
temp_map: &mut HashMap<
Interned<dyn ScheduleLabel>,
HashMap<
Interned<dyn StageLabel>,
(
HashMap<TypeId, NodeIndex>,
HashMap<Interned<dyn SystemSet>, ((NodeIndex, bool), (NodeIndex, bool))>,
),
>,
>,
temp_map2: &HashMap<Interned<dyn SystemSet>, Vec<TypeId>>,
temp_set_condition_index: &HashMap<Interned<dyn SystemSet>, (usize, usize)>,
) {
for (set, config) in self.set_configs.iter() {
for (schedule_label, schedule) in self.schedule_graph.iter_mut() {
let map = temp_map.get_mut(schedule_label).unwrap();
for (stage_label, stage) in schedule.iter_mut() {
let map = map.get_mut(stage_label).unwrap();
let set_before =
Self::get_set_node(set.clone(), true, &mut map.1, &map.0, temp_map2, temp_set_condition_index, stage);
let set_after = Self::get_set_node(
set.clone(),
false,
&mut map.1,
&map.0,
temp_map2,
temp_set_condition_index,
stage,
);
for in_set in config.sets.iter() {
let in_set_before = Self::get_set_node(
in_set.clone(),
true,
&mut map.1,
&map.0,
temp_map2,
temp_set_condition_index,
stage,
);
let in_set_after = Self::get_set_node(
in_set.clone(),
false,
&mut map.1,
&map.0,
temp_map2,
temp_set_condition_index,
stage,
);
stage.add_edge(in_set_before, set_before);
stage.add_edge(set_after, in_set_after);
}
if config.before.len() > 0 {
for before in config.before.iter() {
let before_index = match before {
NodeType::Set(set) => Self::get_set_node(
set.clone(),
true,
&mut map.1,
&map.0,
temp_map2,
temp_set_condition_index,
stage,
),
NodeType::System(r) => map.0.get(r).unwrap().clone(),
};
stage.add_edge(set_after, before_index);
}
}
if config.after.len() > 0 {
for after in config.after.iter() {
let after_index = match after {
NodeType::Set(set) => Self::get_set_node(
set.clone(),
false,
&mut map.1,
&map.0,
temp_map2,
temp_set_condition_index,
stage,
),
NodeType::System(r) => match map.0.get(r) {
Some(r) => r.clone(),
None => continue,
},
};
stage.add_edge(after_index, set_before);
}
}
}
}
}
}
}
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Startup;
#[derive(StageLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub struct First;
#[derive(StageLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub struct PreUpdate;
#[derive(StageLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Update;
#[derive(StageLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub struct PostUpdate;
#[derive(StageLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Last;
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct MainSchedule;
#[derive(SystemSet, Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct SystemSet1;