From 8d2aac12d685502b4e2152fe34678a05a4b16653 Mon Sep 17 00:00:00 2001 From: Nova Date: Wed, 5 Jun 2024 14:34:45 -0400 Subject: [PATCH] feat: upgrade to numerical IDs --- .lapce/run.toml | 6 +- Cargo.lock | 100 ++++++---- Cargo.toml | 2 + codegen/src/lib.rs | 172 ++++++++--------- src/core/client.rs | 48 ++--- src/core/client_state.rs | 46 ++--- src/core/idl_utils.rs | 6 +- src/core/mod.rs | 1 - src/core/node_collections.rs | 83 --------- src/core/registry.rs | 34 ++++ src/core/scenegraph.rs | 31 ++-- src/main.rs | 6 +- src/nodes/alias.rs | 107 ++++++++--- src/nodes/audio.rs | 9 +- src/nodes/data.rs | 97 ++++------ src/nodes/drawable/mod.rs | 19 +- src/nodes/drawable/model.rs | 125 +++++++------ src/nodes/fields/mod.rs | 59 +++--- src/nodes/hmd.rs | 27 +-- src/nodes/input/handler.rs | 25 +-- src/nodes/input/method.rs | 75 +++----- src/nodes/input/mod.rs | 22 +-- src/nodes/items/camera.rs | 62 +++---- src/nodes/items/mod.rs | 288 ++++++++++++----------------- src/nodes/items/panel.rs | 111 ++++------- src/nodes/mod.rs | 68 +++---- src/nodes/root.rs | 167 ++++++++--------- src/nodes/spatial/mod.rs | 32 ++-- src/nodes/spatial/zone.rs | 203 ++++++++++---------- src/objects/input/eye_pointer.rs | 6 +- src/objects/input/mouse_pointer.rs | 19 +- src/objects/input/sk_controller.rs | 14 +- src/objects/input/sk_hand.rs | 6 +- src/objects/play_space.rs | 6 +- src/wayland/seat.rs | 5 +- src/wayland/xdg_shell.rs | 60 +++--- 36 files changed, 978 insertions(+), 1169 deletions(-) delete mode 100644 src/core/node_collections.rs diff --git a/.lapce/run.toml b/.lapce/run.toml index 2f04861..6755a3b 100644 --- a/.lapce/run.toml +++ b/.lapce/run.toml @@ -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] diff --git a/Cargo.lock b/Cargo.lock index 361b88a..755bcf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", ] diff --git a/Cargo.toml b/Cargo.toml index da868c8..2969008 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 96f48d6..b8572ba 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -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, path: String, destroyable: bool) -> Self { -// #node_name(crate::node::Node::from_path(client, path, destroyable)) -// } -// } -// impl serde::Serialize for #node_name { -// fn serialize(&self, serializer: S) -> Result { -// 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)> { + _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) } } + 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) diff --git a/src/core/client.rs b/src/core/client.rs index aeb57fe..1193e40 100644 --- a/src/core/client.rs +++ b/src/core/client.rs @@ -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, std::io::Error> { .map(|(k, v)| (k.to_string(), v.to_string())), )) } -pub fn state(env: &FxHashMap) -> Option> { +pub fn state(env: &FxHashMap) -> Option> { let token = env.get("STARDUST_STARTUP_TOKEN")?; CLIENT_STATES.lock().get(token).cloned() } @@ -60,11 +63,12 @@ pub struct Client { flush_join_handle: OnceCell>>, disconnect_status: OnceCell>, + id_counter: CounterU32, pub message_sender_handle: Option, pub scenegraph: Arc, pub root: OnceCell>, pub base_resource_prefixes: Mutex>, - pub state: Arc, + pub state: OnceCell, } impl Client { pub fn from_connection(connection: UnixStream) -> Result> { @@ -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 { + pub async fn save_state(&self) -> Option { 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> { + pub fn get_node(&self, name: &'static str, id: u64) -> Result> { self.scenegraph - .get_node(path) + .get_node(id) .ok_or_else(|| eyre!("{} not found", name)) } diff --git a/src/core/client_state.rs b/src/core/client_state.rs index 8e0f757..ad99980 100644 --- a/src/core/client_state.rs +++ b/src/core/client_state.rs @@ -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>> = Default::default(); + pub static ref CLIENT_STATES: Mutex>> = 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, pub data: Vec, pub root: Mat4, pub spatial_anchors: FxHashMap, } -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 { - let node = client.scenegraph.get_node(path)?; + fn spatial_transform(client: &Client, id: u64) -> Option { + let node = client.scenegraph.get_node(id)?; let spatial = node.get_aspect::().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) -> ClientStateInternal { + pub fn apply_to(&self, client: &Arc) -> 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(); - Spatial::add_to(&node, None, *v, false); - k.clone() - }) + let node = Node::generate(client, true).add_to_scenegraph().unwrap(); + Spatial::add_to(&node, None, *v, false); + (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>, - root: Option, - spatial_anchors: FxHashMap, -} diff --git a/src/core/idl_utils.rs b/src/core/idl_utils.rs index df881ea..e84d53c 100644 --- a/src/core/idl_utils.rs +++ b/src/core/idl_utils.rs @@ -1,9 +1,9 @@ #[macro_export] macro_rules! create_interface { - ($iface:ident, $aspect:ident, $path:expr) => { + ($iface:ident) => { pub fn create_interface(client: &Arc) -> 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(()) } diff --git a/src/core/mod.rs b/src/core/mod.rs index e42ebf5..a3d2763 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -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; diff --git a/src/core/node_collections.rs b/src/core/node_collections.rs deleted file mode 100644 index 169373c..0000000 --- a/src/core/node_collections.rs +++ /dev/null @@ -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>>, -// } -// impl LifeLinkedNodeList { -// pub fn add(&self, node: Weak) { -// 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 { - nodes: Mutex>>, -} -#[allow(dead_code)] -impl LifeLinkedNodeMap { - pub fn add(&self, key: K, node: &Arc) { - self.nodes.lock().insert(key, Arc::downgrade(node)); - } - pub fn get(&self, key: &Q) -> Option> - where - Q: ?Sized, - K: Borrow, - Q: Hash + Eq, - { - self.nodes.lock().get(key).and_then(|n| n.upgrade()) - } - pub fn nodes(&self) -> Vec> { - self.nodes - .lock() - .values() - .filter_map(|v| v.upgrade()) - .collect() - } - pub fn remove(&self, key: &Q) -> Option> - where - Q: ?Sized, - K: Borrow, - 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 Drop for LifeLinkedNodeMap { - fn drop(&mut self) { - self.clear(); - } -} diff --git a/src/core/registry.rs b/src/core/registry.rs index 7916cc0..f42d968 100644 --- a/src/core/registry.rs +++ b/src/core/registry.rs @@ -33,12 +33,38 @@ impl Registry { self.lock() .contains_key(&(ptr::addr_of!(*t) as *const () as usize)) } + pub fn get_changes(old: &Registry, new: &Registry) -> (Vec>, Vec>) { + 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> { self.lock() .iter() .filter_map(|pair| pair.1.upgrade()) .collect() } + pub fn set(&self, other: &Registry) { + *self.lock() = other.lock().clone(); + } pub fn take_valid_contents(&self) -> Vec> { self.0 .lock() @@ -48,6 +74,14 @@ impl Registry { .filter_map(|pair| pair.1.upgrade()) .collect() } + pub fn retain 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)); diff --git a/src/core/scenegraph.rs b/src/core/scenegraph.rs index 587c5dd..2c10536 100644 --- a/src/core/scenegraph.rs +++ b/src/core/scenegraph.rs @@ -19,7 +19,7 @@ use tracing::{debug, debug_span}; #[derive(Default)] pub struct Scenegraph { pub(super) client: OnceCell>, - nodes: Mutex>>, + nodes: Mutex>>, } impl Scenegraph { @@ -34,12 +34,11 @@ impl Scenegraph { } pub fn add_node_raw(&self, node: Arc) { 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> { - let mut node = self.nodes.lock().get(path)?.clone(); + pub fn get_node(&self, node: u64) -> Option> { + let mut node = self.nodes.lock().get(&node)?.clone(); while let Ok(alias) = node.get_aspect::() { 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> { - debug!(path, "Remove node"); - self.nodes.lock().remove(path) + pub fn remove_node(&self, node: u64) -> Option> { + debug!(node, "Remove node"); + self.nodes.lock().remove(&node) } } @@ -94,16 +93,16 @@ fn map_method_return( impl scenegraph::Scenegraph for Scenegraph { fn send_signal( &self, - path: &str, - method: &str, + node: u64, + method: u64, data: &[u8], fds: Vec, ) -> 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, response: oneshot::Sender, Vec), 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; }; diff --git a/src/main.rs b/src/main.rs index 02e1da7..9109529 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, diff --git a/src/nodes/alias.rs b/src/nodes/alias.rs index 1856892..5493c1f 100644 --- a/src/nodes/alias.rs +++ b/src/nodes/alias.rs @@ -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, + pub(super) server_methods: Vec, + pub(super) client_signals: Vec, +} +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, pub(super) node: Weak, @@ -21,32 +32,86 @@ pub struct Alias { } impl Alias { pub fn create( - client: &Arc, - parent: &str, - name: &str, original: &Arc, + client: &Arc, info: AliasInfo, + list: Option<&AliasList>, ) -> Result> { - 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, + client: &Arc, + new_id: u64, + info: AliasInfo, + list: Option<&AliasList>, + ) -> Result> { + 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, original: &Arc, 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) -> Option> { + let Ok(alias) = node.get_aspect::() else { + return Some(node); + }; + get_original(alias.original.upgrade()?) +} + +#[derive(Debug, Default, Clone)] +pub struct AliasList(Registry); +impl AliasList { + fn add(&self, node: &Arc) { + self.0.add_raw(node); + } + pub fn get(&self, aspect: &A) -> Option> { + self.0.get_valid_contents().into_iter().find(|node| { + let Ok(aspect2) = node.get_aspect::() else { + return false; + }; + Arc::as_ptr(&aspect2) != (aspect as *const A) + }) + } + pub fn get_aliases(&self) -> Vec> { + self.0.get_valid_contents() + } + pub fn remove_aspect(&self, aspect: &A) { + self.0.retain(|node| { + let Ok(aspect2) = node.get_aspect::() 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(); + } + } +} diff --git a/src/nodes/audio.rs b/src/nodes/audio.rs index cb71d19..76ea51f 100644 --- a/src/nodes/audio.rs +++ b/src/nodes/audio.rs @@ -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, calling_client: Arc, - name: String, + id: u64, parent: Arc, 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::()?; let transform = transform.to_mat4(true, true, true); let node = node.add_to_scenegraph()?; diff --git a/src/nodes/data.rs b/src/nodes/data.rs index 7a21e2c..0f8110f 100644 --- a/src/nodes/data.rs +++ b/src/nodes/data.rs @@ -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> = Mutex::new(FxHashMap::default()); + pub static ref KEYMAPS: Mutex> = Mutex::new(SlotMap::default()); } static PULSE_SENDER_REGISTRY: Registry = Registry::new(); @@ -58,14 +56,16 @@ stardust_xr_server_codegen::codegen_data_protocol!(); pub struct PulseSender { node: Weak, pub mask: Datamap, - aliases: LifeLinkedNodeMap, + aliases: AliasList, + field_aliases: AliasList, } impl PulseSender { pub fn add_to(node: &Arc, mask: Datamap) -> Result> { let sender = PulseSender { node: Arc::downgrade(node), mask, - aliases: LifeLinkedNodeMap::default(), + aliases: AliasList::default(), + field_aliases: AliasList::default(), }; // ::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::() + .unwrap() + .field + .spatial_ref() + .node() + .unwrap(), &tx_client, - rx_alias.get_path(), - "field", - &rx_node.get_aspect::().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, - pub field_node: Arc, + pub field: Arc, pub mask: Datamap, } impl PulseReceiver { pub fn add_to( node: &Arc, - field_node: Arc, + field: Arc, mask: Datamap, ) -> Result> { 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, 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::()?; let transform = transform.to_mat4(true, true, false); @@ -229,22 +219,17 @@ impl DataInterfaceAspect for DataInterface { fn create_pulse_receiver( _node: Arc, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, field: Arc, 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::()?; let transform = parse_transform(transform, true, true, false); - let _ = field.get_aspect::()?; + let field = field.get_aspect::()?; 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, _calling_client: Arc, keymap: String, - ) -> Result { + ) -> Result { 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, _calling_client: Arc, - keymap_id: String, + keymap_id: u64, ) -> Result { 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") }; diff --git a/src/nodes/drawable/mod.rs b/src/nodes/drawable/mod.rs index b9ae802..db10b87 100644 --- a/src/nodes/drawable/mod.rs +++ b/src/nodes/drawable/mod.rs @@ -40,10 +40,10 @@ static QUEUED_SKYLIGHT: Mutex> = Mutex::new(None); static QUEUED_SKYTEX: Mutex> = 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, calling_client: Arc, 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, lines: Vec, ) -> 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::()?; let transform = transform.to_mat4(true, true, true); @@ -84,13 +83,12 @@ impl DrawableInterfaceAspect for DrawableInterface { fn load_model( _node: Arc, calling_client: Arc, - name: String, + id: u64, parent: Arc, 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::()?; 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, 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::()?; let transform = transform.to_mat4(true, true, true); diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index cec4313..de2aede 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -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 = Registry::new(); static HOLDOUT_MATERIAL: OnceCell>> = OnceCell::new(); @@ -69,11 +69,12 @@ impl MaterialParameter { pub struct ModelPart { id: i32, - path: PathBuf, + path: String, space: Arc, model: Weak, pending_material_parameters: Mutex>, pending_material_replacement: Mutex>>>, + aliases: AliasList, } impl ModelPart { fn create_for_model(model: &Arc, sk_model: &SKModel) { @@ -91,26 +92,21 @@ impl ModelPart { } fn create(model: &Arc, part: &stereokit_rust::model::ModelNode) -> Option> { - 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::().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::().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,29 +117,25 @@ impl ModelPart { false, ); - let _ = node - .get_aspect::() - .unwrap() - .bounding_box_calc - .set(|node| { - let Ok(model_part) = node.get_aspect::() else { - return Bounds::default(); - }; - let Some(model) = model_part.model.upgrade() else { - return Bounds::default(); - }; - 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 { - return Bounds::default(); - }; - let Some(sk_mesh) = model_node.get_mesh() else { - return Bounds::default(); - }; - sk_mesh.get_bounds() - }); + let _ = space.bounding_box_calc.set(|node| { + let Ok(model_part) = node.get_aspect::() else { + return Bounds::default(); + }; + let Some(model) = model_part.model.upgrade() else { + return Bounds::default(); + }; + let Some(sk_model) = model.sk_model.get() else { + return Bounds::default(); + }; + 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 { + return Bounds::default(); + }; + sk_mesh.get_bounds() + }); let model_part = Arc::new(ModelPart { id: *part.get_id(), @@ -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(), }); ::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, _resource_id: ResourceID, sk_model: OnceCell, - parts: LifeLinkedNodeMap, + parts: Mutex>>, } - impl Model { pub fn add_to(node: &Arc, resource_id: ResourceID) -> Result> { let pending_model_path = get_resource_file( @@ -272,8 +264,9 @@ impl Model { space: node.get_aspect::().unwrap().clone(), _resource_id: resource_id, sk_model: OnceCell::new(), - parts: LifeLinkedNodeMap::default(), + parts: Mutex::new(Vec::default()), }); + ::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::() { - model_node.update(); - }; + 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, + calling_client: Arc, + id: u64, + part_path: String, + ) -> color_eyre::eyre::Result<()> { + let model = node.get_aspect::()?; + 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::>(); + 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); } } diff --git a/src/nodes/fields/mod.rs b/src/nodes/fields/mod.rs index 5febc66..2006b63 100644 --- a/src/nodes/fields/mod.rs +++ b/src/nodes/fields/mod.rs @@ -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 = 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, size: mint::Vector3, ) -> Result<()> { let transform = transform.to_mat4(true, true, false); let parent = parent.get_aspect::()?; - 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, 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::()?; - 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, position: mint::Vector3, radius: f32, ) -> Result<()> { let parent = parent.get_aspect::()?; - 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, 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::()?; - 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(()) diff --git a/src/nodes/hmd.rs b/src/nodes/hmd.rs index c7490e1..e152057 100644 --- a/src/nodes/hmd.rs +++ b/src/nodes/hmd.rs @@ -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 { - 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::().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) -> Result> { - 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) } diff --git a/src/nodes/input/handler.rs b/src/nodes/input/handler.rs index 1d68302..7800348 100644 --- a/src/nodes/input/handler.rs +++ b/src/nodes/input/handler.rs @@ -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, pub spatial: Arc, pub field: Arc, - pub(super) method_aliases: LifeLinkedNodeMap, + pub(super) method_aliases: AliasList, } impl InputHandler { pub fn add_to(node: &Arc, field: &Arc) -> Result<()> { let handler = InputHandler { - uid: node.uid.clone(), - node: Arc::downgrade(node), spatial: node.get_aspect::().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), ); } } diff --git a/src/nodes/input/method.rs b/src/nodes/input/method.rs index 6c45976..c793df9 100644 --- a/src/nodes/input/method.rs +++ b/src/nodes/input/method.rs @@ -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, - pub uid: String, pub enabled: Mutex, pub spatial: Arc, pub data: Mutex, @@ -27,7 +27,8 @@ pub struct InputMethod { pub capture_requests: Registry, pub captures: Registry, - pub(super) handler_aliases: LifeLinkedNodeMap, + handler_aliases: AliasList, + handler_field_aliases: AliasList, pub(super) handler_order: Mutex>>, } impl InputMethod { @@ -38,14 +39,15 @@ impl InputMethod { ) -> Result> { let method = InputMethod { node: Arc::downgrade(node), - uid: node.uid.clone(), enabled: Mutex::new(true), spatial: node.get_aspect::().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 { diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index 93eac5c..4a26cc9 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, initial_data: InputDataType, @@ -93,8 +93,7 @@ impl InputInterfaceAspect for InputInterface { let parent = parent.get_aspect::()?; 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, field: Arc, @@ -113,8 +112,7 @@ impl InputInterfaceAspect for InputInterface { let transform = transform.to_mat4(true, true, true); let field = field.get_aspect::()?; - 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::().ok()) { method_alias.enabled.store(true, Ordering::Release); diff --git a/src/nodes/items/camera.rs b/src/nodes/items/camera.rs index 1320dfe..cf39188 100644 --- a/src/nodes/items/camera.rs +++ b/src/nodes/items/camera.rs @@ -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, apply_to: Registry, } +#[allow(unused)] impl CameraItem { pub fn add_to(node: &Arc, proj_matrix: Mat4, px_size: Vector2) { Item::add_to( node, - nanoid!(), &ITEM_TYPE_INFO_CAMERA, ItemType::Camera(CameraItem { space: node.get_aspect::().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, - ); + // ::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) { - let _ = camera_item_ui_client::create_item(node, uid, item); + pub fn send_ui_item_created(&self, node: &Node, item: &Arc) { + let _ = camera_item_ui_client::create_item(node, item); } - pub fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc) { - let _ = camera_item_acceptor_client::capture_item(node, uid, item); + pub fn send_acceptor_item_created(&self, node: &Node, item: &Arc) { + 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, _calling_client: Arc, item: Arc) -> 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, proj_matrix: ColumnMatrix4, px_size: Vector2, ) -> Result<()> { - let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_CAMERA.type_name); let space = parent.get_aspect::()?; 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::().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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, field: Arc, ) -> Result<()> { create_item_acceptor_flex( calling_client, - name, + id, parent, transform, &ITEM_TYPE_INFO_CAMERA, diff --git a/src/nodes/items/mod.rs b/src/nodes/items/mod.rs index d5f5a05..08547e4 100644 --- a/src/nodes/items/mod.rs +++ b/src/nodes/items/mod.rs @@ -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, acceptor: &Arc) { +fn capture(item: &Arc, acceptor: &Arc) { 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>, pub items: Registry, pub acceptors: Registry, - pub new_acceptor_fn: - fn(node: &Node, uid: &str, acceptor: &Arc, acceptor_field: &Arc), + pub new_acceptor_fn: fn(node: &Node, acceptor: &Arc, acceptor_field: &Arc), } impl Hash for TypeInfo { fn hash(&self, state: &mut H) { @@ -83,7 +63,6 @@ impl Eq for TypeInfo {} pub struct Item { node: Weak, - uid: String, type_info: &'static TypeInfo, captured_acceptor: Mutex>, pub specialization: ItemType, @@ -91,20 +70,18 @@ pub struct Item { impl Item { pub fn add_to( node: &Arc, - uid: String, type_info: &'static TypeInfo, specialization: ItemType, ) -> Arc { 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); + ::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, - parent: &str, - name: &str, - ) -> Result> { + fn make_alias(&self, client: &Arc, alias_list: &AliasList) -> Result> { 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, parent: &str) -> Result> { - self.make_alias_named(client, parent, &self.uid) - } - - fn release_flex( - node: Arc, - _calling_client: Arc, - _message: Message, - ) -> Result<()> { - let item = node.get_aspect::()?; - release(&item); - - Ok(()) - } } impl Aspect for Item { const NAME: &'static str = "Item"; } +impl ItemAspect for Item { + fn release(node: Arc, _calling_client: Arc) -> Result<()> { + let item = node.get_aspect::()?; + 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), } impl ItemType { - fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc) { + fn send_ui_item_created(&self, node: &Node, item: &Arc) { 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) { + fn send_acceptor_item_created(&self, node: &Node, item: &Arc) { 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, type_info: &'static TypeInfo, - item_aliases: LifeLinkedNodeMap, - acceptor_aliases: LifeLinkedNodeMap, - acceptor_field_aliases: LifeLinkedNodeMap, + item_aliases: AliasList, + acceptor_aliases: AliasList, + acceptor_field_aliases: AliasList, } impl ItemUI { fn add_to(node: &Arc, 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, + spatial: Arc, pub type_info: &'static TypeInfo, field: Arc, - accepted_aliases: LifeLinkedNodeMap, + accepted_aliases: AliasList, accepted_registry: Registry, } impl ItemAcceptor { fn add_to(node: &Arc, type_info: &'static TypeInfo, field: Arc) { let acceptor = type_info.acceptors.add(ItemAcceptor { - uid: nanoid!(), - node: Arc::downgrade(node), + spatial: node.get_aspect::().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, calling_client: Arc, message: Message) -> Result<()> { - if !node.enabled.load(Ordering::Relaxed) { - return Ok(()); - } - - let acceptor = node.get_aspect::().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::()?; - capture(&item, &acceptor); - - Ok(()) - } - - fn make_aliases(&self, client: &Arc, parent: &str) -> Result<(Arc, Arc)> { - 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) { - 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, 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, - name: String, + id: u64, parent: Arc, transform: Transform, type_info: &'static TypeInfo, @@ -437,17 +375,19 @@ fn create_item_acceptor_flex( let field = field.get_aspect::()?; 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, item: Arc) -> Result<()> { + let acceptor = node.get_aspect::()?; + let item = item.get_aspect::()?; + capture(&item, &acceptor); + + Ok(()) +} + struct ItemInterface; -// create_interface!(ItemInterface, ItemInterfaceAspect, "/item"); +// create_interface!(ItemInterface); diff --git a/src/nodes/items/panel.rs b/src/nodes/items/panel.rs index e34f97a..daf0ecb 100644 --- a/src/nodes/items/panel.rs +++ b/src/nodes/items/panel.rs @@ -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>, ); - fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec); + fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec); fn touch_down(&self, surface: &SurfaceId, id: u32, position: Vector2); fn touch_move(&self, id: u32, position: Vector2); @@ -101,13 +72,12 @@ pub fn panel_item_from_node(node: &Node) -> Option> { } pub trait PanelItemTrait: Backend + Send + Sync + 'static { - fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc); - fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc); + fn send_ui_item_created(&self, node: &Node, item: &Arc); + fn send_acceptor_item_created(&self, node: &Node, item: &Arc); } pub struct PanelItem { - pub uid: String, - node: Weak, + pub node: Weak, pub backend: Box, } impl PanelItem { @@ -118,20 +88,13 @@ impl PanelItem { .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 PanelItem { let generic_panel_item: Arc = panel_item.clone(); Item::add_to( &node, - uid, &ITEM_TYPE_INFO_PANEL, ItemType::Panel(generic_panel_item), ); @@ -158,7 +120,7 @@ impl PanelItem { // Remote signals #[allow(unused)] impl PanelItem { - 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 PanelItem { } } - 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 PanelItemAspect for PanelItem { node: Arc, _calling_client: Arc, surface: SurfaceId, - keymap_id: String, + keymap_id: u64, keys: Vec, ) -> 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 PanelItemAspect for PanelItem { Ok(()) } } -impl PanelItemTrait for PanelItem { - fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc) { - 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, _calling_client: Arc, item: Arc) -> Result<()> { + super::acceptor_capture_item_flex(node, item) } - fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc) { +} + +impl PanelItemTrait for PanelItem { + fn send_ui_item_created(&self, node: &Node, item: &Arc) { 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) { + let Ok(init_data) = self.backend.start_data() else { + return; + }; + let _ = panel_item_acceptor_client::capture_item(node, item, init_data); } } impl Backend for PanelItem { @@ -488,7 +457,7 @@ impl Backend for PanelItem { .pointer_scroll(surface, scroll_distance, scroll_steps) } - fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec) { + fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec) { self.backend.keyboard_keys(surface, keymap_id, keys) } @@ -508,12 +477,12 @@ impl Backend for PanelItem { impl Drop for PanelItem { 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, calling_client: Arc) -> 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, field: Arc, ) -> Result<()> { create_item_acceptor_flex( calling_client, - name, + id, parent, transform, &ITEM_TYPE_INFO_PANEL, diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index daa3144..d84c7e4 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -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, - pub(super) uid: String, - path: String, + id: u64, client: Weak, message_sender_handle: Option, - // trailing_slash_pos: usize, - local_signals: Mutex>, - local_methods: Mutex>, + + local_signals: Mutex>, + local_methods: Mutex>, aliases: Registry, aspects: Aspects, destroyable: bool, @@ -71,32 +69,19 @@ impl Node { pub fn get_client(&self) -> Option> { 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, - 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, destroyable: bool) -> Self { + Self::from_id(client, client.generate_id(), destroyable) } - pub fn create_path(client: &Arc, path: impl ToString, destroyable: bool) -> Self { + pub fn from_id(client: &Arc, 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(&self, aspect: A) -> Arc { @@ -156,7 +141,7 @@ impl Node { pub fn send_local_signal( self: Arc, calling_client: Arc, - method: &str, + method: u64, message: Message, ) -> Result<(), ScenegraphError> { if let Ok(alias) = self.get_aspect::() { @@ -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, calling_client: Arc, - 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) -> Result<()> { + pub fn send_remote_signal(&self, method: u64, message: impl Into) -> 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( &self, - method: &str, + method: u64, input: S, fds: Vec, ) -> Result<(D, Vec)> { @@ -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 { diff --git a/src/nodes/root.rs b/src/nodes/root.rs index 1ccb8d9..924f8b3 100644 --- a/src/nodes/root.rs +++ b/src/nodes/root.rs @@ -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 = Registry::new(); -pub struct Root { - pub node: Arc, - send_frame_event: AtomicBool, -} +stardust_xr_server_codegen::codegen_root_protocol!(); + +pub struct Root(Arc); impl Root { - pub fn create(client: &Arc) -> Result> { - 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, transform: Mat4) -> Result> { + let node = Node::from_id(client, 0, false); + ::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, - calling_client: Arc, - _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)) { - 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 info = FrameInfo { + delta: delta as f32, + elapsed: 0.0, + }; + for root in ROOT_REGISTRY.get_valid_contents() { + let _ = root_client::frame(&root.0, &info); } } - fn set_base_prefixes_flex( - _node: Arc, - calling_client: Arc, - message: Message, - ) -> Result<()> { - let prefixes: Vec = 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, - calling_client: Arc, - 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::().unwrap(); + let spatial = self.0.get_aspect::().unwrap(); spatial.set_spatial_parent(None).unwrap(); spatial.set_local_transform(transform); } - pub async fn save_state(&self) -> Result { - self.node - .execute_remote_method_typed("save_state", (), Vec::new()) - .await - .map(|(m, _)| m) + pub async fn save_state(&self) -> Result { + 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, calling_client: Arc) -> Result { + let Some(state) = calling_client.state.get() else { + bail!("Couldn't get state"); + }; + Ok(state.clone()) } -} -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, - _calling_client: Arc, - _message: Message, - response: MethodResponseSender, -) { - response.wrap_sync(move || { + #[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, + _calling_client: Arc, + ) -> Result> { + macro_rules! var_env_insert { + ($env:ident, $name:ident) => { + $env.insert(stringify!($name).to_string(), $name.get().unwrap().clone()); + }; + } + let mut env: FxHashMap = 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, + calling_client: Arc, + state: ClientState, + ) -> Result { + 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, + calling_client: Arc, + prefixes: Vec, + ) -> 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, calling_client: Arc) -> color_eyre::eyre::Result<()> { + calling_client.disconnect(Ok(())); + Ok(()) + } +} +impl Drop for Root { + fn drop(&mut self) { + ROOT_REGISTRY.remove(self); + } } diff --git a/src/nodes/spatial/mod.rs b/src/nodes/spatial/mod.rs index 1cd51ff..69469b2 100644 --- a/src/nodes/spatial/mod.rs +++ b/src/nodes/spatial/mod.rs @@ -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 = Registry::new(); pub struct Spatial { - uid: String, - pub(super) node: Weak, + node: Weak, parent: Mutex>>, old_parent: Mutex>>, - pub(super) transform: Mutex, + transform: Mutex, zone: Mutex>, children: Registry, - pub(super) bounding_box_calc: OnceCell Bounds>, + pub bounding_box_calc: OnceCell Bounds>, } impl Spatial { pub fn new(node: Weak, parent: Option>, transform: Mat4) -> Arc { 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, zoneable: bool, ) -> Result<()> { let parent = parent.get_aspect::()?; 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, calling_client: Arc, - name: String, + id: u64, parent: Arc, transform: Transform, field: Arc, @@ -425,12 +420,11 @@ impl SpatialInterfaceAspect for SpatialInterface { let transform = parse_transform(transform, true, true, false); let field = field.get_aspect::()?; - 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); diff --git a/src/nodes/spatial/zone.rs b/src/nodes/spatial/zone.rs index c53fe46..92c96ad 100644 --- a/src/nodes/spatial/zone.rs +++ b/src/nodes/spatial/zone.rs @@ -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, zone: &Arc) { 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) { +pub fn release(spatial: &Spatial) { + let Some(spatial_node) = spatial.node.upgrade() else { + return; + }; + let spatial = spatial_node.get_aspect::().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, - pub field: Weak, - zoneables: Mutex>>, - captured: Registry, + pub field: Arc, + intersecting_spatials: Registry, + intersecting: AliasList, + captured: AliasList, } impl Zone { - pub fn add_to(node: &Arc, spatial: Arc, field: &Arc) -> Arc { + pub fn add_to(node: &Arc, spatial: Arc, field: Arc) -> Arc { 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(), }); ::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, ¤t_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(¤t_zoneables); + + Ok(()) + } } impl Aspect for Zone { const NAME: &'static str = "Zone"; } impl ZoneAspect for Zone { - fn update(node: Arc, _calling_client: Arc) -> color_eyre::eyre::Result<()> { + fn update(node: Arc, _calling_client: Arc) -> Result<()> { let zone = node.get_aspect::()?; - 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::>>(); - - 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, - _calling_client: Arc, - spatial: Arc, - ) -> color_eyre::eyre::Result<()> { + fn capture(node: Arc, _calling_client: Arc, spatial: Arc) -> Result<()> { let zone = node.get_aspect::()?; let spatial = spatial.get_aspect()?; capture(&spatial, &zone); Ok(()) } - fn release( - _node: Arc, - _calling_client: Arc, - spatial: Arc, - ) -> color_eyre::eyre::Result<()> { + fn release(_node: Arc, _calling_client: Arc, spatial: Arc) -> 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::().ok()) + { release(&captured); } } diff --git a/src/objects/input/eye_pointer.rs b/src/objects/input/eye_pointer.rs index e3db7ca..ee4f4f0 100644 --- a/src/objects/input/eye_pointer.rs +++ b/src/objects/input/eye_pointer.rs @@ -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 { - 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() diff --git a/src/objects/input/mouse_pointer.rs b/src/objects/input/mouse_pointer.rs index 9aa3e59..d29a070 100644 --- a/src/objects/input/mouse_pointer.rs +++ b/src/objects/input/mouse_pointer.rs @@ -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, + keymap: DefaultKey, spatial: Arc, pointer: Arc, capture: Option>, @@ -73,8 +75,7 @@ pub struct MousePointer { } impl MousePointer { pub fn new() -> Result { - 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::().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(); diff --git a/src/objects/input/sk_controller.rs b/src/objects/input/sk_controller.rs index 72e9092..a615d3d 100644 --- a/src/objects/input/sk_controller.rs +++ b/src/objects/input/sk_controller.rs @@ -34,17 +34,7 @@ pub struct SkController { } impl SkController { pub fn new(handed: Handed) -> Result { - 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() diff --git a/src/objects/input/sk_hand.rs b/src/objects/input/sk_hand.rs index 6da789f..b1ca256 100644 --- a/src/objects/input/sk_hand.rs +++ b/src/objects/input/sk_hand.rs @@ -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 { - 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() diff --git a/src/objects/play_space.rs b/src/objects/play_space.rs index aa69654..97da224 100644 --- a/src/objects/play_space.rs +++ b/src/objects/play_space.rs @@ -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 { - 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::()?.clone(); let pulse_rx = PulseReceiver::add_to( &node, - node.clone(), + field.clone(), Datamap::from_typed(PlaySpaceMap::default())?, )?; diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs index 8239c15..5b1d62f 100644 --- a/src/wayland/seat.rs +++ b/src/wayland/seat.rs @@ -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) { + pub fn keyboard_keys(&self, surface: WlSurface, keymap_id: u64, keys: Vec) { 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; }; diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index af7acad..4546869 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -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::(popup.wl_surface()) + let Some(SurfaceId::Child(uid)) = utils::get_data::(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::(popup.wl_surface()) + let Some(SurfaceId::Child(uid)) = utils::get_data::(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>, - popups: Mutex>, + popups: Mutex>, pub seat: Arc, } 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 { - let (popup, positioner) = self.popups.lock().get(uid)?.clone(); + fn child_data(&self, id: u64) -> Option { + let (popup, positioner) = self.popups.lock().get(&id)?.clone(); Some(ChildInfo { + id, parent: (*utils::get_data::(&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 parent = toplevel + .parent() + .as_ref() + .and_then(surface_panel_item) + .and_then(|p| p.node.upgrade()) + .map(|p| p.get_id()); let toplevel = ToplevelInfo { - parent: toplevel - .parent() - .as_ref() - .and_then(surface_panel_item) - .map(|p| p.uid.clone()), + 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) { + fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: u64, keys: Vec) { let Some(surface) = self.wl_surface_from_id(&surface) else { return; };