diff --git a/examples/schedule_graph_child_set.rs b/examples/schedule_graph_child_set.rs new file mode 100644 index 0000000..02060fb --- /dev/null +++ b/examples/schedule_graph_child_set.rs @@ -0,0 +1,35 @@ +use bevy::{log::LogPlugin, prelude::*}; + +/// A set for rapier's copying bevy_rapier's Bevy components back into rapier. +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] +pub struct SystemSet1; + +/// A set for rapier's copying bevy_rapier's Bevy components back into rapier. +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] +pub struct SystemSet2; + +fn main() { + let mut app = App::new(); + app.add_plugins(DefaultPlugins.build().disable::()); + app.add_systems( + Update, + ( + system1_no_set, + ( + ( + system_in_child_set1.in_set(SystemSet1), + system_in_child_set1.in_set(SystemSet1), + ), + system_in_child_set2.in_set(SystemSet2), + ) + .chain(), + ) + .chain(), + ); + bevy_mod_debugdump::print_schedule_graph(&mut app, Update); +} + +fn system_in_child_set1() {} + +fn system_in_child_set2() {} +fn system1_no_set() {} diff --git a/src/schedule_graph/mod.rs b/src/schedule_graph/mod.rs index 29de489..e3b2b80 100644 --- a/src/schedule_graph/mod.rs +++ b/src/schedule_graph/mod.rs @@ -12,13 +12,66 @@ use bevy_ecs::{ system::System, world::World, }; -use petgraph::{prelude::DiGraphMap, Direction}; +use petgraph::{ + prelude::DiGraphMap, + Direction::{self, Outgoing}, +}; + +fn dfs_all_neighbours_directed( + graph: &petgraph::prelude::GraphMap, + u: NodeId, + direction: Direction, +) -> Vec { + let mut res = vec![]; + + for neighbor in graph.neighbors_directed(u, direction) { + res.push(neighbor); + res.append(&mut dfs_all_neighbours_directed(graph, neighbor, direction)); + } + + res +} + +fn remove_transitive_edges( + graph: &mut petgraph::prelude::GraphMap, +) { + // Holds all root nodes + let mut top_nodes = HashSet::new(); + + for n in graph.nodes() { + let mut all_upstream_nodes = vec![n]; + + all_upstream_nodes.append(&mut dfs_all_neighbours_directed( + graph, + n, + Direction::Incoming, + )); + // Save the node which is most upstream + top_nodes.insert(all_upstream_nodes.last().unwrap().clone()); + } + + let toposort = petgraph::algo::toposort(&*graph, None).unwrap(); + + for visiting in toposort { + let direct_heighbours: Vec = graph.neighbors_directed(visiting, Outgoing).collect(); + for n in direct_heighbours { + graph.remove_edge(visiting, n); + // if we still can access a neighbour with a longer path, it's a transitive dependency. + let descendants = dfs_all_neighbours_directed(&graph, visiting, Direction::Outgoing); + if !descendants.contains(&n) { + // No longer path, so we're keeping that edge. + graph.add_edge(visiting, n, ()); + } + } + } +} /// Formats the schedule into a dot graph. pub fn schedule_graph_dot(schedule: &Schedule, world: &World, settings: &Settings) -> String { let graph = schedule.graph(); let hierarchy = graph.hierarchy().graph(); - let dependency = graph.dependency().graph(); + let dependency = &mut graph.dependency().graph().clone(); + remove_transitive_edges(dependency); let included_systems_sets = included_systems_sets(graph, settings);