Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
JackCrumpLeys committed Sep 4, 2023
1 parent 60ee8a8 commit 1377440
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 96 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ ahash = "0.8.3"
anyhow = "1.0"
approx = "0.5.1"
assert_cmd = "2.0.10"
bevy_prototype_debug_lines = { version="0.11", features = ["3d"] }
async-compat = "0.2.1"
async-std = "1.11"
async-tar = "0.4.2"
Expand Down
2 changes: 1 addition & 1 deletion crates/energy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ parry3d.workspace = true
tinyvec.workspace = true

# This cannot be a workspace dependency because it is optional
bevy_prototype_debug_lines = { version="0.11", features = ["3d"], optional = true }
bevy_prototype_debug_lines = { workspace = true, optional = true }

[dev-dependencies]
# DE
Expand Down
8 changes: 4 additions & 4 deletions crates/energy/benches/nearby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bevy::prelude::{
use bevy::time::TimePlugin;
use criterion::{criterion_group, criterion_main, Criterion};
use de_core::projection::ToAltitude;
use de_energy::{update_nearby_recv, EnergyReceiver, NearbyUnits};
use de_energy::{update_nearby, EnergyGridMember, NearbyUnits};
use de_index::{EntityIndex, LocalCollider};
use de_objects::ObjectCollider;
use de_test_utils::{load_points, NumPoints};
Expand Down Expand Up @@ -75,7 +75,7 @@ fn init_world_with_entities_moving(world: &mut World, num_entities: &NumPoints)
x: point_msl.x,
y: point_msl.y,
},
EnergyReceiver,
EnergyGridMember,
NearbyUnits::default(),
UnitNumber(i as u32),
))
Expand Down Expand Up @@ -116,7 +116,7 @@ fn nearby_benchmark(c: &mut Criterion) {
for i in [OneHundred, OneThousand, TenThousand, OneHundredThousand] {
let mut app = App::default();
init_world_with_entities_moving(&mut app.world, &i);
app.add_systems(Update, update_nearby_recv);
app.add_systems(Update, update_nearby);
app.add_plugins(TimePlugin);

let update_units_schedule = Schedule::default();
Expand Down Expand Up @@ -155,7 +155,7 @@ fn nearby_benchmark(c: &mut Criterion) {
);
let mut amount_of_connections_formed = 0;
for connections in app.world.query::<&mut NearbyUnits>().iter(&app.world) {
amount_of_connections_formed += connections.units().len()
amount_of_connections_formed += connections.len()
}
println!(
"We ended up with {} connections between {} units",
Expand Down
5 changes: 3 additions & 2 deletions crates/energy/src/battery.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use bevy::prelude::*;
use de_core::objects::Active;
use de_core::state::AppState;

pub(crate) struct BatteryPlugin;

impl Plugin for BatteryPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, discharge_battery)
.add_systems(PostUpdate, spawn_battery);
app.add_systems(Update, discharge_battery.run_if(in_state(AppState::InGame)))
.add_systems(PostUpdate, spawn_battery.run_if(in_state(AppState::InGame)));
}
}

Expand Down
156 changes: 68 additions & 88 deletions crates/energy/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,64 @@ use std::collections::HashSet;
use bevy::prelude::*;
use bevy::utils::petgraph::prelude::*;
#[cfg(feature = "energy_graph_debug_lines")]
use bevy::utils::petgraph::visit::IntoNodeReferences;
#[cfg(feature = "energy_graph_debug_lines")]
use bevy_prototype_debug_lines::{DebugLines, DebugLinesPlugin};
use de_core::gamestate::GameState;
use de_core::objects::Active;
use de_core::projection::ToFlat;
use de_core::state::AppState;
use de_index::SpatialQuery;
use de_spawner::{DespawnEventsPlugin, DespawnedComponentsEvent};
use parry3d::bounding_volume::Aabb;
use parry3d::math::Point;
use tinyvec::TinyVec;

// The max distance (in meters) between two entities for them to be consider neighbors in the graph
use crate::Battery;

/// The max distance (in meters) between two entities for them to be consider neighbors in the graph
const MAX_DISTANCE: f32 = 10.0;
/// Minimum distance squared traveled by an object to update its nearby units.
const MIN_DISTANCE_FOR_UPDATE: f32 = 0.5;

pub(crate) struct GraphPlugin;

impl Plugin for GraphPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(DespawnEventsPlugin::<&NearbyUnits, NearbyUnits>::default())
.add_systems(OnEnter(GameState::Playing), setup)
.add_systems(OnExit(GameState::Playing), clean_up)
.add_systems(PostUpdate, spawn_graph_components)
.add_systems(OnEnter(AppState::InGame), setup)
.add_systems(OnExit(AppState::InGame), clean_up)
.add_systems(
PostUpdate,
spawn_graph_components.run_if(in_state(AppState::InGame)),
)
.add_systems(
Update,
remove_old_nodes
.before(GraphSystemSet::UpdateNearby)
.run_if(in_state(GameState::Playing)),
)
.add_systems(
FixedUpdate,
(
remove_old_nodes.before(GraphSystemSet::UpdateNearby),
update_nearby_recv.in_set(GraphSystemSet::UpdateNearby),
update_nearby.in_set(GraphSystemSet::UpdateNearby),
update_graph
.in_set(GraphSystemSet::UpdateGraph)
.after(GraphSystemSet::UpdateNearby),
)
.run_if(in_state(GameState::Playing)),
.run_if(in_state(AppState::InGame)),
);

#[cfg(feature = "energy_graph_debug_lines")]
app.add_plugins(DebugLinesPlugin::default()).add_systems(
PostUpdate,
(debug_lines).run_if(in_state(GameState::Playing)),
);
app.add_plugins(DebugLinesPlugin::default())
.add_systems(PostUpdate, debug_lines.run_if(in_state(AppState::InGame)));
}
}

/// wrapped entity to allow for default values (se we can work with TinyVec)
#[derive(Debug, Clone, PartialEq, Eq, Hash, SystemSet)]
enum GraphSystemSet {
UpdateNearby,
UpdateGraph,
}

/// wrapped entity to allow for default values (so we can work with TinyVec)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NearbyEntity(Entity);

Expand All @@ -68,12 +82,6 @@ impl From<Entity> for NearbyEntity {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, SystemSet)]
enum GraphSystemSet {
UpdateNearby,
UpdateGraph,
}

/// The power grid resource is used to store the power grid graph.
#[derive(Resource, Debug, Clone)]
pub(crate) struct PowerGrid {
Expand All @@ -89,50 +97,29 @@ impl Default for PowerGrid {
}
}

/// The energy receiver component is used to mark an entity as an energy receiver.
#[derive(Component, Debug, Clone, Copy)]
pub struct EnergyReceiver;

/// The energy producer component is used to mark an entity as an energy producer.
#[derive(Component, Debug, Clone, Copy)]
pub struct EnergyProducer;

/// The nearby component is used to store the nearby entities of an entity.
#[derive(Debug, Clone, Default)]
pub struct Nearby {
receivers: TinyVec<[NearbyEntity; 32]>,
producers: TinyVec<[NearbyEntity; 32]>,
}

impl Nearby {
fn both(&self) -> TinyVec<[NearbyEntity; 64]> {
self.receivers
.clone()
.into_iter()
.chain(self.producers.clone())
.collect()
}

fn clear(&mut self) {
self.receivers.clear();
self.producers.clear();
}

fn remove_matching(&mut self, entity: NearbyEntity) {
self.receivers.retain(|&e| e != entity);
self.producers.retain(|&e| e != entity);
}
}
/// The energy grid member component is used to store the energy grid member entities.
#[derive(Component, Debug, Clone)]
pub struct EnergyGridMember;

/// The nearby units component is used to store the nearby entities of an entity.
#[derive(Component, Default, Debug, Clone)]
pub struct NearbyUnits {
units: Nearby,
units: TinyVec<[NearbyEntity; 16]>,
last_pos: Option<Vec2>,
}

impl NearbyUnits {
pub fn units(&self) -> TinyVec<[NearbyEntity; 64]> {
self.units.both()
fn remove_matching(&mut self, entity: NearbyEntity) {
self.units.retain(|e| *e != entity);
println!("removed {:?} from {:?}", entity, self.units);
}

pub fn len(&self) -> usize {
self.units.len()
}

pub fn is_empty(&self) -> bool {
self.units.is_empty()
}
}

Expand All @@ -147,49 +134,40 @@ fn clean_up(mut commands: Commands) {
/// This system spawns Energy Producers and Energy Receivers and nearby units.
fn spawn_graph_components(
mut commands: Commands,
newly_spawned_units: Query<Entity, Added<Active>>,
newly_spawned_units: Query<Entity, Added<Battery>>,
) {
for entity in newly_spawned_units.iter() {
commands
.entity(entity)
.insert((EnergyReceiver, NearbyUnits::default()));
.insert((EnergyGridMember, NearbyUnits::default()));
}
}

pub fn update_nearby_recv(
spacial_index_producer: SpatialQuery<Entity, With<EnergyProducer>>,
spacial_index_receiver: SpatialQuery<Entity, With<EnergyReceiver>>,
pub fn update_nearby(
spacial_index_member: SpatialQuery<Entity, With<EnergyGridMember>>,
mut nearby_units: Query<(Entity, &mut NearbyUnits, &Transform), Changed<Transform>>,
) {
nearby_units
.par_iter_mut()
.for_each_mut(|(entity, mut nearby_units, transform)| {
let current_pos = transform.translation.to_flat();
if let Some(last_pos) = nearby_units.last_pos {
if transform.translation.to_flat().distance_squared(last_pos) < 0.5 {
if current_pos.distance_squared(last_pos) < MIN_DISTANCE_FOR_UPDATE {
return;
}
}
nearby_units.last_pos = Some(transform.translation.to_flat());
nearby_units.last_pos = Some(current_pos);

let aabb = &Aabb::new(
Point::from(transform.translation - Vec3::splat(MAX_DISTANCE)),
Point::from(transform.translation + Vec3::splat(MAX_DISTANCE)),
);

let producers = spacial_index_producer.query_aabb(aabb, Some(entity));

let receivers = spacial_index_receiver.query_aabb(aabb, Some(entity));
let members = spacial_index_member.query_aabb(aabb, Some(entity));

nearby_units.units.clear();

nearby_units
.units
.producers
.extend(producers.map(|entity| entity.into()));
nearby_units
.units
.receivers
.extend(receivers.map(|entity| entity.into()));
nearby_units.units.extend(members.map(NearbyEntity));
});
}

Expand All @@ -209,8 +187,8 @@ fn update_graph(

let mut edges_to_add = vec![];

for nearby_entity in nearby_units.units.both() {
edges_to_add.push((entity, nearby_entity.into()));
for nearby_entity in &nearby_units.units {
edges_to_add.push((entity, nearby_entity.0));
}

for edge in edges_to_add.iter() {
Expand All @@ -230,15 +208,16 @@ fn update_graph(

fn remove_old_nodes(
mut power_grid: ResMut<PowerGrid>,
mut nearby_units: Query<&mut NearbyUnits>,
mut nearby_units_query: Query<&mut NearbyUnits>,
mut death_events: EventReader<DespawnedComponentsEvent<NearbyUnits>>,
) {
for event in death_events.iter() {
power_grid.graph.remove_node(event.entity);

// Remove the entity from the nearby units of all nearby units
for mut nearby_units in nearby_units.iter_mut() {
nearby_units.units.remove_matching(event.entity.into())
for neighbor in power_grid.graph.neighbors(event.entity) {
if let Ok(mut nearby_units) = nearby_units_query.get_mut(neighbor) {
nearby_units.remove_matching(event.entity.into());
}
}
}
}
Expand All @@ -249,11 +228,12 @@ fn debug_lines(
query: Query<&Transform>,
mut debug_lines: ResMut<DebugLines>,
) {
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);
}
for (from, to, _) in power_grid.graph.all_edges() {
let from = query.get(from).unwrap();
let to = query.get(to).unwrap();

// if let (Ok(from), Ok(to)) = (from, to) {
debug_lines.line_colored(from.translation, to.translation, 0., Color::RED);
// }
}
}
2 changes: 1 addition & 1 deletion crates/energy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod graph;

pub use battery::Battery;
use bevy::{app::PluginGroupBuilder, prelude::PluginGroup};
pub use graph::{update_nearby_recv, EnergyReceiver, NearbyUnits};
pub use graph::{update_nearby, EnergyGridMember, NearbyUnits};

use crate::battery::BatteryPlugin;
use crate::graph::GraphPlugin;
Expand Down

0 comments on commit 1377440

Please sign in to comment.