Files
server/src/nodes/items/mod.rs
2024-12-31 22:39:31 +01:00

408 lines
11 KiB
Rust

// TODO: reimplement with bevy
// pub mod camera;
pub mod panel;
// use self::camera::CameraItem;
use self::panel::PanelItemTrait;
use super::alias::AliasList;
use super::fields::{Field, FIELD_ALIAS_INFO};
use super::spatial::Spatial;
use super::{Alias, Aspect, AspectIdentifier, Node};
use crate::core::client::Client;
use crate::core::error::Result;
use crate::core::registry::Registry;
use crate::ensure;
use crate::nodes::alias::AliasInfo;
use crate::nodes::spatial::Transform;
use crate::nodes::spatial::SPATIAL_ASPECT_ALIAS_INFO;
use parking_lot::Mutex;
use std::hash::Hash;
use std::sync::{Arc, Weak};
stardust_xr_server_codegen::codegen_item_protocol!();
fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) {
if item.captured_acceptor.lock().strong_count() > 0 {
release(item);
}
*item.captured_acceptor.lock() = Arc::downgrade(acceptor);
acceptor.handle_capture(item);
if let Some(ui) = item.type_info.ui.lock().upgrade() {
ui.handle_capture_item(item, acceptor);
}
}
fn release(item: &Item) {
let mut captured_acceptor = item.captured_acceptor.lock();
if let Some(acceptor) = captured_acceptor.upgrade().as_ref() {
*captured_acceptor = Weak::default();
acceptor.handle_release(item);
if let Some(ui) = item.type_info.ui.lock().upgrade() {
ui.handle_release_item(item, acceptor);
}
}
}
pub struct TypeInfo {
pub type_name: &'static str,
pub alias_info: AliasInfo,
pub ui_node_id: u64,
pub ui: Mutex<Weak<ItemUI>>,
pub items: Registry<Item>,
pub acceptors: Registry<ItemAcceptor>,
pub add_ui_aspect: fn(node: &Node),
pub add_acceptor_aspect: fn(node: &Node),
pub new_acceptor_fn: fn(node: &Node, acceptor: &Arc<Node>, acceptor_field: &Arc<Node>),
}
impl Hash for TypeInfo {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.type_name.hash(state);
}
}
impl PartialEq for TypeInfo {
fn eq(&self, other: &Self) -> bool {
self.type_name == other.type_name
}
}
impl Eq for TypeInfo {}
pub struct Item {
spatial: Arc<Spatial>,
type_info: &'static TypeInfo,
captured_acceptor: Mutex<Weak<ItemAcceptor>>,
pub specialization: ItemType,
}
impl Item {
pub fn add_to(
node: &Arc<Node>,
type_info: &'static TypeInfo,
specialization: ItemType,
) -> Arc<Self> {
let item = Item {
spatial: node.aspects.get::<Spatial>().unwrap(),
type_info,
captured_acceptor: Default::default(),
specialization,
};
let item = type_info.items.add(item);
if let Some(ui) = type_info.ui.lock().upgrade() {
ui.handle_create_item(&item);
}
node.add_aspect_raw(item.clone());
// if let Some(auto_acceptor) = node.get_client().and_then(|client| {
// client
// .state
// .as_ref()
// .and_then(|settings| settings.acceptors.get(type_info))
// .and_then(|acceptor| acceptor.upgrade())
// }) {
// capture(&item, &auto_acceptor);
// }
item
}
fn make_alias(&self, client: &Arc<Client>, alias_list: &AliasList) -> Result<Arc<Node>> {
Alias::create(
&self.spatial.node().unwrap(),
client,
self.type_info.alias_info.clone() + ITEM_ASPECT_ALIAS_INFO.clone(),
Some(alias_list),
)
}
}
impl AspectIdentifier for Item {
impl_aspect_for_item_aspect_id! {}
}
impl Aspect for Item {
impl_aspect_for_item_aspect! {}
}
impl ItemAspect for Item {
fn release(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
let item = node.get_aspect::<Item>()?;
release(&item);
Ok(())
}
}
impl Drop for Item {
fn drop(&mut self) {
self.type_info.items.remove(self);
release(self);
if let Some(ui) = self.type_info.ui.lock().upgrade() {
ui.handle_destroy_item(self);
}
}
}
pub enum ItemType {
// Camera(CameraItem),
Panel(Arc<dyn PanelItemTrait>),
}
impl ItemType {
fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>) {
match self {
// ItemType::Camera(c) => c.send_ui_item_created(node, item),
ItemType::Panel(p) => p.send_ui_item_created(node, item),
}
}
fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
match self {
// ItemType::Camera(c) => c.send_acceptor_item_created(node, item),
ItemType::Panel(p) => p.send_acceptor_item_created(node, item),
}
}
}
// impl Deref for ItemType {
// type Target = dyn ItemSpecialization;
// fn deref(&self) -> &Self::Target {
// match self {
// ItemType::Environment(item) => item,
// ItemType::Panel(item) => item.as_ref(),
// }
// }
// }
pub struct ItemUI {
node: Weak<Node>,
type_info: &'static TypeInfo,
item_aliases: AliasList,
acceptor_aliases: AliasList,
acceptor_field_aliases: AliasList,
}
impl ItemUI {
fn add_to(node: &Arc<Node>, type_info: &'static TypeInfo) -> Result<()> {
ensure!(
type_info.ui.lock().upgrade().is_none(),
"A UI is already active for this type of item"
);
let ui = Arc::new(ItemUI {
node: Arc::downgrade(node),
type_info,
item_aliases: AliasList::default(),
acceptor_aliases: AliasList::default(),
acceptor_field_aliases: AliasList::default(),
});
*type_info.ui.lock() = Arc::downgrade(&ui);
node.add_aspect_raw(ui.clone());
for item in type_info.items.get_valid_contents() {
ui.handle_create_item(&item);
}
for acceptor in type_info.acceptors.get_valid_contents() {
ui.handle_create_acceptor(&acceptor);
}
Ok(())
}
fn handle_create_item(&self, item: &Item) {
let Some(node) = self.node.upgrade() else {
return;
};
let Some(client) = node.get_client() else {
return;
};
let Ok(item_alias) = item.make_alias(&client, &self.item_aliases) else {
return;
};
item.specialization.send_ui_item_created(&node, &item_alias);
}
fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) {
let Some(item_alias) = self.item_aliases.get_from_aspect(item) else {
return;
};
let Some(acceptor_alias) = self.acceptor_aliases.get_from_aspect(acceptor) else {
return;
};
let _ = item_ui_client::capture_item(
&self.node.upgrade().unwrap(),
item_alias.id,
acceptor_alias.id,
);
}
fn handle_release_item(&self, item: &Item, acceptor: &ItemAcceptor) {
let Some(item_alias) = self.item_aliases.get_from_aspect(item) else {
return;
};
let Some(acceptor_alias) = self.acceptor_aliases.get_from_aspect(acceptor) else {
return;
};
let _ = item_ui_client::release_item(
&self.node.upgrade().unwrap(),
item_alias.id,
acceptor_alias.id,
);
}
fn handle_destroy_item(&self, item: &Item) {
let Some(item_alias) = self
.item_aliases
.get_from_original_node(item.spatial.node.clone())
else {
return;
};
let _ = item_ui_client::destroy_item(&self.node.upgrade().unwrap(), item_alias.id);
self.item_aliases.remove_aspect(item);
}
fn handle_create_acceptor(&self, acceptor: &ItemAcceptor) {
let Some(node) = self.node.upgrade() else {
return;
};
let Some(client) = node.get_client() else {
return;
};
let Some(acceptor_node) = acceptor.spatial.node() else {
return;
};
let Ok(acceptor_alias) = Alias::create(
&acceptor_node,
&client,
ITEM_ACCEPTOR_ASPECT_ALIAS_INFO.clone(),
Some(&self.acceptor_aliases),
) else {
return;
};
let Some(acceptor_field_node) = acceptor.field.spatial.node() else {
return;
};
let Ok(acceptor_field_alias) = Alias::create(
&acceptor_field_node,
&client,
FIELD_ALIAS_INFO.clone(),
Some(&self.acceptor_aliases),
) else {
return;
};
(acceptor.type_info.new_acceptor_fn)(&node, &acceptor_alias, &acceptor_field_alias);
}
fn handle_destroy_acceptor(&self, acceptor: &ItemAcceptor) {
let acceptor_alias = self.acceptor_aliases.get_from_aspect(acceptor).unwrap();
let _ = item_ui_client::destroy_acceptor(&self.node.upgrade().unwrap(), acceptor_alias.id);
self.acceptor_aliases
.remove_aspect(acceptor.spatial.as_ref());
self.acceptor_field_aliases
.remove_aspect(acceptor.field.as_ref());
}
}
impl AspectIdentifier for ItemUI {
impl_aspect_for_item_ui_aspect_id! {}
}
impl Aspect for ItemUI {
impl_aspect_for_item_ui_aspect! {}
}
impl Drop for ItemUI {
fn drop(&mut self) {
*self.type_info.ui.lock() = Weak::new();
}
}
pub struct ItemAcceptor {
spatial: Arc<Spatial>,
pub type_info: &'static TypeInfo,
field: Arc<Field>,
accepted_aliases: AliasList,
accepted_registry: Registry<Item>,
}
impl ItemAcceptor {
fn add_to(node: &Arc<Node>, type_info: &'static TypeInfo, field: Arc<Field>) {
let acceptor = type_info.acceptors.add(ItemAcceptor {
spatial: node.get_aspect::<Spatial>().unwrap(),
type_info,
field,
accepted_aliases: AliasList::default(),
accepted_registry: Registry::new(),
});
if let Some(ui) = type_info.ui.lock().upgrade() {
ui.handle_create_acceptor(&acceptor);
}
node.add_aspect_raw(acceptor.clone());
}
fn handle_capture(&self, item: &Arc<Item>) {
let Some(node) = self.spatial.node() else {
return;
};
let Some(client) = node.get_client() else {
return;
};
self.accepted_registry.add_raw(item);
let Ok(alias_node) = item.make_alias(&client, &self.accepted_aliases) else {
return;
};
item.specialization
.send_acceptor_item_created(&node, &alias_node);
}
fn handle_release(&self, item: &Item) {
self.accepted_registry.remove(item);
self.accepted_aliases.remove_aspect(item);
let Some(node) = self.spatial.node() else {
return;
};
let alias = self.accepted_aliases.get_from_aspect(item).unwrap();
let _ = item_acceptor_client::release_item(&node, alias.id);
}
}
impl AspectIdentifier for ItemAcceptor {
impl_aspect_for_item_acceptor_aspect_id! {}
}
impl Aspect for ItemAcceptor {
impl_aspect_for_item_acceptor_aspect! {}
}
impl ItemAcceptorAspect for ItemAcceptor {}
impl Drop for ItemAcceptor {
fn drop(&mut self) {
self.type_info.acceptors.remove(self);
for item in self.accepted_registry.get_valid_contents() {
release(&item);
}
if let Some(ui) = self.type_info.ui.lock().upgrade() {
ui.handle_destroy_acceptor(self);
}
}
}
pub fn register_item_ui_flex(
calling_client: Arc<Client>,
type_info: &'static TypeInfo,
) -> Result<()> {
let ui = Node::from_id(&calling_client, type_info.ui_node_id, true).add_to_scenegraph()?;
ItemUI::add_to(&ui, type_info)?;
(type_info.add_ui_aspect)(&ui);
Ok(())
}
fn create_item_acceptor_flex(
calling_client: Arc<Client>,
id: u64,
parent: Arc<Node>,
transform: Transform,
type_info: &'static TypeInfo,
field: Arc<Node>,
) -> Result<()> {
let space = parent.get_aspect::<Spatial>()?;
let field = field.get_aspect::<Field>()?;
let transform = transform.to_mat4(true, true, false);
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(&node, Some(space.clone()), transform, false);
ItemAcceptor::add_to(&node, type_info, field);
(type_info.add_acceptor_aspect)(&node);
Ok(())
}
fn acceptor_capture_item_flex(node: Arc<Node>, item: Arc<Node>) -> Result<()> {
let acceptor = node.get_aspect::<ItemAcceptor>()?;
let item = item.get_aspect::<Item>()?;
capture(&item, &acceptor);
Ok(())
}