use bevy_ecs::{
change_detection::Mut,
prelude::{Commands, Entity, Query},
query::QueryEntityError,
system::SystemParam,
};
use crate::{AnyBufferKey, Gate, GateState, NotifyBufferUpdate};
#[derive(SystemParam)]
pub struct BufferGateAccess<'w, 's> {
query: Query<'w, 's, &'static GateState>,
}
impl<'w, 's> BufferGateAccess<'w, 's> {
pub fn get<'a>(
&'a self,
key: impl Into<AnyBufferKey>,
) -> Result<BufferGateView<'a>, QueryEntityError> {
let key: AnyBufferKey = key.into();
let session = key.session();
self.query
.get(key.id())
.map(|gate| BufferGateView { gate, session })
}
}
pub struct BufferGateView<'a> {
pub(crate) gate: &'a GateState,
pub(crate) session: Entity,
}
impl<'a> BufferGateView<'a> {
pub fn gate(&self) -> Gate {
self.gate
.map
.get(&self.session)
.copied()
.unwrap_or(Gate::Open)
}
}
#[derive(SystemParam)]
pub struct BufferGateAccessMut<'w, 's> {
query: Query<'w, 's, &'static mut GateState>,
commands: Commands<'w, 's>,
}
impl<'w, 's> BufferGateAccessMut<'w, 's> {
pub fn get<'a>(
&'a self,
key: impl Into<AnyBufferKey>,
) -> Result<BufferGateView<'a>, QueryEntityError> {
let key: AnyBufferKey = key.into();
let session = key.session();
self.query
.get(key.id())
.map(|gate| BufferGateView { gate, session })
}
pub fn get_mut<'a>(
&'a mut self,
key: impl Into<AnyBufferKey>,
) -> Result<BufferGateMut<'w, 's, 'a>, QueryEntityError> {
let key: AnyBufferKey = key.into();
let buffer = key.id();
let session = key.session();
let accessor = key.tag.accessor;
self.query
.get_mut(buffer)
.map(|gate| BufferGateMut::new(gate, buffer, session, accessor, &mut self.commands))
}
}
pub struct BufferGateMut<'w, 's, 'a> {
gate: Mut<'a, GateState>,
buffer: Entity,
session: Entity,
accessor: Option<Entity>,
commands: &'a mut Commands<'w, 's>,
modified: bool,
}
impl<'w, 's, 'a> BufferGateMut<'w, 's, 'a> {
pub fn allow_closed_loops(mut self) -> Self {
self.accessor = None;
self
}
pub fn get(&self) -> Gate {
self.gate
.map
.get(&self.session)
.copied()
.unwrap_or(Gate::Open)
}
pub fn open_gate(&mut self) {
if let Some(gate) = self.gate.map.get_mut(&self.session) {
if *gate != Gate::Open {
*gate = Gate::Open;
self.modified = true;
}
}
}
pub fn close_gate(&mut self) {
if let Some(gate) = self.gate.map.get_mut(&self.session) {
*gate = Gate::Closed;
}
}
pub fn gate_action(&mut self, action: Gate) {
match action {
Gate::Open => self.open_gate(),
Gate::Closed => self.close_gate(),
}
}
fn new(
gate: Mut<'a, GateState>,
buffer: Entity,
session: Entity,
accessor: Entity,
commands: &'a mut Commands<'w, 's>,
) -> Self {
Self {
gate,
buffer,
session,
accessor: Some(accessor),
commands,
modified: false,
}
}
}
impl<'w, 's, 'a> Drop for BufferGateMut<'w, 's, 'a> {
fn drop(&mut self) {
if self.modified {
self.commands.queue(NotifyBufferUpdate::new(
self.buffer,
self.session,
self.accessor,
));
}
}
}