use std::sync::{Arc, RwLock};
use bevy::prelude::*;
use crate::coord::CoordSystem;
use crate::octree::OctreeNode;
use crate::store::ZoneStore;
use crate::zone::ZoneEntry;
#[derive(Resource)]
pub struct SharedZoneStore(pub Arc<RwLock<ZoneStore>>);
#[derive(Resource)]
pub struct SharedOctreeRes(pub Arc<RwLock<OctreeNode>>);
#[derive(Component, Default)]
pub struct ZoneTracker {
pub active: Vec<u32>,
}
#[derive(Event)]
pub struct ZoneEnterEvent {
pub entity: Entity,
pub zone_id: u32,
}
#[derive(Event)]
pub struct ZoneExitEvent {
pub entity: Entity,
pub zone_id: u32,
}
pub struct Spatial3dPlugin<C: CoordSystem + Clone + Send + Sync + 'static> {
pub coord: C,
pub world_half: f64,
}
impl<C: CoordSystem + Clone + Send + Sync + 'static> Plugin for Spatial3dPlugin<C> {
fn build(&self, app: &mut App) {
let store = ZoneStore::from_entries(&[], &self.coord);
let octree = OctreeNode::new([0.0; 3], self.world_half);
app.insert_resource(SharedZoneStore(Arc::new(RwLock::new(store))))
.insert_resource(SharedOctreeRes(Arc::new(RwLock::new(octree))))
.insert_resource(CoordRes(self.coord.clone()))
.add_event::<ZoneEnterEvent>()
.add_event::<ZoneExitEvent>()
.add_systems(Update, zone_tracking_system::<C>);
}
}
#[derive(Resource)]
struct CoordRes<C>(C);
fn zone_tracking_system<C: CoordSystem + Clone + Send + Sync + 'static>(
store: Res<SharedZoneStore>,
coord: Res<CoordRes<C>>,
mut query: Query<(Entity, &GlobalTransform, &mut ZoneTracker)>,
mut enter: EventWriter<ZoneEnterEvent>,
mut exit: EventWriter<ZoneExitEvent>,
) {
let store = store.0.read().unwrap();
let conv = &coord.as_ref().0;
for (entity, tf, mut tracker) in &mut query {
let t = tf.translation();
let p = conv.to_internal([t.x as f64, t.z as f64, t.y as f64]);
let current = store.query_enu(p);
for &id in ¤t {
if !tracker.active.contains(&id) {
enter.write(ZoneEnterEvent { entity, zone_id: id });
}
}
for &id in &tracker.active {
if !current.contains(&id) {
exit.write(ZoneExitEvent { entity, zone_id: id });
}
}
tracker.active = current;
}
}
pub fn add_zone_to_store(
store: &SharedZoneStore,
entry: ZoneEntry,
conv: &dyn CoordSystem,
) {
store.0.write().unwrap().add_zone(entry.id, &entry.zone, conv);
}
pub fn insert_point(
octree: &SharedOctreeRes,
pos: [f64; 3],
threshold: usize,
) {
octree.0.write().unwrap().insert(pos, threshold);
}