feat: upgrade to numerical IDs

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

View File

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

100
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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