diff --git a/Cargo.lock b/Cargo.lock index 8f975354..9ed39ff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1148,9 +1148,9 @@ dependencies = [ [[package]] name = "bevy_prototype_debug_lines" -version = "0.10.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b3d03aef02c038e30415712097916928bc375abeb8a6b332dae85a898c4a54" +checksum = "bb1785a35dee1a7ce603569befa4e25ed4cb8b57341b2442c7fedb14e602b139" dependencies = [ "bevy", ] @@ -2319,6 +2319,7 @@ dependencies = [ "bevy_prototype_debug_lines", "de_core", "de_index", + "de_spawner", "parry3d", "smallvec", ] @@ -2591,7 +2592,6 @@ dependencies = [ "ahash 0.8.3", "bevy", "de_core", - "de_energy", "de_index", "de_map", "de_objects", diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 1d07a8cb..89537061 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -8,7 +8,6 @@ use visibility::VisibilityPlugin; pub mod assets; pub mod cleanup; -mod energy_markers; mod errors; pub mod events; pub mod flags; diff --git a/crates/energy/Cargo.toml b/crates/energy/Cargo.toml index f1fcf027..6afa9884 100644 --- a/crates/energy/Cargo.toml +++ b/crates/energy/Cargo.toml @@ -14,6 +14,9 @@ categories.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +de_spawner.workspace = true + + bevy.workspace = true de_core.workspace = true smallvec.workspace = true diff --git a/crates/energy/src/battery.rs b/crates/energy/src/battery.rs index 5b18417a..0b353e07 100644 --- a/crates/energy/src/battery.rs +++ b/crates/energy/src/battery.rs @@ -1,10 +1,15 @@ use bevy::prelude::*; +use de_core::objects::Active; +use de_spawner::SpawnerSet; pub(crate) struct BatteryPlugin; impl Plugin for BatteryPlugin { fn build(&self, app: &mut App) { - app.add_systems(Update, discharge_battery); + app.add_systems( + Update, + (discharge_battery, spawn_battery.after(SpawnerSet::Spawn)), + ); } } @@ -58,6 +63,12 @@ impl Battery { } } +fn spawn_battery(mut commands: Commands, newly_spawned_units: Query>) { + for entity in newly_spawned_units.iter() { + commands.entity(entity).insert((Battery::default(),)); + } +} + /// Discharges the batteries of all units. /// /// # Arguments diff --git a/crates/energy/src/graph.rs b/crates/energy/src/graph.rs index c04f0259..21c65b1e 100644 --- a/crates/energy/src/graph.rs +++ b/crates/energy/src/graph.rs @@ -1,17 +1,15 @@ use std::collections::HashSet; -use std::ops::Add; -use bevy::ecs::query::QueryParIter; use bevy::prelude::*; use bevy::utils::petgraph::prelude::*; use bevy::utils::petgraph::visit::IntoNodeReferences; -use bevy::utils::{HashMap, Instant}; +use bevy::utils::Instant; use bevy_prototype_debug_lines::{DebugLines, DebugLinesPlugin}; -use de_core::baseset::GameSet; use de_core::gamestate::GameState; -use de_core::objects::{MovableSolid, StaticSolid}; +use de_core::objects::Active; use de_core::projection::ToFlat; use de_index::SpatialQuery; +use de_spawner::{DespawnedComponentsEvent, DespawnEventsPlugin, SpawnerSet}; use parry3d::bounding_volume::Aabb; use parry3d::math::Point; use smallvec::{smallvec, SmallVec}; @@ -23,24 +21,18 @@ pub(crate) struct GraphPlugin; impl Plugin for GraphPlugin { fn build(&self, app: &mut App) { - app.add_plugin(DebugLinesPlugin::default()) - .add_system(setup.in_schedule(OnEnter(GameState::Playing))) - .add_system( - update_nearby_recv - .in_base_set(GameSet::PreUpdate) - .in_set(GraphSystemSet::UpdateNearby) - .run_if(in_state(GameState::Playing)), - ) - .add_system( - update_graph - .in_base_set(GameSet::PreUpdate) - .in_set(GraphSystemSet::UpdateGraph) - .run_if(in_state(GameState::Playing)), - ) - .add_system(clean_up.in_schedule(OnExit(GameState::Playing))) - .add_system( - debug_lines - .in_base_set(GameSet::PostUpdate) + app.add_plugins((DebugLinesPlugin::default(), DespawnEventsPlugin::<&NearbyUnits, NearbyUnits>::default())) + .add_systems(OnEnter(GameState::Playing), setup) + .add_systems(OnExit(GameState::Playing), clean_up) + .add_systems(Update, spawn_graph_components.after(SpawnerSet::Spawn)) + .add_systems( + PreUpdate, + ( + remove_old_nodes.before(GraphSystemSet::UpdateNearby), + update_nearby_recv.in_set(GraphSystemSet::UpdateNearby), + update_graph.in_set(GraphSystemSet::UpdateGraph).after(GraphSystemSet::UpdateNearby), + debug_lines.after(GraphSystemSet::UpdateGraph), + ) .run_if(in_state(GameState::Playing)), ); } @@ -50,7 +42,6 @@ impl Plugin for GraphPlugin { enum GraphSystemSet { UpdateNearby, UpdateGraph, - CleanUp, } /// The power grid resource is used to store the power grid graph. @@ -92,10 +83,9 @@ impl Nearby { } } -#[derive(Component, Default)] +#[derive(Component, Default, Debug, Clone)] pub struct NearbyUnits(SmallVec<[Nearby; 2]>, Option); - fn setup(mut commands: Commands) { commands.insert_resource(PowerGrid::default()); } @@ -104,6 +94,18 @@ fn clean_up(mut commands: Commands) { commands.remove_resource::(); } +/// This system spawns Energy Producers and Energy Receivers and nearby units. +fn spawn_graph_components( + mut commands: Commands, + newly_spawned_units: Query>, +) { + for entity in newly_spawned_units.iter() { + commands + .entity(entity) + .insert((EnergyReceiver, NearbyUnits::default())); + } +} + fn update_nearby_recv( spacial_index_producer: SpatialQuery>, spacial_index_receiver: SpatialQuery>, @@ -156,6 +158,7 @@ fn update_nearby( ]; } +#[allow(clippy::type_complexity)] fn update_graph( mut power_grid: ResMut, nearby_units: Query<(Entity, &NearbyUnits), Or<(Added, Changed)>>, @@ -183,7 +186,6 @@ fn update_graph( edges_to_add.push((entity, *receiver)); } } - _ => {} } } @@ -202,35 +204,39 @@ fn update_graph( } } -// fn remove_old_nodes( -// mut power_grid: ResMut, -// mut nearby_removed: RemovedComponents, -// mut death_events: EventReader>, -// ) { -// // for entity in nearby_removed.iter() { -// // // for edge in power_grid.graph.edges(entity).collect::>() { -// // // nearby_units.get_mut(edge.target()).unwrap().0.retain(|e| match e { -// // // Nearby::Receiver(entity) => {} -// // // Nearby::Producer(entity) => {} -// // // } != entity); -// // // } -// // -// // power_grid.graph.remove_node(entity); -// // } -// } +fn remove_old_nodes( + mut power_grid: ResMut, + mut nearby_units: Query<&mut NearbyUnits>, + mut death_events: EventReader>, +) { + for event in death_events.iter() { + power_grid.graph.remove_node(event.entity); + + for outer_nearby in event.data.0.iter().flat_map(|nearby| nearby.clone().into_inner()) { + for inner_nearby in nearby_units.get_mut(outer_nearby).unwrap().0.iter_mut(){ + match inner_nearby { + Nearby::Producer(producer) => { + producer.retain(|entity| *entity != event.entity) + } + Nearby::Receiver(receiver) => { + receiver.retain(|entity| *entity != event.entity) + } + } + } + } + } +} fn debug_lines( power_grid: Res, query: Query<&Transform>, mut debug_lines: ResMut, ) { - let mut i = 0; for (node, _) in power_grid.graph.node_references() { let node_location = query.get(node).unwrap().translation; for neighbor in power_grid.graph.neighbors(node) { let neighbor_location = query.get(neighbor).unwrap().translation; debug_lines.line_colored(node_location, neighbor_location, 0., Color::RED); - i += 1; } } } diff --git a/crates/spawner/Cargo.toml b/crates/spawner/Cargo.toml index f475e2a8..ecdd0f55 100644 --- a/crates/spawner/Cargo.toml +++ b/crates/spawner/Cargo.toml @@ -21,7 +21,6 @@ de_index.workspace = true de_map.workspace = true de_objects.workspace = true de_terrain.workspace = true -de_energy.workspace = true # Other ahash.workspace = true diff --git a/crates/spawner/src/lib.rs b/crates/spawner/src/lib.rs index 5025d1b1..f3f7ae93 100644 --- a/crates/spawner/src/lib.rs +++ b/crates/spawner/src/lib.rs @@ -9,6 +9,7 @@ pub use draft::{DraftAllowed, DraftBundle}; use gameend::GameEndPlugin; pub use spawner::SpawnBundle; use spawner::SpawnerPlugin; +pub use spawner::SpawnerSet; use crate::despawner::DespawnerPlugin; diff --git a/crates/spawner/src/spawner.rs b/crates/spawner/src/spawner.rs index 216ef285..3ddee50d 100644 --- a/crates/spawner/src/spawner.rs +++ b/crates/spawner/src/spawner.rs @@ -7,10 +7,8 @@ use de_core::{ objects::{Active, ActiveObjectType, MovableSolid, ObjectType, Playable, StaticSolid}, player::Player, }; -use de_energy::{Battery, EnergyReceiver, NearbyUnits}; use de_objects::{AssetCollection, InitialHealths, SceneType, Scenes, SolidObjects}; use de_terrain::{CircleMarker, MarkerVisibility, RectangleMarker}; -use smallvec::smallvec; use crate::ObjectCounter; @@ -18,10 +16,21 @@ pub(crate) struct SpawnerPlugin; impl Plugin for SpawnerPlugin { fn build(&self, app: &mut App) { - app.add_systems(Update, spawn.run_if(in_state(GameState::Playing))); + app.add_systems( + Update, + spawn + .run_if(in_state(GameState::Playing)) + .in_set(SpawnerSet::Spawn), + ); } } +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub enum SpawnerSet { + /// This exists so that we can manage newly spawned objects by `.after(SpawnerSet::Spawn)`. + Spawn, +} + #[derive(Bundle)] pub struct SpawnBundle { object_type: ObjectType, @@ -69,9 +78,9 @@ fn spawn( match object_type { ObjectType::Active(active_type) => { entity_commands.insert(Active); - entity_commands.insert(Battery::default()); - entity_commands.insert(EnergyReceiver); - entity_commands.insert(NearbyUnits::default()); + // entity_commands.insert(Battery::default()); + // entity_commands.insert(EnergyReceiver); + // entity_commands.insert(NearbyUnits::default()); let player = *player.expect("Active object without an associated was spawned."); counter.player_mut(player).unwrap().update(active_type, 1);