Files
server/src/nodes/input/method.rs

234 lines
6.4 KiB
Rust

use super::{
input_method_client, InputData, InputDataTrait, InputDataType, InputHandler, InputMethodAspect,
InputMethodRefAspect, INPUT_HANDLER_REGISTRY, INPUT_METHOD_REF_ASPECT_ALIAS_INFO,
INPUT_METHOD_REGISTRY,
};
use crate::{
core::{client::Client, registry::Registry},
nodes::{
alias::{Alias, AliasList},
fields::{Field, FIELD_ALIAS_INFO},
spatial::Spatial,
Aspect, Node,
},
};
use color_eyre::eyre::Result;
use parking_lot::Mutex;
use stardust_xr::values::Datamap;
use std::sync::{Arc, Weak};
pub struct InputMethod {
pub spatial: Arc<Spatial>,
pub data: Mutex<InputDataType>,
pub datamap: Mutex<Datamap>,
handler_aliases: AliasList,
handler_field_aliases: AliasList,
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
pub internal_capture_requests: Registry<InputHandler>,
pub captures: Registry<InputHandler>,
}
impl InputMethod {
pub fn add_to(
node: &Arc<Node>,
data: InputDataType,
datamap: Datamap,
) -> Result<Arc<InputMethod>> {
let method = InputMethod {
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
data: Mutex::new(data),
datamap: Mutex::new(datamap),
handler_aliases: AliasList::default(),
handler_field_aliases: AliasList::default(),
handler_order: Mutex::new(Vec::new()),
internal_capture_requests: Registry::new(),
captures: Registry::new(),
};
<InputMethod as InputMethodRefAspect>::add_node_members(node);
<InputMethod as InputMethodAspect>::add_node_members(node);
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
method.handle_new_handler(&handler);
}
let method = INPUT_METHOD_REGISTRY.add(method);
node.add_aspect_raw(method.clone());
Ok(method)
}
pub fn distance(&self, to: &Field) -> f32 {
self.data.lock().distance(&self.spatial, to)
}
pub fn set_handler_order<'a>(&self, handlers: impl Iterator<Item = &'a Arc<InputHandler>>) {
*self.handler_order.lock() = handlers.map(Arc::downgrade).collect();
}
pub(super) fn make_alias(&self, handler: &InputHandler) {
let Some(method_node) = self.spatial.node() else {
return;
};
let Some(handler_node) = handler.spatial.node() else {
return;
};
let Some(client) = handler_node.get_client() else {
return;
};
let Ok(method_alias) = Alias::create(
&method_node,
&client,
INPUT_METHOD_REF_ASPECT_ALIAS_INFO.clone(),
Some(&handler.method_aliases),
) else {
return;
};
method_alias.set_enabled(false);
}
pub(super) fn handle_new_handler(&self, handler: &InputHandler) {
self.make_alias(handler);
let Some(method_node) = self.spatial.node() else {
return;
};
let Some(method_client) = method_node.get_client() else {
return;
};
let Some(handler_node) = handler.spatial.node() else {
return;
};
// Receiver itself
let Ok(handler_alias) = Alias::create(
&handler_node,
&method_client,
INPUT_METHOD_REF_ASPECT_ALIAS_INFO.clone(),
Some(&self.handler_aliases),
) else {
return;
};
let Some(handler_field_node) = handler.field.spatial.node() else {
return;
};
// Handler's field
let Ok(rx_field_alias) = Alias::create(
&handler_field_node,
&method_client,
FIELD_ALIAS_INFO.clone(),
Some(&self.handler_field_aliases),
) else {
return;
};
let _ = input_method_client::create_handler(&method_node, &handler_alias, &rx_field_alias);
}
pub(super) fn handle_drop_handler(&self, handler: &InputHandler) {
let Some(tx_node) = self.spatial.node() else {
return;
};
let Some(handler_alias) = self.handler_aliases.get_from_aspect(handler) else {
return;
};
let _ = input_method_client::destroy_handler(&tx_node, handler_alias.id);
self.handler_aliases.remove_aspect(handler);
self.handler_field_aliases
.remove_aspect(handler.field.as_ref());
}
pub(super) fn serialize(&self, alias_id: u64, handler: &Arc<InputHandler>) -> InputData {
let mut input = self.data.lock().clone();
input.transform(self, handler);
InputData {
id: alias_id,
input,
distance: self.distance(&handler.field),
datamap: self.datamap.lock().clone(),
order: self
.handler_order
.lock()
.iter()
.enumerate()
.find(|(_, h)| h.ptr_eq(&Arc::downgrade(handler)))
.unwrap()
.0 as u32,
captured: self.captures.get_valid_contents().contains(handler),
}
}
}
impl Aspect for InputMethod {
const NAME: &'static str = "InputMethod";
}
impl InputMethodRefAspect for InputMethod {
#[doc = "Have the input handler that this method reference came from capture the method for the next frame."]
fn request_capture(
node: Arc<Node>,
_calling_client: Arc<Client>,
handler: Arc<Node>,
) -> Result<()> {
let input_method = node.get_aspect::<InputMethod>()?;
let input_handler = handler.get_aspect::<InputHandler>()?;
input_method
.internal_capture_requests
.add_raw(&input_handler);
Ok(())
}
}
impl InputMethodAspect for InputMethod {
#[doc = "Set the spatial input component of this input method. You must keep the same input data type throughout the entire thing."]
fn set_input(
node: Arc<Node>,
_calling_client: Arc<Client>,
input: InputDataType,
) -> Result<()> {
let input_method = node.get_aspect::<InputMethod>()?;
*input_method.data.lock() = input;
Ok(())
}
#[doc = "Set the datmap of this input method"]
fn set_datamap(node: Arc<Node>, _calling_client: Arc<Client>, datamap: Datamap) -> Result<()> {
let input_method = node.get_aspect::<InputMethod>()?;
*input_method.datamap.lock() = datamap;
Ok(())
}
#[doc = "Manually set the order of handlers to propagate input to, or else let the server decide."]
fn set_handler_order(
node: Arc<Node>,
_calling_client: Arc<Client>,
handlers: Vec<Arc<Node>>,
) -> Result<()> {
let input_method = node.get_aspect::<InputMethod>()?;
let handlers = handlers
.into_iter()
.filter_map(|p| p.get_aspect::<InputHandler>().ok())
.map(|i| Arc::downgrade(&i))
.collect::<Vec<_>>();
*input_method.handler_order.lock() = handlers;
Ok(())
}
#[doc = "Set which handlers are captured."]
fn set_captures(
node: Arc<Node>,
_calling_client: Arc<Client>,
handlers: Vec<Arc<Node>>,
) -> Result<()> {
let input_method = node.get_aspect::<InputMethod>()?;
input_method.captures.clear();
for handler in handlers {
let Ok(handler) = handler.get_aspect::<InputHandler>() else {
continue;
};
input_method.captures.add_raw(&handler);
}
Ok(())
}
}
impl Drop for InputMethod {
fn drop(&mut self) {
INPUT_METHOD_REGISTRY.remove(self);
}
}