feat: upgrade to numerical IDs

This commit is contained in:
Nova
2024-06-05 14:34:45 -04:00
parent 5f9d9d4714
commit 8d2aac12d6
36 changed files with 978 additions and 1169 deletions

View File

@@ -8,13 +8,13 @@ name = "task"
# type = "lldb"
# the program to run
program = "cargo"
program = "./target/debug/stardust-xr-server"
# the program arguments, e.g. args = ["arg1", "arg2"], optional
args = ["lrun", "--", "-f"]
# args = []
# current working directory, optional
# cwd = "${workspace}"
cwd = "${workspace}"
# enviroment variables, optional
# [configs.env]

100
Cargo.lock generated
View File

@@ -378,9 +378,9 @@ dependencies = [
[[package]]
name = "bytemuck_derive"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "369cfaf2a5bed5d8f8202073b2e093c9f508251de1551a0deb4253e4c7d80909"
checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b"
dependencies = [
"proc-macro2",
"quote",
@@ -1257,9 +1257,9 @@ checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]]
name = "itertools"
version = "0.10.5"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
@@ -1414,7 +1414,7 @@ dependencies = [
[[package]]
name = "macros"
version = "0.1.0"
source = "git+https://github.com/mvvvv/StereoKit-rust.git#348e8a458e0b329464fa292ec3635d3eaabd21d7"
source = "git+https://github.com/mvvvv/StereoKit-rust.git#e6d6858a24553e70bcb02e3b6e94f7603c663e3b"
[[package]]
name = "manifest-dir-macros"
@@ -1680,7 +1680,7 @@ version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 1.0.109",
@@ -1692,7 +1692,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.66",
@@ -1952,9 +1952,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "polling"
version = "3.7.0"
version = "3.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3"
checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1"
dependencies = [
"cfg-if",
"concurrent-queue",
@@ -1999,10 +1999,19 @@ dependencies = [
]
[[package]]
name = "proc-macro2"
version = "1.0.84"
name = "proc-macro-crate"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
dependencies = [
"toml_edit 0.21.1",
]
[[package]]
name = "proc-macro2"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
dependencies = [
"unicode-ident",
]
@@ -2385,6 +2394,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "slotmap"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
dependencies = [
"version_check",
]
[[package]]
name = "smallvec"
version = "1.13.2"
@@ -2483,7 +2501,7 @@ checksum = "2f2b15926089e5526bb2dd738a2eb0e59034356e06eb71e1cd912358c0e62c4d"
[[package]]
name = "stardust-xr"
version = "0.45.0"
source = "git+https://github.com/StardustXR/core.git?branch=dev#47208187ffdb00627fabbb3af2bd0a12a6208194"
source = "git+https://github.com/StardustXR/core.git?branch=dev#7ddbcb9be74df67efcde057f2b68ba8592507b13"
dependencies = [
"cluFlock",
"color-rs",
@@ -2503,10 +2521,11 @@ dependencies = [
[[package]]
name = "stardust-xr-schemas"
version = "1.5.3"
source = "git+https://github.com/StardustXR/core.git?branch=dev#47208187ffdb00627fabbb3af2bd0a12a6208194"
source = "git+https://github.com/StardustXR/core.git?branch=dev#7ddbcb9be74df67efcde057f2b68ba8592507b13"
dependencies = [
"flatbuffers",
"flexbuffers",
"fnv",
"kdl",
"manifest-dir-macros",
"serde",
@@ -2525,6 +2544,7 @@ dependencies = [
"ctrlc",
"directories",
"glam",
"global_counter",
"input-event-codes",
"lazy_static",
"libc",
@@ -2540,6 +2560,7 @@ dependencies = [
"send_wrapper",
"serde",
"serde_repr",
"slotmap",
"smithay",
"stardust-xr",
"stardust-xr-server-codegen",
@@ -2569,7 +2590,7 @@ dependencies = [
[[package]]
name = "stereokit-rust"
version = "0.1.0"
source = "git+https://github.com/mvvvv/StereoKit-rust.git#348e8a458e0b329464fa292ec3635d3eaabd21d7"
source = "git+https://github.com/mvvvv/StereoKit-rust.git#e6d6858a24553e70bcb02e3b6e94f7603c663e3b"
dependencies = [
"android_logger",
"bitflags 2.5.0",
@@ -2695,9 +2716,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.37.0"
version = "1.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
dependencies = [
"backtrace",
"bytes",
@@ -2725,9 +2746,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "2.2.0"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [
"proc-macro2",
"quote",
@@ -2790,6 +2811,17 @@ dependencies = [
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [
"indexmap 2.2.6",
"toml_datetime",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.22.13"
@@ -2800,7 +2832,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.8",
"winnow 0.6.9",
]
[[package]]
@@ -3095,9 +3127,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "wayland-backend"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40"
checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07"
dependencies = [
"cc",
"downcast-rs",
@@ -3109,9 +3141,9 @@ dependencies = [
[[package]]
name = "wayland-client"
version = "0.31.2"
version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f"
checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133"
dependencies = [
"bitflags 2.5.0",
"rustix",
@@ -3132,9 +3164,9 @@ dependencies = [
[[package]]
name = "wayland-cursor"
version = "0.31.1"
version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba"
checksum = "a206e8b2b53b1d3fcb9428fec72bc278ce539e2fa81fe2bfc1ab27703d5187b9"
dependencies = [
"rustix",
"wayland-client",
@@ -3196,9 +3228,9 @@ dependencies = [
[[package]]
name = "wayland-scanner"
version = "0.31.1"
version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565"
dependencies = [
"proc-macro2",
"quick-xml",
@@ -3207,9 +3239,9 @@ dependencies = [
[[package]]
name = "wayland-server"
version = "0.31.1"
version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e6e4d5c285bc24ba4ed2d5a4bd4febd5fd904451f465973225c8e99772fdb7"
checksum = "63e89118bd072ba6ce0f9c2c92fa41f72d1d78a138d2abc497a80a8264565559"
dependencies = [
"bitflags 2.5.0",
"downcast-rs",
@@ -3221,9 +3253,9 @@ dependencies = [
[[package]]
name = "wayland-sys"
version = "0.31.1"
version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af"
checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12"
dependencies = [
"dlib",
"log",
@@ -3577,9 +3609,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.6.8"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6"
dependencies = [
"memchr",
]

View File

@@ -70,6 +70,8 @@ nix = "0.29.0"
wayland-scanner = "0.31.1"
wayland-backend = "0.3.3"
toml = "0.8.10"
global_counter = "=0.2.2"
slotmap = "1.0.7"
[dependencies.smithay]
# git = "https://github.com/technobaboo/smithay.git"

View File

@@ -8,10 +8,10 @@ fn fold_tokens(a: TokenStream, b: TokenStream) -> TokenStream {
quote!(#a #b)
}
// #[proc_macro]
// pub fn codegen_root_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// codegen_protocol(ROOT_PROTOCOL)
// }
#[proc_macro]
pub fn codegen_root_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
codegen_protocol(ROOT_PROTOCOL)
}
#[proc_macro]
pub fn codegen_node_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
codegen_protocol(NODE_PROTOCOL)
@@ -58,18 +58,17 @@ fn codegen_protocol(protocol: &'static str) -> proc_macro::TokenStream {
let interface = protocol
.interface
.map(|p| {
let virtual_aspect_name = p.path[1..]
.split('/')
.map(ToString::to_string)
.reduce(|a, b| format!("{a}_{b}"))
.unwrap_or_default()
+ "_interface";
generate_aspect(&Aspect {
name: virtual_aspect_name,
let node_id = p.node_id;
let node_id = quote! {
const INTERFACE_NODE_ID: u64 = #node_id;
};
let aspect = generate_aspect(&Aspect {
name: "interface".to_string(),
description: protocol.description.clone(),
inherits: vec![],
members: p.members,
})
});
quote!(#node_id #aspect)
})
.unwrap_or_default();
let custom_enums = protocol
@@ -169,45 +168,6 @@ fn generate_custom_struct(custom_struct: &CustomStruct) -> TokenStream {
}
}
// fn generate_node(node: &Node) -> TokenStream {
// let node_name = Ident::new(&node.name, Span::call_site());
// let description = &node.description;
// let aspects = node
// .aspects
// .iter()
// .map(|a| {
// let aspect_name = Ident::new(&format!("{a}Aspect"), Span::call_site());
// quote!(impl #aspect_name for #node_name {})
// })
// .reduce(fold_tokens)
// .unwrap_or_default();
// quote! {
// #[doc = #description]
// #[derive(Debug)]
// pub struct #node_name (crate::node::Node);
// impl crate::node::NodeType for #node_name {
// fn node(&self) -> &crate::node::Node {
// &self.0
// }
// fn alias(&self) -> Self {
// #node_name(self.0.alias())
// }
// fn from_path(client: &std::sync::Arc<crate::client::Client>, path: String, destroyable: bool) -> Self {
// #node_name(crate::node::Node::from_path(client, path, destroyable))
// }
// }
// impl serde::Serialize for #node_name {
// fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
// let node_path = self.0.get_path().map_err(|e| serde::ser::Error::custom(e))?;
// serializer.serialize_str(&node_path)
// }
// }
// #aspects
// }
// }
fn generate_aspect(aspect: &Aspect) -> TokenStream {
let description = &aspect.description;
let (client_members, server_members) = aspect.members.iter().split(|m| m.side == Side::Server);
@@ -234,6 +194,30 @@ fn generate_aspect(aspect: &Aspect) -> TokenStream {
&format!("{}Aspect", &aspect.name.to_case(Case::Pascal)),
Span::call_site(),
);
let opcodes = aspect
.members
.iter()
.map(|m| {
let aspect_name = aspect.name.to_case(Case::ScreamingSnake);
let member_name = m.name.to_case(Case::ScreamingSnake);
let name_type = if m.side == Side::Client {
"CLIENT"
} else {
"SERVER"
};
let name = Ident::new(
&format!("{aspect_name}_{member_name}_{name_type}_OPCODE"),
Span::call_site(),
);
let opcode = m.opcode;
quote!(pub(crate) const #name: u64 = #opcode;)
})
.reduce(fold_tokens)
.unwrap_or_default();
let alias_info = generate_alias_info(aspect);
let server_side_members = server_members
.map(generate_member)
.reduce(fold_tokens)
@@ -259,11 +243,45 @@ fn generate_aspect(aspect: &Aspect) -> TokenStream {
#server_side_members
}
};
quote!(#client_side_members #server_side_members)
quote!(#opcodes #alias_info #client_side_members #server_side_members)
}
fn generate_alias_opcodes(aspect: &Aspect, side: Side, _type: MemberType) -> TokenStream {
aspect
.members
.iter()
.filter(|m| m.side == side)
.filter(|m| m._type == _type)
.map(|m| m.opcode)
.map(|o| quote!(#o))
.reduce(|a, b| quote!(#a, #b))
.unwrap_or_default()
}
fn generate_alias_info(aspect: &Aspect) -> TokenStream {
let aspect_alias_info_name = Ident::new(
&format!(
"{}_ASPECT_ALIAS_INFO",
aspect.name.to_case(Case::ScreamingSnake)
),
Span::call_site(),
);
let local_signals = generate_alias_opcodes(aspect, Side::Server, MemberType::Signal);
let local_methods = generate_alias_opcodes(aspect, Side::Server, MemberType::Method);
let remote_signals = generate_alias_opcodes(aspect, Side::Client, MemberType::Signal);
quote! {
lazy_static::lazy_static! {
pub static ref #aspect_alias_info_name: crate::nodes::alias::AliasInfo = crate::nodes::alias::AliasInfo {
server_signals: vec![#local_signals],
server_methods: vec![#local_methods],
client_signals: vec![#remote_signals],
};
}
}
}
fn generate_member(member: &Member) -> TokenStream {
let name_str = &member.name;
let id = member.opcode;
let name = Ident::new(&member.name.to_case(Case::Snake), Span::call_site());
let description = &member.description;
@@ -298,8 +316,8 @@ fn generate_member(member: &Member) -> TokenStream {
(Side::Client, MemberType::Method) => {
quote! {
#[doc = #description]
pub async fn #name(#argument_decls) -> color_eyre::eyre::Result<#return_type> {
_node.execute_remote_method(#name_str, &(#argument_uses)).await
pub async fn #name(#argument_decls) -> color_eyre::eyre::Result<(#return_type, Vec<std::os::fd::OwnedFd>)> {
_node.execute_remote_method_typed(#id, &(#argument_uses), vec![]).await
}
}
}
@@ -308,7 +326,7 @@ fn generate_member(member: &Member) -> TokenStream {
#[doc = #description]
pub fn #name(#argument_decls) -> color_eyre::eyre::Result<()> {
let serialized = stardust_xr::schemas::flex::serialize((#argument_uses))?;
_node.send_remote_signal(#name_str, serialized)
_node.send_remote_signal(#id, serialized)
}
}
}
@@ -319,23 +337,7 @@ fn generate_member(member: &Member) -> TokenStream {
}
}
(Side::Server, MemberType::Signal) => {
let prefix =
if let Some(ArgumentType::Node { _type, return_info }) = &member.return_type {
if let Some(return_info) = return_info {
let parent_name = Ident::new(
&(name_str.to_case(Case::ScreamingSnake) + "_PARENT_PATH"),
Span::call_site(),
);
let parent_path = &return_info.parent;
quote!(const #parent_name: &'static str = #parent_path;)
} else {
TokenStream::default()
}
} else {
TokenStream::default()
};
quote! {
#prefix
#[doc = #description]
fn #name(#argument_decls) -> color_eyre::eyre::Result<()>;
}
@@ -343,8 +345,8 @@ fn generate_member(member: &Member) -> TokenStream {
}
}
fn generate_handler(member: &Member) -> TokenStream {
let member_name = &member.name;
let member_name_ident = Ident::new(&member_name, Span::call_site());
let opcode = member.opcode;
let member_name_ident = Ident::new(&member.name, Span::call_site());
let argument_names = member
.arguments
@@ -375,13 +377,13 @@ fn generate_handler(member: &Member) -> TokenStream {
.unwrap_or_default();
match member._type {
MemberType::Signal => quote! {
node.add_local_signal(#member_name, |_node, _calling_client, _message| {
node.add_local_signal(#opcode, |_node, _calling_client, _message| {
#deserialize
Self::#member_name_ident(_node, _calling_client.clone(), #argument_uses)
});
},
MemberType::Method => quote! {
node.add_local_method(#member_name, |_node, _calling_client, _message, _method_response| {
node.add_local_method(#opcode, |_node, _calling_client, _message, _method_response| {
_method_response.wrap_async(async move {
#deserialize
Ok((Self::#member_name_ident(_node, _calling_client.clone(), #argument_uses).await?, Vec::new()))
@@ -396,7 +398,7 @@ fn generate_argument_name(argument: &Argument) -> TokenStream {
fn convert_deserializeable_argument_type(argument_type: &ArgumentType) -> ArgumentType {
match argument_type {
ArgumentType::Node { .. } => ArgumentType::String,
ArgumentType::Node { .. } => ArgumentType::NodeID,
ArgumentType::Vec(v) => {
ArgumentType::Vec(Box::new(convert_deserializeable_argument_type(v.as_ref())))
}
@@ -414,8 +416,8 @@ fn generate_argument_deserialize(
let name = Ident::new(&argument_name.to_case(Case::Snake), Span::call_site());
if let ArgumentType::Node { .. } = argument_type {
return match optional {
true => quote!(#name.map(|n| _calling_client.get_node(#argument_name, &n)?)),
false => quote!(_calling_client.get_node(#argument_name, &#name)?),
true => quote!(#name.map(|n| _calling_client.get_node(#argument_name, n)?)),
false => quote!(_calling_client.get_node(#argument_name, #name)?),
};
}
if optional {
@@ -445,10 +447,10 @@ fn generate_argument_serialize(
match argument_type {
ArgumentType::Node {
_type,
return_info: _,
return_id_parameter_name: _,
} => match optional {
true => quote!(#name.map(|n| n.get_path())),
false => quote!(#name.get_path()),
true => quote!(#name.map(|n| n.get_id())),
false => quote!(#name.get_id()),
},
ArgumentType::Color => quote!([#name.c.r, #name.c.g, #name.c.b, #name.a]),
ArgumentType::Vec(v) => {
@@ -483,6 +485,7 @@ fn argument_type_option_name(argument_type: &ArgumentType) -> String {
ArgumentType::Bytes => "Bytes".to_string(),
ArgumentType::Vec(v) => format!("{}Vector", argument_type_option_name(&v)),
ArgumentType::Map(m) => format!("{}Map", argument_type_option_name(&m)),
ArgumentType::NodeID => "Node ID".to_string(),
ArgumentType::Datamap => "Datamap".to_string(),
ArgumentType::ResourceID => "ResourceID".to_string(),
ArgumentType::Enum(e) => e.clone(),
@@ -544,6 +547,7 @@ fn generate_argument_type(
quote!(stardust_xr::values::Map<String, #t>)
}
}
ArgumentType::NodeID => quote!(u64),
ArgumentType::Datamap => {
if !owned {
quote!(&stardust_xr::values::Datamap)
@@ -576,7 +580,7 @@ fn generate_argument_type(
}
ArgumentType::Node {
_type,
return_info: _,
return_id_parameter_name: _,
} => {
if !owned {
quote!(&std::sync::Arc<crate::nodes::Node>)

View File

@@ -1,21 +1,23 @@
use super::{
client_state::{ClientState, CLIENT_STATES},
client_state::{ClientStateParsed, CLIENT_STATES},
destroy_queue,
scenegraph::Scenegraph,
};
use crate::{
core::{registry::OwnedRegistry, task},
nodes::{audio, data, drawable, fields, hmd, input, items, root::Root, spatial, Node},
nodes::{
audio, data, drawable, fields, hmd, input, items,
root::{ClientState, Root},
spatial, Node,
},
};
use color_eyre::eyre::{eyre, Result};
use global_counter::primitive::exact::CounterU32;
use lazy_static::lazy_static;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use stardust_xr::{
messenger::{self, MessageSenderHandle},
schemas::flex::serialize,
};
use stardust_xr::messenger::{self, MessageSenderHandle};
use std::{fmt::Debug, fs, iter::FromIterator, path::PathBuf, sync::Arc};
use tokio::{net::UnixStream, task::JoinHandle};
use tracing::info;
@@ -32,10 +34,11 @@ lazy_static! {
disconnect_status: OnceCell::new(),
message_sender_handle: None,
id_counter: CounterU32::new(0),
scenegraph: Default::default(),
root: OnceCell::new(),
base_resource_prefixes: Default::default(),
state: Arc::new(ClientState::default()),
state: OnceCell::default(),
});
}
@@ -47,7 +50,7 @@ pub fn get_env(pid: i32) -> Result<FxHashMap<String, String>, std::io::Error> {
.map(|(k, v)| (k.to_string(), v.to_string())),
))
}
pub fn state(env: &FxHashMap<String, String>) -> Option<Arc<ClientState>> {
pub fn state(env: &FxHashMap<String, String>) -> Option<Arc<ClientStateParsed>> {
let token = env.get("STARDUST_STARTUP_TOKEN")?;
CLIENT_STATES.lock().get(token).cloned()
}
@@ -60,11 +63,12 @@ pub struct Client {
flush_join_handle: OnceCell<JoinHandle<Result<()>>>,
disconnect_status: OnceCell<Result<()>>,
id_counter: CounterU32,
pub message_sender_handle: Option<MessageSenderHandle>,
pub scenegraph: Arc<Scenegraph>,
pub root: OnceCell<Arc<Root>>,
pub base_resource_prefixes: Mutex<Vec<PathBuf>>,
pub state: Arc<ClientState>,
pub state: OnceCell<ClientState>,
}
impl Client {
pub fn from_connection(connection: UnixStream) -> Result<Arc<Self>> {
@@ -84,7 +88,7 @@ impl Client {
let state = env
.as_ref()
.and_then(state)
.unwrap_or_else(|| Arc::new(ClientState::default()));
.unwrap_or_else(|| Arc::new(ClientStateParsed::default()));
let client = CLIENTS.add(Client {
pid,
@@ -95,14 +99,15 @@ impl Client {
flush_join_handle: OnceCell::new(),
disconnect_status: OnceCell::new(),
id_counter: CounterU32::new(256),
message_sender_handle: Some(messenger_tx.handle()),
scenegraph: scenegraph.clone(),
root: OnceCell::new(),
base_resource_prefixes: Default::default(),
state,
state: OnceCell::default(),
});
let _ = client.scenegraph.client.set(Arc::downgrade(&client));
let _ = client.root.set(Root::create(&client)?);
let _ = client.root.set(Root::create(&client, state.root)?);
hmd::make_alias(&client)?;
spatial::create_interface(&client)?;
fields::create_interface(&client)?;
@@ -113,12 +118,7 @@ impl Client {
items::camera::create_interface(&client)?;
items::panel::create_interface(&client)?;
client
.root
.get()
.unwrap()
.node
.send_remote_signal("restore_state", serialize(client.state.apply_to(&client))?)?;
let _ = client.state.set(state.apply_to(&client));
let pid_printable = pid
.map(|pid| pid.to_string())
@@ -191,15 +191,19 @@ impl Client {
let cwd_proc_path = format!("/proc/{pid}/cwd");
std::fs::read_link(cwd_proc_path).ok()
}
pub async fn save_state(&self) -> Option<ClientState> {
pub async fn save_state(&self) -> Option<ClientStateParsed> {
let internal = self.root.get()?.save_state().await.ok()?;
Some(ClientState::from_deserialized(self, internal))
Some(ClientStateParsed::from_deserialized(self, internal))
}
pub fn generate_id(&self) -> u64 {
self.id_counter.inc() as u64
}
#[inline]
pub fn get_node(&self, name: &'static str, path: &str) -> Result<Arc<Node>> {
pub fn get_node(&self, name: &'static str, id: u64) -> Result<Arc<Node>> {
self.scenegraph
.get_node(path)
.get_node(id)
.ok_or_else(|| eyre!("{} not found", name))
}

View File

@@ -1,5 +1,5 @@
use super::client::{get_env, Client};
use crate::nodes::{spatial::Spatial, Node};
use crate::nodes::{root::ClientState, spatial::Spatial, Node};
use glam::Mat4;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
@@ -11,7 +11,7 @@ use std::{
};
lazy_static::lazy_static! {
pub static ref CLIENT_STATES: Mutex<FxHashMap<String, Arc<ClientState>>> = Default::default();
pub static ref CLIENT_STATES: Mutex<FxHashMap<String, Arc<ClientStateParsed>>> = Default::default();
}
#[derive(Debug, Serialize, Deserialize)]
@@ -31,28 +31,27 @@ impl LaunchInfo {
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ClientState {
pub struct ClientStateParsed {
pub launch_info: Option<LaunchInfo>,
pub data: Vec<u8>,
pub root: Mat4,
pub spatial_anchors: FxHashMap<String, Mat4>,
}
impl ClientState {
pub fn from_deserialized(client: &Client, state: ClientStateInternal) -> Self {
ClientState {
impl ClientStateParsed {
pub fn from_deserialized(client: &Client, state: ClientState) -> Self {
ClientStateParsed {
launch_info: LaunchInfo::from_client(client),
data: state.data.unwrap_or_default(),
root: Self::spatial_transform(client, &state.root.unwrap_or_default())
.unwrap_or_default(),
root: Self::spatial_transform(client, state.root).unwrap_or_default(),
spatial_anchors: state
.spatial_anchors
.into_iter()
.filter_map(|(k, v)| Some((k, Self::spatial_transform(client, &v)?)))
.filter_map(|(k, v)| Some((k, Self::spatial_transform(client, v)?)))
.collect(),
}
}
fn spatial_transform(client: &Client, path: &str) -> Option<Mat4> {
let node = client.scenegraph.get_node(path)?;
fn spatial_transform(client: &Client, id: u64) -> Option<Mat4> {
let node = client.scenegraph.get_node(id)?;
let spatial = node.get_aspect::<Spatial>().ok()?;
Some(spatial.global_transform())
}
@@ -79,24 +78,20 @@ impl ClientState {
std::fs::write(state_file_path, toml::to_string(&self).unwrap()).unwrap();
}
pub fn apply_to(&self, client: &Arc<Client>) -> ClientStateInternal {
pub fn apply_to(&self, client: &Arc<Client>) -> ClientState {
if let Some(root) = client.root.get() {
root.set_transform(self.root)
}
ClientStateInternal {
ClientState {
data: Some(self.data.clone()),
root: Some("/".to_string()),
root: 0,
spatial_anchors: self
.spatial_anchors
.iter()
.map(|(k, v)| {
(k.clone(), {
let node = Node::create_parent_name(client, "/spatial/anchor", k, true)
.add_to_scenegraph()
.unwrap();
let node = Node::generate(client, true).add_to_scenegraph().unwrap();
Spatial::add_to(&node, None, *v, false);
k.clone()
})
(k.clone(), node.get_id())
})
.collect(),
}
@@ -112,7 +107,7 @@ impl ClientState {
Some(command)
}
}
impl Default for ClientState {
impl Default for ClientStateParsed {
fn default() -> Self {
Self {
launch_info: None,
@@ -122,10 +117,3 @@ impl Default for ClientState {
}
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct ClientStateInternal {
data: Option<Vec<u8>>,
root: Option<String>,
spatial_anchors: FxHashMap<String, String>,
}

View File

@@ -1,9 +1,9 @@
#[macro_export]
macro_rules! create_interface {
($iface:ident, $aspect:ident, $path:expr) => {
($iface:ident) => {
pub fn create_interface(client: &Arc<Client>) -> Result<()> {
let node = Node::create_path(client, $path, false);
<$iface as $aspect>::add_node_members(&node);
let node = Node::from_id(client, INTERFACE_NODE_ID, false);
<$iface as self::InterfaceAspect>::add_node_members(&node);
node.add_to_scenegraph()?;
Ok(())
}

View File

@@ -4,7 +4,6 @@ pub mod delta;
pub mod destroy_queue;
pub mod eventloop;
pub mod idl_utils;
pub mod node_collections;
pub mod registry;
pub mod resource;
pub mod scenegraph;

View File

@@ -1,83 +0,0 @@
use crate::nodes::Node;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use std::{
borrow::Borrow,
hash::Hash,
sync::{Arc, Weak},
};
// #[derive(Default)]
// pub struct LifeLinkedNodeList {
// nodes: Mutex<Vec<Weak<Node>>>,
// }
// impl LifeLinkedNodeList {
// pub fn add(&self, node: Weak<Node>) {
// self.nodes.lock().push(node);
// }
// pub fn clear(&self) {
// self.nodes
// .lock()
// .iter()
// .filter_map(|node| node.upgrade())
// .for_each(|node| {
// node.destroy();
// });
// self.nodes.lock().clear();
// }
// }
// impl Drop for LifeLinkedNodeList {
// fn drop(&mut self) {
// self.clear();
// }
// }
#[derive(Default, Debug)]
pub struct LifeLinkedNodeMap<K: Hash + Eq> {
nodes: Mutex<FxHashMap<K, Weak<Node>>>,
}
#[allow(dead_code)]
impl<K: Hash + Eq> LifeLinkedNodeMap<K> {
pub fn add(&self, key: K, node: &Arc<Node>) {
self.nodes.lock().insert(key, Arc::downgrade(node));
}
pub fn get<Q>(&self, key: &Q) -> Option<Arc<Node>>
where
Q: ?Sized,
K: Borrow<Q>,
Q: Hash + Eq,
{
self.nodes.lock().get(key).and_then(|n| n.upgrade())
}
pub fn nodes(&self) -> Vec<Arc<Node>> {
self.nodes
.lock()
.values()
.filter_map(|v| v.upgrade())
.collect()
}
pub fn remove<Q>(&self, key: &Q) -> Option<Arc<Node>>
where
Q: ?Sized,
K: Borrow<Q>,
Q: Hash + Eq,
{
self.nodes.lock().remove(key).and_then(|n| n.upgrade())
}
pub fn clear(&self) {
let mut nodes = self.nodes.lock();
nodes
.values()
.filter_map(|node| node.upgrade())
.for_each(|node| {
node.destroy();
});
nodes.clear();
}
}
impl<K: Hash + Eq> Drop for LifeLinkedNodeMap<K> {
fn drop(&mut self) {
self.clear();
}
}

View File

@@ -33,12 +33,38 @@ impl<T: Send + Sync + ?Sized> Registry<T> {
self.lock()
.contains_key(&(ptr::addr_of!(*t) as *const () as usize))
}
pub fn get_changes(old: &Registry<T>, new: &Registry<T>) -> (Vec<Arc<T>>, Vec<Arc<T>>) {
let old = old.lock();
let new = new.lock();
let mut added = Vec::new();
let mut removed = Vec::new();
for (id, entry) in new.iter() {
if let Some(entry) = entry.upgrade() {
if !old.contains_key(id) {
added.push(entry);
}
}
}
for (id, entry) in old.iter() {
if let Some(entry) = entry.upgrade() {
if !new.contains_key(id) {
removed.push(entry);
}
}
}
(added, removed)
}
pub fn get_valid_contents(&self) -> Vec<Arc<T>> {
self.lock()
.iter()
.filter_map(|pair| pair.1.upgrade())
.collect()
}
pub fn set(&self, other: &Registry<T>) {
*self.lock() = other.lock().clone();
}
pub fn take_valid_contents(&self) -> Vec<Arc<T>> {
self.0
.lock()
@@ -48,6 +74,14 @@ impl<T: Send + Sync + ?Sized> Registry<T> {
.filter_map(|pair| pair.1.upgrade())
.collect()
}
pub fn retain<F: Fn(&T) -> bool>(&self, f: F) {
self.lock().retain(|_, v| {
let Some(v) = v.upgrade() else {
return true;
};
(f)(&v)
})
}
pub fn remove(&self, t: &T) {
self.lock()
.remove(&(ptr::addr_of!(*t) as *const () as usize));

View File

@@ -19,7 +19,7 @@ use tracing::{debug, debug_span};
#[derive(Default)]
pub struct Scenegraph {
pub(super) client: OnceCell<Weak<Client>>,
nodes: Mutex<FxHashMap<String, Arc<Node>>>,
nodes: Mutex<FxHashMap<u64, Arc<Node>>>,
}
impl Scenegraph {
@@ -34,12 +34,11 @@ impl Scenegraph {
}
pub fn add_node_raw(&self, node: Arc<Node>) {
debug!(node = ?&*node, "Add node");
let path = node.get_path().to_string();
self.nodes.lock().insert(path, node);
self.nodes.lock().insert(node.get_id(), node);
}
pub fn get_node(&self, path: &str) -> Option<Arc<Node>> {
let mut node = self.nodes.lock().get(path)?.clone();
pub fn get_node(&self, node: u64) -> Option<Arc<Node>> {
let mut node = self.nodes.lock().get(&node)?.clone();
while let Ok(alias) = node.get_aspect::<Alias>() {
if alias.enabled.load(Ordering::Acquire) {
node = alias.original.upgrade()?;
@@ -50,9 +49,9 @@ impl Scenegraph {
Some(node)
}
pub fn remove_node(&self, path: &str) -> Option<Arc<Node>> {
debug!(path, "Remove node");
self.nodes.lock().remove(path)
pub fn remove_node(&self, node: u64) -> Option<Arc<Node>> {
debug!(node, "Remove node");
self.nodes.lock().remove(&node)
}
}
@@ -94,16 +93,16 @@ fn map_method_return<T: Serialize>(
impl scenegraph::Scenegraph for Scenegraph {
fn send_signal(
&self,
path: &str,
method: &str,
node: u64,
method: u64,
data: &[u8],
fds: Vec<OwnedFd>,
) -> Result<(), ScenegraphError> {
let Some(client) = self.get_client() else {
return Err(ScenegraphError::SignalNotFound);
};
debug_span!("Handle signal", path, method).in_scope(|| {
self.get_node(path)
debug_span!("Handle signal", node, method).in_scope(|| {
self.get_node(node)
.ok_or(ScenegraphError::NodeNotFound)?
.send_local_signal(
client,
@@ -117,8 +116,8 @@ impl scenegraph::Scenegraph for Scenegraph {
}
fn execute_method(
&self,
path: &str,
method: &str,
node: u64,
method: u64,
data: &[u8],
fds: Vec<OwnedFd>,
response: oneshot::Sender<Result<(Vec<u8>, Vec<OwnedFd>), ScenegraphError>>,
@@ -127,8 +126,8 @@ impl scenegraph::Scenegraph for Scenegraph {
let _ = response.send(Err(ScenegraphError::MethodNotFound));
return;
};
debug!(path, method, "Handle method");
let Some(node) = self.get_node(path) else {
debug!(node, method, "Handle method");
let Some(node) = self.get_node(node) else {
let _ = response.send(Err(ScenegraphError::NodeNotFound));
return;
};

View File

@@ -17,7 +17,7 @@ use crate::wayland::X_DISPLAY;
use self::core::eventloop::EventLoop;
use clap::Parser;
use core::client_state::ClientState;
use core::client_state::ClientStateParsed;
use directories::ProjectDirs;
use once_cell::sync::OnceCell;
use stardust_xr::server;
@@ -364,8 +364,8 @@ fn restore_session(
};
clients
.filter_map(Result::ok)
.filter_map(|c| ClientState::from_file(&c.path()))
.filter_map(ClientState::launch_command)
.filter_map(|c| ClientStateParsed::from_file(&c.path()))
.filter_map(ClientStateParsed::launch_command)
.filter_map(|startup_command| {
run_client(
startup_command,

View File

@@ -1,17 +1,28 @@
use super::{Aspect, Node};
use crate::core::client::Client;
use color_eyre::eyre::{ensure, Result};
use crate::core::{client::Client, registry::Registry};
use color_eyre::eyre::Result;
use portable_atomic::AtomicBool;
use std::sync::{Arc, Weak};
use std::{
ops::Add,
sync::{Arc, Weak},
};
#[derive(Debug, Default, Clone)]
pub struct AliasInfo {
pub(super) server_signals: Vec<&'static str>,
pub(super) server_methods: Vec<&'static str>,
pub(super) client_signals: Vec<&'static str>,
pub(super) server_signals: Vec<u64>,
pub(super) server_methods: Vec<u64>,
pub(super) client_signals: Vec<u64>,
}
impl Add for AliasInfo {
type Output = AliasInfo;
fn add(mut self, mut rhs: Self) -> Self::Output {
self.server_signals.append(&mut rhs.server_signals);
self.server_methods.append(&mut rhs.server_methods);
self.client_signals.append(&mut rhs.client_signals);
self
}
}
#[allow(dead_code)]
pub struct Alias {
pub enabled: Arc<AtomicBool>,
pub(super) node: Weak<Node>,
@@ -21,32 +32,86 @@ pub struct Alias {
}
impl Alias {
pub fn create(
client: &Arc<Client>,
parent: &str,
name: &str,
original: &Arc<Node>,
client: &Arc<Client>,
info: AliasInfo,
list: Option<&AliasList>,
) -> Result<Arc<Node>> {
ensure!(
client
.scenegraph
.get_node(&(parent.to_string() + "/" + name))
.is_none(),
"Node already exists"
);
let node = Node::generate(client, true).add_to_scenegraph()?;
Self::add_to(&node, original, info)?;
if let Some(list) = list {
list.add(&node);
}
Ok(node)
}
pub fn create_with_id(
original: &Arc<Node>,
client: &Arc<Client>,
new_id: u64,
info: AliasInfo,
list: Option<&AliasList>,
) -> Result<Arc<Node>> {
let node = Node::from_id(client, new_id, true).add_to_scenegraph()?;
Self::add_to(&node, original, info)?;
if let Some(list) = list {
list.add(&node);
}
Ok(node)
}
let node = Node::create_parent_name(client, parent, name, true).add_to_scenegraph()?;
fn add_to(new_node: &Arc<Node>, original: &Arc<Node>, info: AliasInfo) -> Result<()> {
let alias = Alias {
enabled: Arc::new(AtomicBool::new(true)),
node: Arc::downgrade(&node),
node: Arc::downgrade(&new_node),
original: Arc::downgrade(original),
info,
};
let alias = original.aliases.add(alias);
node.add_aspect_raw(alias);
Ok(node)
new_node.add_aspect_raw(alias);
Ok(())
}
}
impl Aspect for Alias {
const NAME: &'static str = "Alias";
}
pub fn get_original(node: Arc<Node>) -> Option<Arc<Node>> {
let Ok(alias) = node.get_aspect::<Alias>() else {
return Some(node);
};
get_original(alias.original.upgrade()?)
}
#[derive(Debug, Default, Clone)]
pub struct AliasList(Registry<Node>);
impl AliasList {
fn add(&self, node: &Arc<Node>) {
self.0.add_raw(node);
}
pub fn get<A: Aspect>(&self, aspect: &A) -> Option<Arc<Node>> {
self.0.get_valid_contents().into_iter().find(|node| {
let Ok(aspect2) = node.get_aspect::<A>() else {
return false;
};
Arc::as_ptr(&aspect2) != (aspect as *const A)
})
}
pub fn get_aliases(&self) -> Vec<Arc<Node>> {
self.0.get_valid_contents()
}
pub fn remove_aspect<A: Aspect>(&self, aspect: &A) {
self.0.retain(|node| {
let Ok(aspect2) = node.get_aspect::<A>() else {
return false;
};
Arc::as_ptr(&aspect2) != (aspect as *const A)
})
}
}
impl Drop for AliasList {
fn drop(&mut self) {
for node in self.0.take_valid_contents() {
node.destroy();
}
}
}

View File

@@ -101,20 +101,19 @@ pub fn update() {
}
}
create_interface!(AudioInterface, AudioInterfaceAspect, "/audio");
create_interface!(AudioInterface);
struct AudioInterface;
impl AudioInterfaceAspect for AudioInterface {
impl InterfaceAspect for AudioInterface {
#[doc = "Create a sound node. WAV and MP3 are supported."]
fn create_sound(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
resource: ResourceID,
) -> Result<()> {
let node =
Node::create_parent_name(&calling_client, Self::CREATE_SOUND_PARENT_PATH, &name, true);
let node = Node::from_id(&calling_client, id, true);
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);
let node = node.add_to_scenegraph()?;

View File

@@ -1,24 +1,22 @@
use super::alias::AliasInfo;
use super::alias::AliasList;
use super::fields::Field;
use super::spatial::{parse_transform, Spatial};
use super::{Alias, Aspect, Node};
use crate::core::client::Client;
use crate::core::node_collections::LifeLinkedNodeMap;
use crate::core::registry::Registry;
use crate::create_interface;
use crate::nodes::fields::FIELD_ALIAS_INFO;
use crate::nodes::spatial::Transform;
use color_eyre::eyre::{bail, ensure, eyre, Result};
use lazy_static::lazy_static;
use nanoid::nanoid;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use slotmap::{DefaultKey, Key, KeyData, SlotMap};
use stardust_xr::schemas::flex::flexbuffers;
use stardust_xr::values::Datamap;
use std::sync::{Arc, Weak};
lazy_static! {
pub static ref KEYMAPS: Mutex<FxHashMap<String, String>> = Mutex::new(FxHashMap::default());
pub static ref KEYMAPS: Mutex<SlotMap<DefaultKey, String>> = Mutex::new(SlotMap::default());
}
static PULSE_SENDER_REGISTRY: Registry<PulseSender> = Registry::new();
@@ -58,14 +56,16 @@ stardust_xr_server_codegen::codegen_data_protocol!();
pub struct PulseSender {
node: Weak<Node>,
pub mask: Datamap,
aliases: LifeLinkedNodeMap<String>,
aliases: AliasList,
field_aliases: AliasList,
}
impl PulseSender {
pub fn add_to(node: &Arc<Node>, mask: Datamap) -> Result<Arc<PulseSender>> {
let sender = PulseSender {
node: Arc::downgrade(node),
mask,
aliases: LifeLinkedNodeMap::default(),
aliases: AliasList::default(),
field_aliases: AliasList::default(),
};
// <PulseSender as PulseSenderAspect>::add_node_members(node);
@@ -91,44 +91,41 @@ impl PulseSender {
};
// Receiver itself
let Ok(rx_alias) = Alias::create(
&tx_client,
tx_node.get_path(),
receiver.uid.as_str(),
&rx_node,
AliasInfo {
server_methods: vec!["send_data"],
..Default::default()
},
&tx_client,
PULSE_RECEIVER_ASPECT_ALIAS_INFO.clone(),
Some(&self.aliases),
) else {
return;
};
self.aliases.add(receiver.uid.clone(), &rx_alias);
// Receiver's field
let Ok(rx_field_alias) = Alias::create(
&rx_node
.get_aspect::<PulseReceiver>()
.unwrap()
.field
.spatial_ref()
.node()
.unwrap(),
&tx_client,
rx_alias.get_path(),
"field",
&rx_node.get_aspect::<PulseReceiver>().unwrap().field_node,
FIELD_ALIAS_INFO.clone(),
Some(&self.aliases),
) else {
return;
};
self.aliases
.add(receiver.uid.clone() + "-field", &rx_field_alias);
let _ =
pulse_sender_client::new_receiver(&tx_node, &receiver.uid, &rx_alias, &rx_field_alias);
let _ = pulse_sender_client::new_receiver(&tx_node, &rx_alias, &rx_field_alias);
}
fn handle_drop_receiver(&self, receiver: &PulseReceiver) {
let uid = receiver.uid.as_str();
self.aliases.remove(uid);
self.aliases.remove(&(uid.to_string() + "-field"));
let id = receiver.node.upgrade().unwrap().get_id();
self.aliases.remove_aspect(receiver);
self.field_aliases.remove_aspect(receiver.field.as_ref());
let Some(tx_node) = self.node.upgrade() else {
return;
};
let _ = pulse_sender_client::drop_receiver(&tx_node, uid);
let _ = pulse_sender_client::drop_receiver(&tx_node, id);
}
}
impl Aspect for PulseSender {
@@ -142,21 +139,19 @@ impl Drop for PulseSender {
}
pub struct PulseReceiver {
uid: String,
pub node: Weak<Node>,
pub field_node: Arc<Node>,
pub field: Arc<Field>,
pub mask: Datamap,
}
impl PulseReceiver {
pub fn add_to(
node: &Arc<Node>,
field_node: Arc<Node>,
field: Arc<Field>,
mask: Datamap,
) -> Result<Arc<PulseReceiver>> {
let receiver = PulseReceiver {
uid: nanoid!(),
node: Arc::downgrade(node),
field_node,
field,
mask,
};
let receiver = PULSE_RECEIVER_REGISTRY.add(receiver);
@@ -186,7 +181,7 @@ impl PulseReceiverAspect for PulseReceiver {
"Message ({data:?}) does not contain the same keys as the receiver's mask ({:?})",
this_receiver.mask
);
pulse_receiver_client::data(&node, &sender.uid, &data)?;
pulse_receiver_client::data(&node, &sender, &data)?;
Ok(())
}
}
@@ -199,24 +194,19 @@ impl Drop for PulseReceiver {
}
}
create_interface!(DataInterface, DataInterfaceAspect, "/data");
create_interface!(DataInterface);
struct DataInterface;
impl DataInterfaceAspect for DataInterface {
impl InterfaceAspect for DataInterface {
fn create_pulse_sender(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
mask: Datamap,
) -> Result<()> {
get_mask(&mask)?;
let node = Node::create_parent_name(
&calling_client,
Self::CREATE_PULSE_SENDER_PARENT_PATH,
&name,
true,
);
let node = Node::from_id(&calling_client, id, true);
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, false);
@@ -229,22 +219,17 @@ impl DataInterfaceAspect for DataInterface {
fn create_pulse_receiver(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
field: Arc<Node>,
mask: Datamap,
) -> Result<()> {
get_mask(&mask)?;
let node = Node::create_parent_name(
&calling_client,
Self::CREATE_PULSE_RECEIVER_PARENT_PATH,
&name,
true,
);
let node = Node::from_id(&calling_client, id, true);
let parent = parent.get_aspect::<Spatial>()?;
let transform = parse_transform(transform, true, true, false);
let _ = field.get_aspect::<Field>()?;
let field = field.get_aspect::<Field>()?;
let node = node.add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
@@ -256,7 +241,7 @@ impl DataInterfaceAspect for DataInterface {
_node: Arc<Node>,
_calling_client: Arc<Client>,
keymap: String,
) -> Result<String> {
) -> Result<u64> {
let mut keymaps = KEYMAPS.lock();
if let Some(found_keymap_id) = keymaps
.iter()
@@ -264,22 +249,20 @@ impl DataInterfaceAspect for DataInterface {
.map(|(k, _v)| k)
.last()
{
return Ok(found_keymap_id.clone());
return Ok(found_keymap_id.data().as_ffi());
}
let generated_id = nanoid!();
keymaps.insert(generated_id.clone(), keymap);
Ok(generated_id)
let key = keymaps.insert(keymap);
Ok(key.data().as_ffi())
}
async fn get_keymap(
_node: Arc<Node>,
_calling_client: Arc<Client>,
keymap_id: String,
keymap_id: u64,
) -> Result<String> {
let keymaps = KEYMAPS.lock();
let Some(keymap) = keymaps.get(&keymap_id) else {
let Some(keymap) = keymaps.get(KeyData::from_ffi(keymap_id).into()) else {
bail!("Could not find keymap. Try registering it")
};

View File

@@ -40,10 +40,10 @@ static QUEUED_SKYLIGHT: Mutex<Option<PathBuf>> = Mutex::new(None);
static QUEUED_SKYTEX: Mutex<Option<PathBuf>> = Mutex::new(None);
stardust_xr_server_codegen::codegen_drawable_protocol!();
create_interface!(DrawableInterface, DrawableInterfaceAspect, "/drawable");
create_interface!(DrawableInterface);
pub struct DrawableInterface;
impl DrawableInterfaceAspect for DrawableInterface {
impl InterfaceAspect for DrawableInterface {
fn set_sky_tex(_node: Arc<Node>, calling_client: Arc<Client>, tex: ResourceID) -> Result<()> {
let resource_path = get_resource_file(&tex, &calling_client, &[OsStr::new("hdr")])
.ok_or(eyre::eyre!("Could not find resource"))?;
@@ -65,13 +65,12 @@ impl DrawableInterfaceAspect for DrawableInterface {
fn create_lines(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
lines: Vec<Line>,
) -> Result<()> {
let node =
Node::create_parent_name(&calling_client, Self::CREATE_LINES_PARENT_PATH, &name, true);
let node = Node::from_id(&calling_client, id, true);
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);
@@ -84,13 +83,12 @@ impl DrawableInterfaceAspect for DrawableInterface {
fn load_model(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
model: ResourceID,
) -> Result<()> {
let node =
Node::create_parent_name(&calling_client, Self::LOAD_MODEL_PARENT_PATH, &name, true);
let node = Node::from_id(&calling_client, id, true);
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);
let node = node.add_to_scenegraph()?;
@@ -102,14 +100,13 @@ impl DrawableInterfaceAspect for DrawableInterface {
fn create_text(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
text: String,
style: TextStyle,
) -> Result<()> {
let node =
Node::create_parent_name(&calling_client, Self::CREATE_TEXT_PARENT_PATH, &name, true);
let node = Node::from_id(&calling_client, id, true);
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);

View File

@@ -1,11 +1,10 @@
use super::{MaterialParameter, ModelAspect, ModelPartAspect, Node};
use crate::core::client::Client;
use crate::core::node_collections::LifeLinkedNodeMap;
use crate::core::registry::Registry;
use crate::core::resource::get_resource_file;
use crate::nodes::alias::{Alias, AliasList};
use crate::nodes::spatial::Spatial;
use crate::nodes::Aspect;
use color_eyre::eyre::{eyre, Result};
use crate::nodes::{Aspect, Node};
use color_eyre::eyre::{bail, eyre, Result};
use glam::{Mat4, Vec2, Vec3};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
@@ -19,9 +18,10 @@ use stereokit_rust::sk::MainThreadToken;
use stereokit_rust::{material::Material, model::Model as SKModel, tex::Tex, util::Color128};
use std::ffi::OsStr;
use std::path::PathBuf;
use std::sync::{Arc, Weak};
use super::{MaterialParameter, ModelAspect, ModelPartAspect, MODEL_PART_ASPECT_ALIAS_INFO};
static MODEL_REGISTRY: Registry<Model> = Registry::new();
static HOLDOUT_MATERIAL: OnceCell<Arc<SendWrapper<Material>>> = OnceCell::new();
@@ -69,11 +69,12 @@ impl MaterialParameter {
pub struct ModelPart {
id: i32,
path: PathBuf,
path: String,
space: Arc<Spatial>,
model: Weak<Model>,
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
pending_material_replacement: Mutex<Option<Arc<SendWrapper<Material>>>>,
aliases: AliasList,
}
impl ModelPart {
fn create_for_model(model: &Arc<Model>, sk_model: &SKModel) {
@@ -91,26 +92,21 @@ impl ModelPart {
}
fn create(model: &Arc<Model>, part: &stereokit_rust::model::ModelNode) -> Option<Arc<Self>> {
let parent_node = part
let mut parts = model.parts.lock();
let parent_part = part
.get_parent()
.and_then(|part| model.parts.get(part.get_id()));
let parent_part = parent_node
.as_ref()
.and_then(|node| node.get_aspect::<ModelPart>().ok());
.and_then(|part| parts.iter().find(|p| p.id == *part.get_id()));
let stardust_model_part = model.space.node()?;
let client = stardust_model_part.get_client()?;
let mut part_path = parent_part.map(|n| n.path.clone()).unwrap_or_default();
part_path.push(part.get_name().unwrap());
let mut part_path = parent_part
.map(|n| n.path.clone() + "/")
.unwrap_or_default();
part_path += part.get_name().unwrap();
let node = client.scenegraph.add_node(Node::create_parent_name(
&client,
stardust_model_part.get_path(),
part_path.to_str()?,
false,
));
let spatial_parent = parent_node
.and_then(|n| n.get_aspect::<Spatial>().ok())
let node = client.scenegraph.add_node(Node::generate(&client, false));
let spatial_parent = parent_part
.map(|n| n.space.clone())
.unwrap_or_else(|| model.space.clone());
let local_transform = unsafe { part.get_local_transform().m };
@@ -121,11 +117,7 @@ impl ModelPart {
false,
);
let _ = node
.get_aspect::<Spatial>()
.unwrap()
.bounding_box_calc
.set(|node| {
let _ = space.bounding_box_calc.set(|node| {
let Ok(model_part) = node.get_aspect::<ModelPart>() else {
return Bounds::default();
};
@@ -135,8 +127,8 @@ impl ModelPart {
let Some(sk_model) = model.sk_model.get() else {
return Bounds::default();
};
let nodes = sk_model.get_nodes();
let Some(model_node) = nodes.get_index(model_part.id) else {
let model_nodes = sk_model.get_nodes();
let Some(model_node) = model_nodes.get_index(model_part.id) else {
return Bounds::default();
};
let Some(sk_mesh) = model_node.get_mesh() else {
@@ -152,10 +144,11 @@ impl ModelPart {
model: Arc::downgrade(model),
pending_material_parameters: Mutex::new(FxHashMap::default()),
pending_material_replacement: Mutex::new(None),
aliases: AliasList::default(),
});
<ModelPart as ModelPartAspect>::add_node_members(&node);
node.add_aspect_raw(model_part.clone());
model.parts.add(*part.get_id(), &node);
parts.push(model_part.clone());
Some(model_part)
}
@@ -255,9 +248,8 @@ pub struct Model {
space: Arc<Spatial>,
_resource_id: ResourceID,
sk_model: OnceCell<SKModel>,
parts: LifeLinkedNodeMap<i32>,
parts: Mutex<Vec<Arc<ModelPart>>>,
}
impl Model {
pub fn add_to(node: &Arc<Node>, resource_id: ResourceID) -> Result<Arc<Model>> {
let pending_model_path = get_resource_file(
@@ -272,8 +264,9 @@ impl Model {
space: node.get_aspect::<Spatial>().unwrap().clone(),
_resource_id: resource_id,
sk_model: OnceCell::new(),
parts: LifeLinkedNodeMap::default(),
parts: Mutex::new(Vec::default()),
});
<Model as ModelAspect>::add_node_members(node);
MODEL_REGISTRY.add_raw(&model);
// technically doing this in anything but the main thread isn't a good idea but dangit we need those model nodes ASAP
@@ -291,11 +284,11 @@ impl Model {
let Some(sk_model) = self.sk_model.get() else {
return;
};
for model_node_node in self.parts.nodes() {
if let Ok(model_node) = model_node_node.get_aspect::<ModelPart>() {
let parts = self.parts.lock();
for model_node in &*parts {
model_node.update();
};
}
drop(parts);
if self.enabled.load(Ordering::Relaxed) {
sk_model.draw(token, self.space.global_transform(), None, None);
@@ -308,12 +301,32 @@ unsafe impl Sync for Model {}
impl Aspect for Model {
const NAME: &'static str = "Model";
}
impl ModelAspect for Model {}
impl ModelAspect for Model {
#[doc = "Bind a model part to the node with the ID input."]
fn bind_model_part(
node: Arc<Node>,
calling_client: Arc<Client>,
id: u64,
part_path: String,
) -> color_eyre::eyre::Result<()> {
let model = node.get_aspect::<Model>()?;
let parts = model.parts.lock();
let Some(part) = parts.iter().find(|p| p.path == part_path) else {
let paths = parts.iter().map(|p| &p.path).collect::<Vec<_>>();
bail!("Couldn't find model part at path {part_path}, all available paths: {paths:?}",)
};
Alias::create_with_id(
&part.space.node().unwrap(),
&calling_client,
id,
MODEL_PART_ASPECT_ALIAS_INFO.clone(),
Some(&part.aliases),
)?;
Ok(())
}
}
impl Drop for Model {
fn drop(&mut self) {
// if let Some(sk_model) = self.sk_model.take() {
// destroy_queue::add(sk_model);
// }
MODEL_REGISTRY.remove(self);
}
}

View File

@@ -9,7 +9,10 @@ use self::sphere::SphereField;
use self::torus::TorusField;
use super::alias::AliasInfo;
use super::spatial::Spatial;
use super::spatial::{
Spatial, SPATIAL_REF_GET_LOCAL_BOUNDING_BOX_SERVER_OPCODE,
SPATIAL_REF_GET_RELATIVE_BOUNDING_BOX_SERVER_OPCODE, SPATIAL_REF_GET_TRANSFORM_SERVER_OPCODE,
};
use super::{Aspect, Node};
use crate::core::client::Client;
use crate::create_interface;
@@ -24,7 +27,15 @@ use std::sync::Arc;
// TODO: get SDFs working properly with non-uniform scale and so on, output distance relative to the spatial it's compared against
pub static FIELD_ALIAS_INFO: Lazy<AliasInfo> = Lazy::new(|| AliasInfo {
server_methods: vec!["distance", "normal", "closest_point", "ray_march"],
server_methods: vec![
SPATIAL_REF_GET_TRANSFORM_SERVER_OPCODE,
SPATIAL_REF_GET_LOCAL_BOUNDING_BOX_SERVER_OPCODE,
SPATIAL_REF_GET_RELATIVE_BOUNDING_BOX_SERVER_OPCODE,
FIELD_DISTANCE_SERVER_OPCODE,
FIELD_NORMAL_SERVER_OPCODE,
FIELD_CLOSEST_POINT_SERVER_OPCODE,
FIELD_RAY_MARCH_SERVER_OPCODE,
],
..Default::default()
});
@@ -200,26 +211,20 @@ impl Deref for Field {
}
}
create_interface!(FieldInterface, FieldInterfaceAspect, "/field");
create_interface!(FieldInterface);
pub struct FieldInterface;
impl FieldInterfaceAspect for FieldInterface {
impl InterfaceAspect for FieldInterface {
fn create_box_field(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
size: mint::Vector3<f32>,
) -> Result<()> {
let transform = transform.to_mat4(true, true, false);
let parent = parent.get_aspect::<Spatial>()?;
let node = Node::create_parent_name(
&calling_client,
Self::CREATE_BOX_FIELD_PARENT_PATH,
&name,
true,
)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
BoxField::add_to(&node, size);
Ok(())
@@ -228,7 +233,7 @@ impl FieldInterfaceAspect for FieldInterface {
fn create_cylinder_field(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
length: f32,
@@ -236,13 +241,7 @@ impl FieldInterfaceAspect for FieldInterface {
) -> Result<()> {
let transform = transform.to_mat4(true, true, false);
let parent = parent.get_aspect::<Spatial>()?;
let node = Node::create_parent_name(
&calling_client,
Self::CREATE_CYLINDER_FIELD_PARENT_PATH,
&name,
true,
)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
CylinderField::add_to(&node, length, radius);
Ok(())
@@ -251,19 +250,13 @@ impl FieldInterfaceAspect for FieldInterface {
fn create_sphere_field(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
position: mint::Vector3<f32>,
radius: f32,
) -> Result<()> {
let parent = parent.get_aspect::<Spatial>()?;
let node = Node::create_parent_name(
&calling_client,
Self::CREATE_SPHERE_FIELD_PARENT_PATH,
&name,
true,
)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(
&node,
Some(parent.clone()),
@@ -277,7 +270,7 @@ impl FieldInterfaceAspect for FieldInterface {
fn create_torus_field(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
radius_a: f32,
@@ -285,13 +278,7 @@ impl FieldInterfaceAspect for FieldInterface {
) -> Result<()> {
let transform = transform.to_mat4(true, true, false);
let parent = parent.get_aspect::<Spatial>()?;
let node = Node::create_parent_name(
&calling_client,
Self::CREATE_TORUS_FIELD_PARENT_PATH,
&name,
true,
)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
TorusField::add_to(&node, radius_a, radius_b);
Ok(())

View File

@@ -1,8 +1,9 @@
use super::{alias::Alias, spatial::Spatial, Node};
use crate::{
core::client::{Client, INTERNAL_CLIENT},
nodes::alias::AliasInfo,
use super::{
alias::Alias,
spatial::{Spatial, SPATIAL_ASPECT_ALIAS_INFO},
Node,
};
use crate::core::client::{Client, INTERNAL_CLIENT};
use color_eyre::eyre::Result;
use glam::{vec3, Mat4};
use std::sync::Arc;
@@ -13,31 +14,21 @@ lazy_static::lazy_static! {
}
fn create() -> Arc<Node> {
let node = Arc::new(Node::create_parent_name(&INTERNAL_CLIENT, "", "hmd", false));
let node = Arc::new(Node::generate(&INTERNAL_CLIENT, false));
Spatial::add_to(&node, None, Mat4::IDENTITY, false);
node
}
pub fn frame() {
let spatial = HMD.get_aspect::<Spatial>().unwrap();
let hmd_pose = Input::get_head();
*spatial.transform.lock() = Mat4::from_scale_rotation_translation(
spatial.set_local_transform(Mat4::from_scale_rotation_translation(
vec3(1.0, 1.0, 1.0),
hmd_pose.orientation.into(),
hmd_pose.position.into(),
);
));
}
pub fn make_alias(client: &Arc<Client>) -> Result<Arc<Node>> {
Alias::create(
client,
"",
"hmd",
&HMD,
AliasInfo {
server_signals: vec!["get_bounds", "get_transform"],
..Default::default()
},
)
Alias::create(&HMD, client, SPATIAL_ASPECT_ALIAS_INFO.clone(), None)
}

View File

@@ -2,30 +2,23 @@ use super::{
input_handler_client, InputHandlerAspect, InputLink, INPUT_HANDLER_REGISTRY,
INPUT_METHOD_REGISTRY,
};
use crate::{
core::node_collections::LifeLinkedNodeMap,
nodes::{fields::Field, spatial::Spatial, Aspect, Node},
};
use crate::nodes::{alias::AliasList, fields::Field, spatial::Spatial, Aspect, Node};
use color_eyre::eyre::Result;
use stardust_xr::values::Datamap;
use std::sync::{Arc, Weak};
use std::sync::Arc;
use tracing::instrument;
pub struct InputHandler {
pub uid: String,
pub node: Weak<Node>,
pub spatial: Arc<Spatial>,
pub field: Arc<Field>,
pub(super) method_aliases: LifeLinkedNodeMap<usize>,
pub(super) method_aliases: AliasList,
}
impl InputHandler {
pub fn add_to(node: &Arc<Node>, field: &Arc<Field>) -> Result<()> {
let handler = InputHandler {
uid: node.uid.clone(),
node: Arc::downgrade(node),
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
field: field.clone(),
method_aliases: LifeLinkedNodeMap::default(),
method_aliases: AliasList::default(),
};
for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
method.make_alias(&handler);
@@ -44,20 +37,16 @@ impl InputHandler {
input_link: &InputLink,
datamap: Datamap,
) {
let Some(node) = self.node.upgrade() else {
let Some(node) = self.spatial.node() else {
return;
};
let Some(method_alias) = input_link
.handler
.method_aliases
.get(&(Arc::as_ptr(&input_link.method) as usize))
else {
let Some(method_alias) = self.method_aliases.get(input_link.method.as_ref()) else {
return;
};
let _ = input_handler_client::input(
&node,
&method_alias,
&input_link.serialize(order, captured, datamap),
&input_link.serialize(method_alias.id, order, captured, datamap),
);
}
}

View File

@@ -1,11 +1,12 @@
use super::{
input_method_client, InputDataTrait, InputDataType, InputHandler, InputMethodAspect,
InputMethodRefAspect, INPUT_HANDLER_REGISTRY, INPUT_METHOD_REGISTRY,
InputMethodRefAspect, INPUT_HANDLER_REGISTRY, INPUT_METHOD_ASPECT_ALIAS_INFO,
INPUT_METHOD_REF_ASPECT_ALIAS_INFO, INPUT_METHOD_REGISTRY,
};
use crate::{
core::{client::Client, node_collections::LifeLinkedNodeMap, registry::Registry},
core::{client::Client, registry::Registry},
nodes::{
alias::{Alias, AliasInfo},
alias::{Alias, AliasList},
fields::{Field, FIELD_ALIAS_INFO},
spatial::Spatial,
Aspect, Node,
@@ -19,7 +20,6 @@ use std::sync::{Arc, Weak};
pub struct InputMethod {
pub node: Weak<Node>,
pub uid: String,
pub enabled: Mutex<bool>,
pub spatial: Arc<Spatial>,
pub data: Mutex<InputDataType>,
@@ -27,7 +27,8 @@ pub struct InputMethod {
pub capture_requests: Registry<InputHandler>,
pub captures: Registry<InputHandler>,
pub(super) handler_aliases: LifeLinkedNodeMap<String>,
handler_aliases: AliasList,
handler_field_aliases: AliasList,
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
}
impl InputMethod {
@@ -38,14 +39,15 @@ impl InputMethod {
) -> Result<Arc<InputMethod>> {
let method = InputMethod {
node: Arc::downgrade(node),
uid: node.uid.clone(),
enabled: Mutex::new(true),
spatial: node.get_aspect::<Spatial>().unwrap().clone(),
data: Mutex::new(data),
datamap: Mutex::new(datamap),
capture_requests: Registry::new(),
captures: Registry::new(),
datamap: Mutex::new(datamap),
handler_aliases: LifeLinkedNodeMap::default(),
handler_aliases: AliasList::default(),
handler_field_aliases: AliasList::default(),
handler_order: Mutex::new(Vec::new()),
};
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
@@ -63,28 +65,21 @@ impl InputMethod {
let Some(method_node) = self.node.upgrade() else {
return;
};
let Some(handler_node) = handler.node.upgrade() else {
let Some(handler_node) = handler.spatial.node() else {
return;
};
let Some(client) = handler_node.get_client() else {
return;
};
let Ok(method_alias) = Alias::create(
&client,
handler_node.get_path(),
&self.uid,
&method_node,
AliasInfo {
server_signals: vec!["capture"],
..Default::default()
},
&client,
INPUT_METHOD_ASPECT_ALIAS_INFO.clone(),
Some(&handler.method_aliases),
) else {
return;
};
method_alias.enabled.store(false, Ordering::Relaxed);
handler
.method_aliases
.add(self as *const InputMethod as usize, &method_alias);
}
pub fn distance(&self, to: &Field) -> f32 {
@@ -102,57 +97,45 @@ impl InputMethod {
let Some(method_client) = method_node.get_client() else {
return;
};
let Some(handler_node) = handler.node.upgrade() else {
let Some(handler_node) = handler.spatial.node() else {
return;
};
// Receiver itself
let Ok(handler_alias) = Alias::create(
&method_client,
method_node.get_path(),
handler.uid.as_str(),
&handler_node,
AliasInfo {
server_methods: vec!["get_transform"],
..Default::default()
},
&method_client,
INPUT_METHOD_REF_ASPECT_ALIAS_INFO.clone(),
Some(&self.handler_aliases),
) else {
return;
};
self.handler_aliases
.add(handler.uid.clone(), &handler_alias);
let Some(handler_field_node) = handler.field.spatial_ref().node.upgrade() else {
let Some(handler_field_node) = handler.field.spatial_ref().node() else {
return;
};
// Handler's field
let Ok(rx_field_alias) = Alias::create(
&method_client,
handler_alias.get_path(),
"field",
&handler_field_node,
&method_client,
FIELD_ALIAS_INFO.clone(),
Some(&self.handler_field_aliases),
) else {
return;
};
self.handler_aliases
.add(handler.uid.clone() + "-field", &rx_field_alias);
let _ = input_method_client::create_handler(
&method_node,
&handler.uid,
&handler_node,
&rx_field_alias,
);
let _ = input_method_client::create_handler(&method_node, &handler_alias, &rx_field_alias);
}
pub(super) fn handle_drop_handler(&self, handler: &InputHandler) {
let uid = handler.uid.as_str();
self.handler_aliases.remove(uid);
self.handler_aliases.remove(&(uid.to_string() + "-field"));
let Some(tx_node) = self.node.upgrade() else {
return;
};
let _ = input_method_client::destroy_handler(&tx_node, &uid);
let Some(handler_alias) = self.handler_aliases.get(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());
}
}
impl Aspect for InputMethod {

View File

@@ -38,7 +38,7 @@ impl InputLink {
self.handler.send_input(order, captured, self, datamap);
}
#[instrument(level = "debug", skip(self))]
fn serialize(&self, order: u32, captured: bool, datamap: Datamap) -> InputData {
fn serialize(&self, id: u64, order: u32, captured: bool, datamap: Datamap) -> InputData {
let mut input = self.method.data.lock().clone();
input.update_to(
self,
@@ -46,7 +46,7 @@ impl InputLink {
);
InputData {
uid: self.method.uid.clone(),
id,
input,
distance: self.method.distance(&self.handler.field),
datamap,
@@ -77,14 +77,14 @@ impl InputDataTrait for InputDataType {
}
}
create_interface!(InputInterface, InputInterfaceAspect, "/input");
create_interface!(InputInterface);
pub struct InputInterface;
impl InputInterfaceAspect for InputInterface {
impl InterfaceAspect for InputInterface {
#[doc = "Create an input method node"]
fn create_input_method(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
initial_data: InputDataType,
@@ -93,8 +93,7 @@ impl InputInterfaceAspect for InputInterface {
let parent = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, true);
let node = Node::create_parent_name(&calling_client, "/input/method", &name, true)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
InputMethod::add_to(&node, initial_data, datamap)?;
Ok(())
@@ -104,7 +103,7 @@ impl InputInterfaceAspect for InputInterface {
fn create_input_handler(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
field: Arc<Node>,
@@ -113,8 +112,7 @@ impl InputInterfaceAspect for InputInterface {
let transform = transform.to_mat4(true, true, true);
let field = field.get_aspect::<Field>()?;
let node = Node::create_parent_name(&calling_client, "/input/handler", &name, true)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent.clone()), transform, false);
InputHandler::add_to(&node, &field)?;
Ok(())
@@ -145,7 +143,7 @@ pub fn process_input() {
.iter()
.filter_map(Weak::upgrade)
.filter(|handler| {
let Some(node) = handler.node.upgrade() else {
let Some(node) = handler.spatial.node() else {
return false;
};
node.enabled()
@@ -159,7 +157,7 @@ pub fn process_input() {
if let Some(method_alias) = input_link
.handler
.method_aliases
.get(&(Arc::as_ptr(&input_link.method) as usize))
.get(input_link.method.as_ref())
.and_then(|a| a.get_aspect::<Alias>().ok())
{
method_alias.enabled.store(true, Ordering::Release);

View File

@@ -1,10 +1,8 @@
use super::{create_item_acceptor_flex, register_item_ui_flex, Item, ItemInterface, ItemType};
use super::{
create_item_acceptor_flex, register_item_ui_flex, Item, ItemAcceptor, ItemInterface, ItemType,
};
use crate::{
core::{
client::{Client, INTERNAL_CLIENT},
registry::Registry,
scenegraph::MethodResponseSender,
},
core::{client::Client, registry::Registry, scenegraph::MethodResponseSender},
create_interface,
nodes::{
drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES},
@@ -17,7 +15,6 @@ use color_eyre::eyre::{bail, eyre, Result};
use glam::Mat4;
use lazy_static::lazy_static;
use mint::{ColumnMatrix4, Vector2};
use nanoid::nanoid;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use send_wrapper::SendWrapper;
@@ -37,14 +34,13 @@ stardust_xr_server_codegen::codegen_item_camera_protocol!();
lazy_static! {
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
type_name: "camera",
aliased_local_signals: vec!["apply_preview_material", "frame"],
aliased_local_methods: vec![],
aliased_remote_signals: vec![],
alias_info: CAMERA_ITEM_ASPECT_ALIAS_INFO.clone(),
ui_node_id: INTERFACE_NODE_ID,
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
new_acceptor_fn: |node, uid, acceptor, acceptor_field| {
let _ = camera_item_ui_client::create_acceptor(node, uid, acceptor, acceptor_field);
new_acceptor_fn: |node, acceptor, acceptor_field| {
let _ = camera_item_ui_client::create_acceptor(node, acceptor, acceptor_field);
}
};
}
@@ -62,11 +58,11 @@ pub struct CameraItem {
applied_to: Registry<ModelPart>,
apply_to: Registry<ModelPart>,
}
#[allow(unused)]
impl CameraItem {
pub fn add_to(node: &Arc<Node>, proj_matrix: Mat4, px_size: Vector2<u32>) {
Item::add_to(
node,
nanoid!(),
&ITEM_TYPE_INFO_CAMERA,
ItemType::Camera(CameraItem {
space: node.get_aspect::<Spatial>().unwrap().clone(),
@@ -80,11 +76,7 @@ impl CameraItem {
apply_to: Registry::new(),
}),
);
node.add_local_method("frame", CameraItem::frame_flex);
node.add_local_signal(
"apply_preview_material",
CameraItem::apply_preview_material_flex,
);
// <CameraItem as CameraItemAspect>::node_methods(node);
}
fn frame_flex(
@@ -118,11 +110,11 @@ impl CameraItem {
Ok(())
}
pub fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
let _ = camera_item_ui_client::create_item(node, uid, item);
pub fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>) {
let _ = camera_item_ui_client::create_item(node, item);
}
pub fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
let _ = camera_item_acceptor_client::capture_item(node, uid, item);
pub fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
let _ = camera_item_acceptor_client::capture_item(node, item);
}
pub fn update(&self, token: &MainThreadToken) {
@@ -166,6 +158,13 @@ impl CameraItem {
}
}
}
impl CameraItemAspect for CameraItem {}
impl CameraItemAcceptorAspect for ItemAcceptor {
fn capture_item(node: Arc<Node>, _calling_client: Arc<Client>, item: Arc<Node>) -> Result<()> {
super::acceptor_capture_item_flex(node, item)
}
}
pub fn update(token: &MainThreadToken) {
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
@@ -176,31 +175,24 @@ pub fn update(token: &MainThreadToken) {
}
}
create_interface!(ItemInterface, ItemCameraInterfaceAspect, "/item/camera");
impl ItemCameraInterfaceAspect for ItemInterface {
create_interface!(ItemInterface);
impl InterfaceAspect for ItemInterface {
#[doc = "Create a camera item at a specific location"]
fn create_camera_item(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
proj_matrix: ColumnMatrix4<f32>,
px_size: Vector2<u32>,
) -> Result<()> {
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_CAMERA.type_name);
let space = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, false);
let node = Node::create_parent_name(&INTERNAL_CLIENT, &parent_name, &name, false)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, false).add_to_scenegraph()?;
Spatial::add_to(&node, None, transform * space.global_transform(), false);
CameraItem::add_to(&node, proj_matrix.into(), px_size);
node.get_aspect::<Item>().unwrap().make_alias_named(
&calling_client,
&parent_name,
&name,
)?;
Ok(())
}
@@ -213,14 +205,14 @@ impl ItemCameraInterfaceAspect for ItemInterface {
fn create_camera_item_acceptor(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
field: Arc<Node>,
) -> Result<()> {
create_item_acceptor_flex(
calling_client,
name,
id,
parent,
transform,
&ITEM_TYPE_INFO_CAMERA,

View File

@@ -3,41 +3,23 @@ pub mod panel;
use self::camera::CameraItem;
use self::panel::PanelItemTrait;
use super::fields::Field;
use super::alias::AliasList;
use super::fields::{Field, FIELD_ALIAS_INFO};
use super::spatial::Spatial;
use super::{Alias, Aspect, Message, Node};
use super::{Alias, Aspect, Node};
use crate::core::client::Client;
use crate::core::node_collections::LifeLinkedNodeMap;
use crate::core::registry::Registry;
use crate::nodes::alias::AliasInfo;
use crate::nodes::spatial::Transform;
use color_eyre::eyre::{ensure, Result};
use lazy_static::lazy_static;
use nanoid::nanoid;
use parking_lot::Mutex;
use portable_atomic::Ordering;
use stardust_xr::schemas::flex::deserialize;
use std::hash::Hash;
use std::sync::{Arc, Weak};
stardust_xr_server_codegen::codegen_item_protocol!();
lazy_static! {
static ref ITEM_ALIAS_LOCAL_SIGNALS: Vec<&'static str> = vec![
"get_bounds",
"get_transform",
"set_transform",
"set_spatial_parent",
"set_spatial_parent_in_place",
"set_zoneable",
"release",
];
static ref ITEM_ALIAS_LOCAL_METHODS: Vec<&'static str> = vec![];
static ref ITEM_ALIAS_REMOTE_SIGNALS: Vec<&'static str> = vec![];
}
pub fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) {
fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) {
if item.captured_acceptor.lock().strong_count() > 0 {
release(item);
}
@@ -60,14 +42,12 @@ fn release(item: &Item) {
pub struct TypeInfo {
pub type_name: &'static str,
pub aliased_local_signals: Vec<&'static str>,
pub aliased_local_methods: Vec<&'static str>,
pub aliased_remote_signals: Vec<&'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 new_acceptor_fn:
fn(node: &Node, uid: &str, acceptor: &Arc<Node>, acceptor_field: &Arc<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) {
@@ -83,7 +63,6 @@ impl Eq for TypeInfo {}
pub struct Item {
node: Weak<Node>,
uid: String,
type_info: &'static TypeInfo,
captured_acceptor: Mutex<Weak<ItemAcceptor>>,
pub specialization: ItemType,
@@ -91,20 +70,18 @@ pub struct Item {
impl Item {
pub fn add_to(
node: &Arc<Node>,
uid: String,
type_info: &'static TypeInfo,
specialization: ItemType,
) -> Arc<Self> {
let item = Item {
node: Arc::downgrade(node),
uid,
type_info,
captured_acceptor: Default::default(),
specialization,
};
let item = type_info.items.add(item);
node.add_local_signal("release", Item::release_flex);
<Item as ItemAspect>::add_node_members(node);
if let Some(ui) = type_info.ui.lock().upgrade() {
ui.handle_create_item(&item);
}
@@ -122,54 +99,25 @@ impl Item {
item
}
fn make_alias_named(
&self,
client: &Arc<Client>,
parent: &str,
name: &str,
) -> Result<Arc<Node>> {
fn make_alias(&self, client: &Arc<Client>, alias_list: &AliasList) -> Result<Arc<Node>> {
Alias::create(
client,
parent,
name,
&self.node.upgrade().unwrap(),
AliasInfo {
server_signals: [
&self.type_info.aliased_local_signals,
ITEM_ALIAS_LOCAL_SIGNALS.as_slice(),
]
.concat(),
server_methods: [
&self.type_info.aliased_local_methods,
ITEM_ALIAS_LOCAL_METHODS.as_slice(),
]
.concat(),
client_signals: [
&self.type_info.aliased_remote_signals,
ITEM_ALIAS_REMOTE_SIGNALS.as_slice(),
]
.concat(),
},
client,
self.type_info.alias_info.clone() + ITEM_ASPECT_ALIAS_INFO.clone(),
Some(alias_list),
)
}
fn make_alias(&self, client: &Arc<Client>, parent: &str) -> Result<Arc<Node>> {
self.make_alias_named(client, parent, &self.uid)
}
fn release_flex(
node: Arc<Node>,
_calling_client: Arc<Client>,
_message: Message,
) -> Result<()> {
let item = node.get_aspect::<Item>()?;
release(&item);
Ok(())
}
}
impl Aspect for Item {
const NAME: &'static str = "Item";
}
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);
@@ -185,16 +133,16 @@ pub enum ItemType {
Panel(Arc<dyn PanelItemTrait>),
}
impl ItemType {
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>) {
match self {
ItemType::Camera(c) => c.send_ui_item_created(node, uid, item),
ItemType::Panel(p) => p.send_ui_item_created(node, uid, item),
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, uid: &str, item: &Arc<Node>) {
fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
match self {
ItemType::Camera(c) => c.send_acceptor_item_created(node, uid, item),
ItemType::Panel(p) => p.send_acceptor_item_created(node, uid, item),
ItemType::Camera(c) => c.send_acceptor_item_created(node, item),
ItemType::Panel(p) => p.send_acceptor_item_created(node, item),
}
}
}
@@ -212,9 +160,9 @@ impl ItemType {
pub struct ItemUI {
node: Weak<Node>,
type_info: &'static TypeInfo,
item_aliases: LifeLinkedNodeMap<String>,
acceptor_aliases: LifeLinkedNodeMap<String>,
acceptor_field_aliases: LifeLinkedNodeMap<String>,
item_aliases: AliasList,
acceptor_aliases: AliasList,
acceptor_field_aliases: AliasList,
}
impl ItemUI {
fn add_to(node: &Arc<Node>, type_info: &'static TypeInfo) -> Result<()> {
@@ -226,9 +174,9 @@ impl ItemUI {
let ui = Arc::new(ItemUI {
node: Arc::downgrade(node),
type_info,
item_aliases: Default::default(),
acceptor_aliases: Default::default(),
acceptor_field_aliases: Default::default(),
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());
@@ -250,26 +198,44 @@ impl ItemUI {
return;
};
let Ok(item_alias) = item.make_alias(&client, &(node.get_path().to_string() + "/item"))
else {
let Ok(item_alias) = item.make_alias(&client, &self.item_aliases) else {
return;
};
self.item_aliases.add(item.uid.clone(), &item_alias);
item.specialization
.send_ui_item_created(&node, &item.uid, &item_alias);
item.specialization.send_ui_item_created(&node, &item_alias);
}
fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) {
let _ =
item_ui_client::capture_item(&self.node.upgrade().unwrap(), &item.uid, &acceptor.uid);
let Some(item_alias) = self.item_aliases.get(item) else {
return;
};
let Some(acceptor_alias) = self.acceptor_aliases.get(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 _ =
item_ui_client::release_item(&self.node.upgrade().unwrap(), &item.uid, &acceptor.uid);
let Some(item_alias) = self.item_aliases.get(item) else {
return;
};
let Some(acceptor_alias) = self.acceptor_aliases.get(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 _ = item_ui_client::destroy_item(&self.node.upgrade().unwrap(), &item.uid);
self.item_aliases.remove(&item.uid);
let Some(item_alias) = self.item_aliases.get(item) 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 {
@@ -279,28 +245,40 @@ impl ItemUI {
return;
};
let Ok((acceptor_alias, acceptor_field_alias)) = acceptor.make_aliases(
let Some(acceptor_node) = acceptor.spatial.node() else {
return;
};
let Ok(acceptor_alias) = Alias::create(
&acceptor_node,
&client,
&format!("/item/{}/acceptor", self.type_info.type_name),
ITEM_ACCEPTOR_ASPECT_ALIAS_INFO.clone(),
Some(&self.acceptor_aliases),
) else {
return;
};
self.acceptor_aliases
.add(acceptor.uid.clone(), &acceptor_alias);
self.acceptor_field_aliases
.add(acceptor.uid.clone(), &acceptor_field_alias);
(acceptor.type_info.new_acceptor_fn)(
&node,
&acceptor.uid,
&acceptor_alias,
&acceptor_field_alias,
);
let Some(acceptor_field_node) = acceptor.field.spatial_ref().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 _ = item_ui_client::destroy_acceptor(&self.node.upgrade().unwrap(), &acceptor.uid);
self.acceptor_aliases.remove(&acceptor.uid);
self.acceptor_field_aliases.remove(&acceptor.uid);
let acceptor_alias = self.acceptor_aliases.get(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 Aspect for ItemUI {
@@ -313,69 +291,29 @@ impl Drop for ItemUI {
}
pub struct ItemAcceptor {
uid: String,
node: Weak<Node>,
spatial: Arc<Spatial>,
pub type_info: &'static TypeInfo,
field: Arc<Field>,
accepted_aliases: LifeLinkedNodeMap<String>,
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 {
uid: nanoid!(),
node: Arc::downgrade(node),
spatial: node.get_aspect::<Spatial>().unwrap(),
type_info,
field,
accepted_aliases: Default::default(),
accepted_aliases: AliasList::default(),
accepted_registry: Registry::new(),
});
node.add_local_signal("capture", ItemAcceptor::capture_flex);
if let Some(ui) = type_info.ui.lock().upgrade() {
ui.handle_create_acceptor(&acceptor);
}
node.add_aspect_raw(acceptor);
node.add_aspect_raw(acceptor.clone());
}
fn capture_flex(node: Arc<Node>, calling_client: Arc<Client>, message: Message) -> Result<()> {
if !node.enabled.load(Ordering::Relaxed) {
return Ok(());
}
let acceptor = node.get_aspect::<ItemAcceptor>().unwrap();
let item_path: &str = deserialize(message.as_ref())?;
let item_node = calling_client.get_node("Item", item_path)?;
let item = item_node.get_aspect::<Item>()?;
capture(&item, &acceptor);
Ok(())
}
fn make_aliases(&self, client: &Arc<Client>, parent: &str) -> Result<(Arc<Node>, Arc<Node>)> {
let acceptor_node = &self.node.upgrade().unwrap();
let acceptor_alias = Alias::create(
client,
parent,
&self.uid,
acceptor_node,
AliasInfo {
server_signals: vec!["capture"],
..Default::default()
},
)?;
let acceptor_field_alias = Alias::create(
client,
acceptor_alias.get_path(),
"field",
&self.field.spatial_ref().node.upgrade().unwrap(),
AliasInfo::default(),
)?;
Ok((acceptor_alias, acceptor_field_alias))
}
fn handle_capture(&self, item: &Arc<Item>) {
let Some(node) = self.node.upgrade() else {
let Some(node) = self.spatial.node() else {
return;
};
let Some(client) = node.get_client() else {
@@ -383,21 +321,22 @@ impl ItemAcceptor {
};
self.accepted_registry.add_raw(item);
let Ok(alias_node) = item.make_alias(&client, &node.path) else {
let Ok(alias_node) = item.make_alias(&client, &self.accepted_aliases) else {
return;
};
self.accepted_aliases.add(item.uid.clone(), &alias_node);
item.specialization
.send_acceptor_item_created(&node, &item.uid, &alias_node);
.send_acceptor_item_created(&node, &alias_node);
}
fn handle_release(&self, item: &Item) {
if let Some(node) = self.node.upgrade() {
let _ = item_acceptor_client::release_item(&node, &item.uid);
}
self.accepted_registry.remove(item);
self.accepted_aliases.remove(&item.uid);
self.accepted_aliases.remove_aspect(item);
let Some(node) = self.spatial.node() else {
return;
};
let alias = self.accepted_aliases.get(item).unwrap();
let _ = item_acceptor_client::release_item(&node, alias.id);
}
}
impl Aspect for ItemAcceptor {
@@ -420,14 +359,13 @@ pub fn register_item_ui_flex(
calling_client: Arc<Client>,
type_info: &'static TypeInfo,
) -> Result<()> {
let ui = Node::create_parent_name(&calling_client, "/item", type_info.type_name, true)
.add_to_scenegraph()?;
let ui = Node::from_id(&calling_client, type_info.ui_node_id, true).add_to_scenegraph()?;
ItemUI::add_to(&ui, type_info)?;
Ok(())
}
fn create_item_acceptor_flex(
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
type_info: &'static TypeInfo,
@@ -437,17 +375,19 @@ fn create_item_acceptor_flex(
let field = field.get_aspect::<Field>()?;
let transform = transform.to_mat4(true, true, false);
let node = Node::create_parent_name(
&calling_client,
&format!("/item/{}/acceptor", type_info.type_name),
&name,
true,
)
.add_to_scenegraph()?;
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);
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(())
}
struct ItemInterface;
// create_interface!(ItemInterface, ItemInterfaceAspect, "/item");
// create_interface!(ItemInterface);

View File

@@ -15,51 +15,22 @@ use color_eyre::eyre::Result;
use glam::Mat4;
use lazy_static::lazy_static;
use mint::Vector2;
use nanoid::nanoid;
use std::sync::{Arc, Weak};
use tracing::{debug, info};
use super::{create_item_acceptor_flex, register_item_ui_flex, ItemInterface};
use super::{create_item_acceptor_flex, register_item_ui_flex, ItemAcceptor, ItemInterface};
stardust_xr_server_codegen::codegen_item_panel_protocol!();
lazy_static! {
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
type_name: "panel",
aliased_local_signals: vec![
"apply_surface_material",
"close_toplevel",
"auto_size_toplevel",
"set_toplevel_size",
"set_toplevel_focused_visuals",
"pointer_motion",
"pointer_button",
"pointer_scroll",
"keyboard_keymap",
"keyboard_key",
"touch_down",
"touch_move",
"touch_up",
"reset_touches",
],
aliased_local_methods: vec![],
aliased_remote_signals: vec![
"toplevel_parent_changed",
"toplevel_title_changed",
"toplevel_app_id_changed",
"toplevel_fullscreen_active",
"toplevel_move_request",
"toplevel_resize_request",
"toplevel_size_changed",
"set_cursor",
"new_child",
"reposition_child",
"drop_child",
],
alias_info: PANEL_ITEM_ASPECT_ALIAS_INFO.clone(),
ui_node_id: INTERFACE_NODE_ID,
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
new_acceptor_fn: |node, uid, acceptor, acceptor_field| {
let _ = panel_item_ui_client::create_acceptor(node, uid, acceptor, acceptor_field);
new_acceptor_fn: |node, acceptor, acceptor_field| {
let _ = panel_item_ui_client::create_acceptor(node, acceptor, acceptor_field);
}
};
}
@@ -85,7 +56,7 @@ pub trait Backend: Send + Sync + 'static {
scroll_steps: Option<Vector2<f32>>,
);
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>);
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec<i32>);
fn touch_down(&self, surface: &SurfaceId, id: u32, position: Vector2<f32>);
fn touch_move(&self, id: u32, position: Vector2<f32>);
@@ -101,13 +72,12 @@ pub fn panel_item_from_node(node: &Node) -> Option<Arc<dyn PanelItemTrait>> {
}
pub trait PanelItemTrait: Backend + Send + Sync + 'static {
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>);
fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>);
fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>);
fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>);
}
pub struct PanelItem<B: Backend + ?Sized> {
pub uid: String,
node: Weak<Node>,
pub node: Weak<Node>,
pub backend: Box<B>,
}
impl<B: Backend + ?Sized> PanelItem<B> {
@@ -118,20 +88,13 @@ impl<B: Backend + ?Sized> PanelItem<B> {
.and_then(|pid| get_env(pid).ok())
.and_then(|env| state(&env));
let uid = nanoid!();
let node = Arc::new(Node::create_parent_name(
&INTERNAL_CLIENT,
"/item/panel/item",
&uid,
true,
));
let node = Arc::new(Node::generate(&INTERNAL_CLIENT, true));
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
if let Some(startup_settings) = &startup_settings {
spatial.set_local_transform(startup_settings.root);
}
let panel_item = Arc::new(PanelItem {
uid: uid.clone(),
node: Arc::downgrade(&node),
backend,
});
@@ -139,7 +102,6 @@ impl<B: Backend + ?Sized> PanelItem<B> {
let generic_panel_item: Arc<dyn PanelItemTrait> = panel_item.clone();
Item::add_to(
&node,
uid,
&ITEM_TYPE_INFO_PANEL,
ItemType::Panel(generic_panel_item),
);
@@ -158,7 +120,7 @@ impl<B: Backend + ?Sized> PanelItem<B> {
// Remote signals
#[allow(unused)]
impl<B: Backend + ?Sized> PanelItem<B> {
pub fn toplevel_parent_changed(&self, parent: &str) {
pub fn toplevel_parent_changed(&self, parent: u64) {
let Some(node) = self.node.upgrade() else {
return;
};
@@ -212,23 +174,23 @@ impl<B: Backend + ?Sized> PanelItem<B> {
}
}
pub fn create_child(&self, uid: &str, info: ChildInfo) {
pub fn create_child(&self, id: u64, info: &ChildInfo) {
let Some(node) = self.node.upgrade() else {
return;
};
panel_item_client::create_child(&node, uid, &info);
panel_item_client::create_child(&node, id, info);
}
pub fn reposition_child(&self, uid: &str, geometry: Geometry) {
pub fn reposition_child(&self, id: u64, geometry: &Geometry) {
let Some(node) = self.node.upgrade() else {
return;
};
panel_item_client::reposition_child(&node, uid, &geometry);
panel_item_client::reposition_child(&node, id, geometry);
}
pub fn destroy_child(&self, uid: &str) {
pub fn destroy_child(&self, id: u64) {
let Some(node) = self.node.upgrade() else {
return;
};
panel_item_client::destroy_child(&node, uid);
panel_item_client::destroy_child(&node, id);
}
}
@@ -373,13 +335,13 @@ impl<B: Backend + ?Sized> PanelItemAspect for PanelItem<B> {
node: Arc<Node>,
_calling_client: Arc<Client>,
surface: SurfaceId,
keymap_id: String,
keymap_id: u64,
keys: Vec<i32>,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.keyboard_keys(&surface, &keymap_id, keys);
panel_item.keyboard_keys(&surface, keymap_id, keys);
Ok(())
}
@@ -430,18 +392,25 @@ impl<B: Backend + ?Sized> PanelItemAspect for PanelItem<B> {
Ok(())
}
}
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
let Ok(init_data) = self.backend.start_data() else {
return;
};
let _ = panel_item_ui_client::create_item(node, uid, item, init_data);
impl PanelItemAcceptorAspect for ItemAcceptor {
fn capture_item(node: Arc<Node>, _calling_client: Arc<Client>, item: Arc<Node>) -> Result<()> {
super::acceptor_capture_item_flex(node, item)
}
fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
}
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
fn send_ui_item_created(&self, node: &Node, item: &Arc<Node>) {
let Ok(init_data) = self.backend.start_data() else {
return;
};
let _ = panel_item_acceptor_client::capture_item(node, uid, item, init_data);
let _ = panel_item_ui_client::create_item(node, item, init_data);
}
fn send_acceptor_item_created(&self, node: &Node, item: &Arc<Node>) {
let Ok(init_data) = self.backend.start_data() else {
return;
};
let _ = panel_item_acceptor_client::capture_item(node, item, init_data);
}
}
impl<B: Backend + ?Sized> Backend for PanelItem<B> {
@@ -488,7 +457,7 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
.pointer_scroll(surface, scroll_distance, scroll_steps)
}
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>) {
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec<i32>) {
self.backend.keyboard_keys(surface, keymap_id, keys)
}
@@ -508,12 +477,12 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
impl<B: Backend + ?Sized> Drop for PanelItem<B> {
fn drop(&mut self) {
// Dropped panel item, basically just a debug breakpoint place
info!("Dropped panel item {}", self.uid);
info!("Dropped panel item");
}
}
create_interface!(ItemInterface, ItemPanelInterfaceAspect, "/item/panel");
impl ItemPanelInterfaceAspect for ItemInterface {
create_interface!(ItemInterface);
impl InterfaceAspect for ItemInterface {
#[doc = "Register this client to manage the items of a certain type and create default 3D UI for them."]
fn register_panel_item_ui(_node: Arc<Node>, calling_client: Arc<Client>) -> Result<()> {
register_item_ui_flex(calling_client, &ITEM_TYPE_INFO_PANEL)
@@ -523,14 +492,14 @@ impl ItemPanelInterfaceAspect for ItemInterface {
fn create_panel_item_acceptor(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
field: Arc<Node>,
) -> Result<()> {
create_item_acceptor_flex(
calling_client,
name,
id,
parent,
transform,
&ITEM_TYPE_INFO_PANEL,

View File

@@ -10,7 +10,6 @@ pub mod root;
pub mod spatial;
use color_eyre::eyre::{eyre, Result};
use nanoid::nanoid;
use parking_lot::Mutex;
use portable_atomic::{AtomicBool, Ordering};
use rustc_hash::FxHashMap;
@@ -56,13 +55,12 @@ stardust_xr_server_codegen::codegen_node_protocol!();
pub struct Node {
enabled: Arc<AtomicBool>,
pub(super) uid: String,
path: String,
id: u64,
client: Weak<Client>,
message_sender_handle: Option<MessageSenderHandle>,
// trailing_slash_pos: usize,
local_signals: Mutex<FxHashMap<String, Signal>>,
local_methods: Mutex<FxHashMap<String, Method>>,
local_signals: Mutex<FxHashMap<u64, Signal>>,
local_methods: Mutex<FxHashMap<u64, Method>>,
aliases: Registry<Alias>,
aspects: Aspects,
destroyable: bool,
@@ -71,32 +69,19 @@ impl Node {
pub fn get_client(&self) -> Option<Arc<Client>> {
self.client.upgrade()
}
// pub fn get_name(&self) -> &str {
// &self.path[self.trailing_slash_pos + 1..]
// }
pub fn get_path(&self) -> &str {
self.path.as_str()
pub fn get_id(&self) -> u64 {
self.id
}
pub fn create_parent_name(
client: &Arc<Client>,
parent: &str,
name: &str,
destroyable: bool,
) -> Self {
let mut path = parent.to_string();
path.push('/');
path.push_str(name);
Self::create_path(client, path, destroyable)
pub fn generate(client: &Arc<Client>, destroyable: bool) -> Self {
Self::from_id(client, client.generate_id(), destroyable)
}
pub fn create_path(client: &Arc<Client>, path: impl ToString, destroyable: bool) -> Self {
pub fn from_id(client: &Arc<Client>, id: u64, destroyable: bool) -> Self {
let node = Node {
enabled: Arc::new(AtomicBool::new(true)),
uid: nanoid!(),
client: Arc::downgrade(client),
message_sender_handle: client.message_sender_handle.clone(),
path: path.to_string(),
// trailing_slash_pos: parent.len(),
id,
local_signals: Default::default(),
local_methods: Default::default(),
aliases: Default::default(),
@@ -118,7 +103,7 @@ impl Node {
}
pub fn destroy(&self) {
if let Some(client) = self.get_client() {
client.scenegraph.remove_node(self.get_path());
client.scenegraph.remove_node(self.get_id());
}
}
@@ -136,11 +121,11 @@ impl Node {
// Ok(serialize(pid)?.into())
// }
pub fn add_local_signal(&self, name: &str, signal: Signal) {
self.local_signals.lock().insert(name.to_string(), signal);
pub fn add_local_signal(&self, id: u64, signal: Signal) {
self.local_signals.lock().insert(id, signal);
}
pub fn add_local_method(&self, name: &str, method: Method) {
self.local_methods.lock().insert(name.to_string(), method);
pub fn add_local_method(&self, id: u64, method: Method) {
self.local_methods.lock().insert(id, method);
}
pub fn add_aspect<A: Aspect>(&self, aspect: A) -> Arc<A> {
@@ -156,7 +141,7 @@ impl Node {
pub fn send_local_signal(
self: Arc<Self>,
calling_client: Arc<Client>,
method: &str,
method: u64,
message: Message,
) -> Result<(), ScenegraphError> {
if let Ok(alias) = self.get_aspect::<Alias>() {
@@ -172,7 +157,7 @@ impl Node {
let signal = self
.local_signals
.lock()
.get(method)
.get(&method)
.cloned()
.ok_or(ScenegraphError::SignalNotFound)?;
signal(self, calling_client, message).map_err(|error| ScenegraphError::SignalError {
@@ -183,7 +168,7 @@ impl Node {
pub fn execute_local_method(
self: Arc<Self>,
calling_client: Arc<Client>,
method: &str,
method: u64,
message: Message,
response: MethodResponseSender,
) {
@@ -206,14 +191,14 @@ impl Node {
response,
)
} else {
let Some(method) = self.local_methods.lock().get(method).cloned() else {
let Some(method) = self.local_methods.lock().get(&method).cloned() else {
response.send(Err(ScenegraphError::MethodNotFound));
return;
};
method(self, calling_client, message, response);
}
}
pub fn send_remote_signal(&self, method: &str, message: impl Into<Message>) -> Result<()> {
pub fn send_remote_signal(&self, method: u64, message: impl Into<Message>) -> Result<()> {
let message = message.into();
self.aliases
.get_valid_contents()
@@ -230,16 +215,14 @@ impl Node {
},
);
});
let path = self.path.clone();
let method = method.to_string();
if let Some(handle) = self.message_sender_handle.as_ref() {
handle.signal(path.as_str(), method.as_str(), &message.data, message.fds)?;
handle.signal(self.id, method, &message.data, message.fds)?;
}
Ok(())
}
pub async fn execute_remote_method_typed<S: Serialize, D: DeserializeOwned>(
&self,
method: &str,
method: u64,
input: S,
fds: Vec<OwnedFd>,
) -> Result<(D, Vec<OwnedFd>)> {
@@ -250,7 +233,7 @@ impl Node {
let serialized = serialize(input)?;
let result = message_sender_handle
.method(self.path.as_str(), method, &serialized, fds)?
.method(self.id, method, &serialized, fds)?
.await
.map_err(|e| eyre!(e))?;
@@ -261,10 +244,7 @@ impl Node {
}
impl Debug for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Node")
.field("uid", &self.uid)
.field("path", &self.path)
.finish()
f.debug_struct("Node").field("id", &self.id).finish()
}
}
impl OwnedAspect for Node {

View File

@@ -1,128 +1,73 @@
use super::spatial::Spatial;
use super::{Message, Node};
use super::Node;
use crate::core::client::Client;
use crate::core::client_state::{ClientState, ClientStateInternal};
use crate::core::client_state::ClientStateParsed;
use crate::core::registry::Registry;
use crate::core::scenegraph::MethodResponseSender;
#[cfg(feature = "wayland")]
use crate::wayland::WAYLAND_DISPLAY;
#[cfg(feature = "xwayland")]
use crate::wayland::X_DISPLAY;
use crate::STARDUST_INSTANCE;
use color_eyre::eyre::Result;
use color_eyre::eyre::{bail, Result};
use glam::Mat4;
use rustc_hash::FxHashMap;
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tracing::{info, instrument};
use tracing::info;
static ROOT_REGISTRY: Registry<Root> = Registry::new();
pub struct Root {
pub node: Arc<Node>,
send_frame_event: AtomicBool,
}
stardust_xr_server_codegen::codegen_root_protocol!();
pub struct Root(Arc<Node>);
impl Root {
pub fn create(client: &Arc<Client>) -> Result<Arc<Self>> {
let node = Node::create_parent_name(client, "", "", false);
node.add_local_signal("subscribe_frame", Root::subscribe_frame_flex);
node.add_local_signal("set_base_prefixes", Root::set_base_prefixes_flex);
node.add_local_method("state_token", Root::state_token_flex);
node.add_local_method(
"get_connection_environment",
get_connection_environment_flex,
);
pub fn create(client: &Arc<Client>, transform: Mat4) -> Result<Arc<Self>> {
let node = Node::from_id(client, 0, false);
<Self as RootAspect>::add_node_members(&node);
let node = node.add_to_scenegraph()?;
let _ = Spatial::add_to(&node, None, client.state.root, false);
let _ = Spatial::add_to(&node, None, transform, false);
Ok(ROOT_REGISTRY.add(Root {
node,
send_frame_event: AtomicBool::from(false),
}))
Ok(ROOT_REGISTRY.add(Root(node)))
}
fn subscribe_frame_flex(
_node: Arc<Node>,
calling_client: Arc<Client>,
_message: Message,
) -> Result<()> {
calling_client
.root
.get()
.unwrap()
.send_frame_event
.store(true, Ordering::Relaxed);
Ok(())
}
#[instrument(level = "debug")]
pub fn send_frame_events(delta: f64) {
if let Ok(data) = serialize((delta, 0.0)) {
let info = FrameInfo {
delta: delta as f32,
elapsed: 0.0,
};
for root in ROOT_REGISTRY.get_valid_contents() {
if root.send_frame_event.load(Ordering::Relaxed) {
let _ = root.node.send_remote_signal("frame", data.clone());
let _ = root_client::frame(&root.0, &info);
}
}
}
}
fn set_base_prefixes_flex(
_node: Arc<Node>,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let prefixes: Vec<PathBuf> = deserialize(message.as_ref())?;
info!(?calling_client, ?prefixes, "Set base prefixes");
*calling_client.base_resource_prefixes.lock() = prefixes;
Ok(())
}
fn state_token_flex(
_node: Arc<Node>,
calling_client: Arc<Client>,
message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(|| {
let state: ClientStateInternal = deserialize(message.as_ref())?;
let token = ClientState::from_deserialized(&calling_client, state).token();
Ok(serialize(token)?.into())
})
}
pub fn set_transform(&self, transform: Mat4) {
let spatial = self.node.get_aspect::<Spatial>().unwrap();
let spatial = self.0.get_aspect::<Spatial>().unwrap();
spatial.set_spatial_parent(None).unwrap();
spatial.set_local_transform(transform);
}
pub async fn save_state(&self) -> Result<ClientStateInternal> {
self.node
.execute_remote_method_typed("save_state", (), Vec::new())
.await
.map(|(m, _)| m)
pub async fn save_state(&self) -> Result<ClientState> {
Ok(root_client::save_state(&self.0).await?.0)
}
}
impl Drop for Root {
fn drop(&mut self) {
ROOT_REGISTRY.remove(self);
impl RootAspect for Root {
async fn get_state(_node: Arc<Node>, calling_client: Arc<Client>) -> Result<ClientState> {
let Some(state) = calling_client.state.get() else {
bail!("Couldn't get state");
};
Ok(state.clone())
}
}
macro_rules! var_env_insert {
#[doc = "Get a hashmap of all the environment variables to connect a given app to the stardust server"]
async fn get_connection_environment(
_node: Arc<Node>,
_calling_client: Arc<Client>,
) -> Result<stardust_xr::values::Map<String, String>> {
macro_rules! var_env_insert {
($env:ident, $name:ident) => {
$env.insert(stringify!($name).to_string(), $name.get().unwrap().clone());
};
}
pub fn get_connection_environment_flex(
_node: Arc<Node>,
_calling_client: Arc<Client>,
_message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(move || {
}
let mut env: FxHashMap<String, String> = FxHashMap::default();
var_env_insert!(env, STARDUST_INSTANCE);
#[cfg(feature = "wayland")]
@@ -140,6 +85,38 @@ pub fn get_connection_environment_flex(
env.insert("SDL_VIDEODRIVER".to_string(), "wayland".to_string());
}
Ok(serialize(env)?.into())
});
Ok(env)
}
#[doc = "Generate a client state token and return it back.\n\n When launching a new client, set the environment variable `STARDUST_STARTUP_TOKEN` to the returned string.\n Make sure the environment variable shows in `/proc/{pid}/environ` as that's the only reliable way to pass the value to the server (suggestions welcome).\n"]
async fn client_state_token(
_node: Arc<Node>,
calling_client: Arc<Client>,
state: ClientState,
) -> Result<String> {
Ok(ClientStateParsed::from_deserialized(&calling_client, state).token())
}
#[doc = "Set initial list of folders to look for namespaced resources in"]
fn set_base_prefixes(
_node: Arc<Node>,
calling_client: Arc<Client>,
prefixes: Vec<String>,
) -> Result<()> {
info!(?calling_client, ?prefixes, "Set base prefixes");
*calling_client.base_resource_prefixes.lock() =
prefixes.into_iter().map(PathBuf::from).collect();
Ok(())
}
#[doc = "Cleanly disconnect from the server"]
fn disconnect(_node: Arc<Node>, calling_client: Arc<Client>) -> color_eyre::eyre::Result<()> {
calling_client.disconnect(Ok(()));
Ok(())
}
}
impl Drop for Root {
fn drop(&mut self) {
ROOT_REGISTRY.remove(self);
}
}

View File

@@ -9,7 +9,6 @@ use crate::create_interface;
use color_eyre::eyre::{eyre, Result};
use glam::{vec3a, Mat4, Quat, Vec3};
use mint::Vector3;
use nanoid::nanoid;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use std::fmt::Debug;
@@ -40,20 +39,18 @@ impl Transform {
static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new();
pub struct Spatial {
uid: String,
pub(super) node: Weak<Node>,
node: Weak<Node>,
parent: Mutex<Option<Arc<Spatial>>>,
old_parent: Mutex<Option<Arc<Spatial>>>,
pub(super) transform: Mutex<Mat4>,
transform: Mutex<Mat4>,
zone: Mutex<Weak<Zone>>,
children: Registry<Spatial>,
pub(super) bounding_box_calc: OnceCell<fn(&Node) -> Bounds>,
pub bounding_box_calc: OnceCell<fn(&Node) -> Bounds>,
}
impl Spatial {
pub fn new(node: Weak<Node>, parent: Option<Arc<Spatial>>, transform: Mat4) -> Arc<Self> {
Arc::new(Spatial {
uid: nanoid!(),
node,
parent: Mutex::new(parent),
old_parent: Mutex::new(None),
@@ -232,7 +229,7 @@ impl Spatial {
self.zone
.lock()
.upgrade()
.and_then(|zone| zone.field.upgrade())
.map(|zone| zone.field.clone())
.map(|field| field.distance(self, vec3a(0.0, 0.0, 0.0)))
.unwrap_or(f32::MAX)
}
@@ -359,13 +356,12 @@ impl SpatialAspect for Spatial {
}
impl PartialEq for Spatial {
fn eq(&self, other: &Self) -> bool {
self.uid == other.uid
self.node.as_ptr() == other.node.as_ptr()
}
}
impl Debug for Spatial {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Spatial")
.field("uid", &self.uid)
.field("parent", &self.parent)
.field("old_parent", &self.old_parent)
.field("transform", &self.transform)
@@ -374,7 +370,7 @@ impl Debug for Spatial {
}
impl Drop for Spatial {
fn drop(&mut self) {
zone::release_drop(self);
zone::release(self);
ZONEABLE_REGISTRY.remove(self);
}
}
@@ -397,26 +393,25 @@ pub fn parse_transform(transform: Transform, position: bool, rotation: bool, sca
}
pub struct SpatialInterface;
impl SpatialInterfaceAspect for SpatialInterface {
impl InterfaceAspect for SpatialInterface {
fn create_spatial(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
zoneable: bool,
) -> Result<()> {
let parent = parent.get_aspect::<Spatial>()?;
let transform = parse_transform(transform, true, true, true);
let node = Node::create_parent_name(&calling_client, "/spatial/spatial", &name, true)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
Spatial::add_to(&node, Some(parent.clone()), transform, zoneable);
Ok(())
}
fn create_zone(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
id: u64,
parent: Arc<Node>,
transform: Transform,
field: Arc<Node>,
@@ -425,12 +420,11 @@ impl SpatialInterfaceAspect for SpatialInterface {
let transform = parse_transform(transform, true, true, false);
let field = field.get_aspect::<Field>()?;
let node = Node::create_parent_name(&calling_client, "/spatial/zone", &name, true)
.add_to_scenegraph()?;
let node = Node::from_id(&calling_client, id, true).add_to_scenegraph()?;
let space = Spatial::add_to(&node, Some(parent.clone()), transform, false);
Zone::add_to(&node, space, &field);
Zone::add_to(&node, space, field);
Ok(())
}
}
create_interface!(SpatialInterface, SpatialInterfaceAspect, "/spatial");
create_interface!(SpatialInterface);

View File

@@ -1,166 +1,147 @@
use super::{Spatial, ZoneAspect, ZONEABLE_REGISTRY};
use super::{
Spatial, ZoneAspect, SPATIAL_ASPECT_ALIAS_INFO, SPATIAL_REF_ASPECT_ALIAS_INFO,
ZONEABLE_REGISTRY,
};
use crate::{
core::{client::Client, registry::Registry},
nodes::{
alias::{Alias, AliasInfo},
alias::{get_original, Alias, AliasList},
fields::Field,
Aspect, Node,
},
};
use color_eyre::eyre::Result;
use glam::vec3a;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use std::sync::{Arc, Weak};
pub fn capture(spatial: &Arc<Spatial>, zone: &Arc<Zone>) {
let old_distance = spatial.zone_distance();
let new_distance = zone
.field
.upgrade()
.map(|field| field.distance(spatial, vec3a(0.0, 0.0, 0.0)))
.unwrap_or(f32::MAX);
let new_distance = zone.field.distance(spatial, vec3a(0.0, 0.0, 0.0));
if new_distance.abs() < old_distance.abs() {
release(spatial);
*spatial.old_parent.lock() = spatial.get_parent();
*spatial.zone.lock() = Arc::downgrade(zone);
zone.captured.add_raw(spatial);
let Some(node) = zone.spatial.node.upgrade() else {
let Some(zone_node) = zone.spatial.node.upgrade() else {
return;
};
let _ = super::zone_client::capture(&node, &spatial.uid);
let Some(spatial_node) = spatial.node.upgrade() else {
return;
};
let Ok(spatial_alias) = Alias::create(
&spatial_node,
&zone_node.get_client().unwrap(),
SPATIAL_ASPECT_ALIAS_INFO.clone(),
Some(&zone.captured),
) else {
return;
};
let _ = super::zone_client::capture(&zone_node, &spatial_alias);
}
}
pub fn release(spatial: &Arc<Spatial>) {
pub fn release(spatial: &Spatial) {
let Some(spatial_node) = spatial.node.upgrade() else {
return;
};
let spatial = spatial_node.get_aspect::<Spatial>().unwrap();
let _ = spatial.set_spatial_parent_in_place(spatial.old_parent.lock().take().as_ref());
let mut spatial_zone = spatial.zone.lock();
if let Some(spatial_zone) = spatial_zone.upgrade() {
spatial_zone.captured.remove_aspect(spatial.as_ref());
let Some(node) = spatial_zone.spatial.node.upgrade() else {
return;
};
spatial_zone.captured.remove(spatial);
let _ = super::zone_client::release(&node, &spatial.uid);
let _ = super::zone_client::release(&node, spatial_node.id);
}
*spatial_zone = Weak::new();
}
pub(super) fn release_drop(spatial: &Spatial) {
let spatial_zone = spatial.zone.lock();
if let Some(spatial_zone) = spatial_zone.upgrade() {
let Some(node) = spatial_zone.spatial.node.upgrade() else {
return;
};
spatial_zone.captured.remove(spatial);
let _ = super::zone_client::release(&node, &spatial.uid);
}
}
pub struct Zone {
spatial: Arc<Spatial>,
pub field: Weak<Field>,
zoneables: Mutex<FxHashMap<String, Arc<Node>>>,
captured: Registry<Spatial>,
pub field: Arc<Field>,
intersecting_spatials: Registry<Spatial>,
intersecting: AliasList,
captured: AliasList,
}
impl Zone {
pub fn add_to(node: &Arc<Node>, spatial: Arc<Spatial>, field: &Arc<Field>) -> Arc<Zone> {
pub fn add_to(node: &Arc<Node>, spatial: Arc<Spatial>, field: Arc<Field>) -> Arc<Zone> {
let zone = Arc::new(Zone {
spatial,
field: Arc::downgrade(field),
zoneables: Mutex::new(FxHashMap::default()),
captured: Registry::new(),
field,
intersecting_spatials: Registry::default(),
intersecting: AliasList::default(),
captured: AliasList::default(),
});
<Zone as ZoneAspect>::add_node_members(node);
node.add_aspect_raw(zone.clone());
zone
}
pub fn update(&self) -> Result<()> {
let node = self.spatial.node().unwrap();
let current_zoneables = Registry::new();
for zoneable in ZONEABLE_REGISTRY.get_valid_contents() {
let distance = self.field.distance(&zoneable, [0.0; 3].into());
if distance > 0.0 {
continue;
}
if let Some(zone) = zoneable.zone.lock().upgrade() {
let zoneable_distance = zone.field.distance(&zoneable, [0.0; 3].into());
if zoneable_distance < distance {
continue;
}
}
current_zoneables.add_raw(&zoneable);
}
let (added, removed) =
Registry::get_changes(&self.intersecting_spatials, &current_zoneables);
for added in added {
let Some(added_node) = added.node() else {
continue;
};
let Ok(alias) = Alias::create(
&added_node,
&self.spatial.node().unwrap().get_client().unwrap(),
SPATIAL_REF_ASPECT_ALIAS_INFO.clone(),
Some(&self.intersecting),
) else {
continue;
};
let _ = super::zone_client::enter(&node, &alias);
}
for removed in removed {
let Some(removed_node) = removed.node() else {
continue;
};
release(&removed);
let _ = super::zone_client::leave(&node, removed_node.id);
self.intersecting.remove_aspect(removed.as_ref());
}
self.intersecting_spatials.set(&current_zoneables);
Ok(())
}
}
impl Aspect for Zone {
const NAME: &'static str = "Zone";
}
impl ZoneAspect for Zone {
fn update(node: Arc<Node>, _calling_client: Arc<Client>) -> color_eyre::eyre::Result<()> {
fn update(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
let zone = node.get_aspect::<Zone>()?;
let Some(field) = zone.field.upgrade() else {
return Err(color_eyre::eyre::eyre!("Zone's field has been destroyed"));
};
let Some((zone_client, zone_node)) = zone
.spatial
.node
.upgrade()
.and_then(|n| n.get_client().zip(Some(n)))
else {
return Err(color_eyre::eyre::eyre!("No client on node?"));
};
let mut old_zoneables = zone.zoneables.lock();
for (_uid, zoneable) in old_zoneables.iter() {
zoneable.destroy();
}
let captured = zone.captured.get_valid_contents();
let zoneables = ZONEABLE_REGISTRY
.get_valid_contents()
.into_iter()
.filter(|zoneable| zoneable.node.upgrade().is_some())
.filter(|zoneable| {
if captured
.iter()
.any(|captured| Arc::ptr_eq(captured, zoneable))
{
return true;
}
let spatial_zone_distance = zoneable.zone_distance();
let self_zone_distance = field.distance(zoneable, vec3a(0.0, 0.0, 0.0));
self_zone_distance < 0.0 && spatial_zone_distance > self_zone_distance
})
.filter_map(|zoneable| {
let alias = Alias::create(
&zone_client,
zone_node.get_path(),
&zoneable.uid,
&zoneable.node.upgrade().unwrap(),
AliasInfo {
server_signals: vec![
"set_transform",
"set_spatial_parent",
"set_spatial_parent_in_place",
],
server_methods: vec!["get_bounds", "get_transform"],
..Default::default()
},
)
.ok()?;
Some((zoneable.uid.clone(), alias))
})
.collect::<FxHashMap<String, Arc<Node>>>();
for (uid, zoneable) in zoneables
.iter()
.filter(|(k, _)| !old_zoneables.contains_key(*k))
{
super::zone_client::enter(&node, uid, zoneable)?;
}
for left_uid in old_zoneables.keys().filter(|k| !zoneables.contains_key(*k)) {
super::zone_client::leave(&node, &left_uid)?;
}
*old_zoneables = zoneables;
let _ = zone.update();
Ok(())
}
fn capture(
node: Arc<Node>,
_calling_client: Arc<Client>,
spatial: Arc<Node>,
) -> color_eyre::eyre::Result<()> {
fn capture(node: Arc<Node>, _calling_client: Arc<Client>, spatial: Arc<Node>) -> Result<()> {
let zone = node.get_aspect::<Zone>()?;
let spatial = spatial.get_aspect()?;
capture(&spatial, &zone);
Ok(())
}
fn release(
_node: Arc<Node>,
_calling_client: Arc<Client>,
spatial: Arc<Node>,
) -> color_eyre::eyre::Result<()> {
fn release(_node: Arc<Node>, _calling_client: Arc<Client>, spatial: Arc<Node>) -> Result<()> {
let spatial = spatial.get_aspect()?;
release(&spatial);
Ok(())
@@ -168,7 +149,13 @@ impl ZoneAspect for Zone {
}
impl Drop for Zone {
fn drop(&mut self) {
for captured in self.captured.get_valid_contents() {
for captured in self
.captured
.get_aliases()
.into_iter()
.filter_map(get_original)
.filter_map(|n| n.get_aspect::<Spatial>().ok())
{
release(&captured);
}
}

View File

@@ -9,7 +9,6 @@ use crate::{
};
use color_eyre::eyre::Result;
use glam::{vec3, Mat4};
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use stardust_xr::values::Datamap;
use std::sync::Arc;
@@ -34,8 +33,7 @@ pub struct EyePointer {
}
impl EyePointer {
pub fn new() -> Result<Self> {
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
.add_to_scenegraph()?;
let node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
let pointer = InputMethod::add_to(
&node,
@@ -62,7 +60,7 @@ impl EyePointer {
.into_iter()
// filter out all the disabled handlers
.filter(|handler| {
let Some(node) = handler.node.upgrade() else {
let Some(node) = handler.spatial.node() else {
return false;
};
node.enabled()

View File

@@ -4,7 +4,7 @@ use crate::{
data::{
mask_matches, pulse_receiver_client, PulseSender, KEYMAPS, PULSE_RECEIVER_REGISTRY,
},
fields::{Field, Ray},
fields::Ray,
input::{InputDataType, InputHandler, InputMethod, Pointer, INPUT_HANDLER_REGISTRY},
spatial::Spatial,
Node,
@@ -13,8 +13,8 @@ use crate::{
use color_eyre::eyre::Result;
use glam::{vec3, Mat4, Vec3};
use mint::Vector2;
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use slotmap::DefaultKey;
use stardust_xr::values::Datamap;
use std::sync::Arc;
use stereokit_rust::system::{Input, Key};
@@ -62,8 +62,10 @@ impl Default for KeyboardEvent {
}
}
#[allow(unused)]
pub struct MousePointer {
node: Arc<Node>,
keymap: DefaultKey,
spatial: Arc<Spatial>,
pointer: Arc<InputMethod>,
capture: Option<Arc<InputHandler>>,
@@ -73,8 +75,7 @@ pub struct MousePointer {
}
impl MousePointer {
pub fn new() -> Result<Self> {
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
.add_to_scenegraph()?;
let node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
let pointer = InputMethod::add_to(
&node,
@@ -82,8 +83,7 @@ impl MousePointer {
Datamap::from_typed(MouseEvent::default())?,
)?;
KEYMAPS.lock().insert(
"flatscreen".to_string(),
let keymap = KEYMAPS.lock().insert(
Keymap::new_from_names(&Context::new(0), "evdev", "", "", "", None, 0)
.unwrap()
.get_as_string(FORMAT_TEXT_V1),
@@ -97,6 +97,7 @@ impl MousePointer {
Ok(MousePointer {
node,
keymap,
spatial,
pointer,
capture: None,
@@ -206,7 +207,7 @@ impl MousePointer {
.into_iter()
// filter out all the disabled handlers
.filter(|handler| {
let Some(node) = handler.node.upgrade() else {
let Some(node) = handler.spatial.node() else {
return false;
};
node.enabled()
@@ -253,7 +254,7 @@ impl MousePointer {
.into_iter()
.filter(|rx| mask_matches(&rx.mask, &self.keyboard_sender.mask))
.map(|rx| {
let result = rx.field_node.get_aspect::<Field>().unwrap().ray_march(Ray {
let result = rx.field.ray_march(Ray {
origin: vec3(0.0, 0.0, 0.0),
direction: vec3(0.0, 0.0, -1.0),
space: self.spatial.clone(),
@@ -291,7 +292,7 @@ impl MousePointer {
if !self.keyboard_datamap.keys.is_empty() {
pulse_receiver_client::data(
&rx.node.upgrade().unwrap(),
&self.node.uid,
&self.node,
&Datamap::from_typed(&self.keyboard_datamap).unwrap(),
)
.unwrap();

View File

@@ -34,17 +34,7 @@ pub struct SkController {
}
impl SkController {
pub fn new(handed: Handed) -> Result<Self> {
let _node = Node::create_parent_name(
&INTERNAL_CLIENT,
"",
if handed == Handed::Left {
"controller_left"
} else {
"controller_right"
},
false,
)
.add_to_scenegraph()?;
let _node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
let model = Model::from_memory("cursor.glb", include_bytes!("cursor.glb"), None)?;
let tip = InputDataType::Tip(Tip::default());
@@ -135,7 +125,7 @@ impl SkController {
.into_iter()
// filter out all the disabled handlers
.filter(|handler| {
let Some(node) = handler.node.upgrade() else {
let Some(node) = handler.spatial.node() else {
return false;
};
node.enabled()

View File

@@ -8,7 +8,6 @@ use crate::nodes::{
};
use color_eyre::eyre::Result;
use glam::{Mat4, Quat, Vec3};
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use stardust_xr::values::Datamap;
use std::f32::INFINITY;
@@ -41,8 +40,7 @@ pub struct SkHand {
}
impl SkHand {
pub fn new(handed: Handed) -> Result<Self> {
let _node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
.add_to_scenegraph()?;
let _node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
Spatial::add_to(&_node, None, Mat4::IDENTITY, false);
let hand = InputDataType::Hand(Hand {
right: handed == Handed::Right,
@@ -156,7 +154,7 @@ impl SkHand {
.into_iter()
// filter out all the disabled handlers
.filter(|handler| {
let Some(node) = handler.node.upgrade() else {
let Some(node) = handler.spatial.node() else {
return false;
};
node.enabled()

View File

@@ -3,7 +3,6 @@ use std::sync::Arc;
use color_eyre::eyre::Result;
use glam::Mat4;
use mint::Vector2;
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use stardust_xr::values::Datamap;
use stereokit_rust::system::World;
@@ -40,15 +39,14 @@ pub struct PlaySpace {
}
impl PlaySpace {
pub fn new() -> Result<Self> {
let node = Node::create_parent_name(&INTERNAL_CLIENT, "", &nanoid!(), false)
.add_to_scenegraph()?;
let node = Node::generate(&INTERNAL_CLIENT, false).add_to_scenegraph()?;
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
BoxField::add_to(&node, [0.0; 3].into());
let field = node.get_aspect::<Field>()?.clone();
let pulse_rx = PulseReceiver::add_to(
&node,
node.clone(),
field.clone(),
Datamap::from_typed(PlaySpaceMap::default())?,
)?;

View File

@@ -9,6 +9,7 @@ use crate::{
use mint::Vector2;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use slotmap::KeyData;
use smithay::{
backend::input::{AxisRelativeDirection, ButtonState, KeyState},
delegate_seat,
@@ -212,7 +213,7 @@ impl SeatWrapper {
pointer.frame(&mut state);
}
pub fn keyboard_keys(&self, surface: WlSurface, keymap_id: &str, keys: Vec<i32>) {
pub fn keyboard_keys(&self, surface: WlSurface, keymap_id: u64, keys: Vec<i32>) {
let Some(state) = self.wayland_state.upgrade() else {
return;
};
@@ -220,7 +221,7 @@ impl SeatWrapper {
return;
};
let keymaps = KEYMAPS.lock();
let Some(keymap) = keymaps.get(keymap_id).cloned() else {
let Some(keymap) = keymaps.get(KeyData::from_ffi(keymap_id).into()).cloned() else {
return;
};

View File

@@ -13,6 +13,7 @@ use crate::nodes::{
use color_eyre::eyre::Result;
use mint::Vector2;
use parking_lot::Mutex;
use rand::Rng;
use rustc_hash::FxHashMap;
use smithay::{
delegate_xdg_shell,
@@ -184,7 +185,7 @@ impl XdgShellHandler for WaylandState {
}
fn new_popup(&mut self, popup: PopupSurface, positioner: PositionerState) {
let uid = nanoid::nanoid!();
let uid = rand::thread_rng().gen_range(0..u64::MAX);
let Some(parent) = popup.get_parent_surface() else {
return;
};
@@ -194,8 +195,8 @@ impl XdgShellHandler for WaylandState {
if popup.send_configure().is_err() {
return;
}
utils::insert_data(popup.wl_surface(), SurfaceId::Child(uid.clone()));
utils::insert_data(popup.wl_surface(), uid.clone());
utils::insert_data(popup.wl_surface(), SurfaceId::Child(uid));
utils::insert_data(popup.wl_surface(), uid);
utils::insert_data(popup.wl_surface(), Arc::downgrade(&panel_item));
CoreSurface::add_to(
self.display_handle.clone(),
@@ -203,9 +204,7 @@ impl XdgShellHandler for WaylandState {
{
let popup = popup.clone();
move || {
panel_item
.backend
.new_popup(&uid, popup.clone(), positioner);
panel_item.backend.new_popup(uid, popup.clone(), positioner);
}
},
{
@@ -228,14 +227,14 @@ impl XdgShellHandler for WaylandState {
let Some(panel_item) = surface_panel_item(popup.wl_surface()) else {
return;
};
let Some(uid) = utils::get_data::<String>(popup.wl_surface())
let Some(SurfaceId::Child(uid)) = utils::get_data::<SurfaceId>(popup.wl_surface())
.as_deref()
.cloned()
else {
return;
};
panel_item.backend.reposition_popup(&uid, popup, positioner)
panel_item.backend.reposition_popup(uid, popup, positioner)
}
fn popup_destroyed(&mut self, popup: PopupSurface) {
if let Some(core_surface) = CoreSurface::from_wl_surface(popup.wl_surface()) {
@@ -244,14 +243,14 @@ impl XdgShellHandler for WaylandState {
let Some(panel_item) = surface_panel_item(popup.wl_surface()) else {
return;
};
let Some(uid) = utils::get_data::<String>(popup.wl_surface())
let Some(SurfaceId::Child(uid)) = utils::get_data::<SurfaceId>(popup.wl_surface())
.as_deref()
.cloned()
else {
return;
};
panel_item.backend.seat.unfocus(popup.wl_surface(), self);
panel_item.backend.drop_popup(&uid);
panel_item.backend.drop_popup(uid);
}
fn grab(&mut self, _popup: PopupSurface, _seat: WlSeat, _serial: Serial) {}
@@ -330,7 +329,7 @@ delegate_xdg_shell!(WaylandState);
pub struct XdgBackend {
toplevel: Mutex<Option<ToplevelSurface>>,
popups: Mutex<FxHashMap<String, (PopupSurface, PositionerState)>>,
popups: Mutex<FxHashMap<u64, (PopupSurface, PositionerState)>>,
pub seat: Arc<SeatWrapper>,
}
impl XdgBackend {
@@ -354,20 +353,18 @@ impl XdgBackend {
surface_panel_item(self.toplevel.lock().clone()?.wl_surface())
}
pub fn new_popup(&self, uid: &str, popup: PopupSurface, positioner: PositionerState) {
pub fn new_popup(&self, id: u64, popup: PopupSurface, positioner: PositionerState) {
let Some(panel_item) = self.panel_item() else {
return;
};
self.popups
.lock()
.insert(uid.to_string(), (popup, positioner));
self.popups.lock().insert(id, (popup, positioner));
panel_item.create_child(uid, self.child_data(uid).unwrap());
panel_item.create_child(id, &self.child_data(id).unwrap());
}
pub fn reposition_popup(&self, uid: &str, _popup: PopupSurface, positioner: PositionerState) {
pub fn reposition_popup(&self, id: u64, _popup: PopupSurface, positioner: PositionerState) {
let mut popups = self.popups.lock();
let Some((_, old_positioner)) = popups.get_mut(uid) else {
let Some((_, old_positioner)) = popups.get_mut(&id) else {
return;
};
let Some(panel_item) = self.panel_item() else {
@@ -376,18 +373,19 @@ impl XdgBackend {
let geometry = positioner.get_geometry();
*old_positioner = positioner;
panel_item.reposition_child(uid, geometry.into());
panel_item.reposition_child(id, &geometry.into());
}
pub fn drop_popup(&self, uid: &str) {
pub fn drop_popup(&self, id: u64) {
let Some(panel_item) = self.panel_item() else {
return;
};
panel_item.destroy_child(uid);
panel_item.destroy_child(id);
}
fn child_data(&self, uid: &str) -> Option<ChildInfo> {
let (popup, positioner) = self.popups.lock().get(uid)?.clone();
fn child_data(&self, id: u64) -> Option<ChildInfo> {
let (popup, positioner) = self.popups.lock().get(&id)?.clone();
Some(ChildInfo {
id,
parent: (*utils::get_data::<SurfaceId>(&popup.get_parent_surface()?)?).clone(),
geometry: positioner.get_geometry().into(),
})
@@ -443,12 +441,14 @@ impl Backend for XdgBackend {
.map(|s| Vector2::from([s.w as u32, s.h as u32]))
.or_else(|| toplevel_core_surface.size())
.unwrap_or(Vector2::from([0; 2]));
let toplevel = ToplevelInfo {
parent: toplevel
let parent = toplevel
.parent()
.as_ref()
.and_then(surface_panel_item)
.map(|p| p.uid.clone()),
.and_then(|p| p.node.upgrade())
.map(|p| p.get_id());
let toplevel = ToplevelInfo {
parent,
title,
app_id,
size,
@@ -491,7 +491,7 @@ impl Backend for XdgBackend {
.popups
.lock()
.keys()
.map(|k| (k.clone(), self.child_data(k).unwrap()))
.map(|k| self.child_data(*k).unwrap())
.collect();
Ok(PanelItemInitData {
@@ -588,7 +588,7 @@ impl Backend for XdgBackend {
self.seat.pointer_scroll(scroll_distance, scroll_steps)
}
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>) {
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec<i32>) {
let Some(surface) = self.wl_surface_from_id(&surface) else {
return;
};