Bevy Rewrite, attempt 2 #46
@@ -24,8 +24,8 @@ path = "src/main.rs"
|
||||
default = []
|
||||
wayland = ["dep:smithay", "dep:wayland-scanner", "dep:wayland-backend"]
|
||||
|
|
||||
profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
|
||||
profile_app = ["dep:tracing-tracy", "bevy/trace_tracy"]
|
||||
change_tracking = ["bevy/track_location"]
|
||||
profile_app = ["dep:tracing-tracy", "bevy/trace_tracy", "bevy/trace"]
|
||||
bevy_debugging = ["bevy/bevy_remote", "bevy/track_location"]
|
||||
|
||||
[package.metadata.appimage]
|
||||
auto_link = true
|
||||
@@ -64,7 +64,7 @@ color-eyre = { version = "0.6.3", default-features = false }
|
||||
clap = { version = "4.5.13", features = ["derive"] }
|
||||
console-subscriber = { version = "0.4.0", optional = true }
|
||||
thiserror = "2.0.9"
|
||||
tracing = "0.1.40"
|
||||
tracing = { version = "0.1.40", features = ["release_max_level_warn"] }
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
tracing-tracy = { version = "0.11.1", optional = true }
|
||||
|
||||
|
🛠️ Refactor suggestion Pin git dependencies to specific commits for reproducible builds. Using branch names without commit hashes can lead to non-reproducible builds as branches can be updated. Add specific commit hashes or tags to ensure reproducible builds: 🤖 Prompt for AI Agents_🛠️ Refactor suggestion_
**Pin git dependencies to specific commits for reproducible builds.**
Using branch names without commit hashes can lead to non-reproducible builds as branches can be updated.
Add specific commit hashes or tags to ensure reproducible builds:
```diff
-bevy_mod_openxr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "non_default_wait_frame_system" }
+bevy_mod_openxr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", rev = "COMMIT_HASH" }
```
<details>
<summary>🤖 Prompt for AI Agents</summary>
```
In Cargo.toml around lines 45 to 48, the git dependencies are specified using
branch names, which can cause non-reproducible builds because branches may
change over time. To fix this, replace the branch specifications with exact
commit hashes or tags for each dependency to ensure builds are reproducible and
consistent.
```
</details>
<!-- This is an auto-generated comment by CodeRabbit -->
<!-- fingerprinting:phantom:medusa:lion -->
|
||||
@@ -79,7 +79,7 @@ mint = "0.5.9"
|
||||
tokio = { version = "1.39.2", features = ["rt-multi-thread", "signal", "time"] }
|
||||
|
||||
# bevy
|
||||
bevy = { version = "0.16", features = ["wayland", "bevy_remote", "mp3", "wav"] }
|
||||
bevy = { version = "0.16", features = ["wayland", "mp3", "wav"] }
|
||||
bevy_mod_xr = "0.3"
|
||||
bevy_mod_openxr = "0.3"
|
||||
# bevy_sk.git = "https://github.com/MalekiRe/bevy_sk"
|
||||
|
||||
@@ -21,8 +21,6 @@ use bevy::gizmos::GizmoPlugin;
|
||||
use bevy::gltf::GltfPlugin;
|
||||
use bevy::input::InputPlugin;
|
||||
use bevy::pbr::PbrPlugin;
|
||||
use bevy::remote::RemotePlugin;
|
||||
use bevy::remote::http::RemoteHttpPlugin;
|
||||
use bevy::render::{RenderDebugFlags, RenderPlugin};
|
||||
use bevy::scene::ScenePlugin;
|
||||
use bevy::text::FontLoader;
|
||||
@@ -378,7 +376,10 @@ fn bevy_loop(
|
||||
app.add_schedule(pre_frame_wait);
|
||||
app.insert_resource(ClearColor(Color::BLACK.with_alpha(0.0)));
|
||||
app.insert_resource(ObjectRegistryRes(object_registry));
|
||||
app.add_plugins((RemotePlugin::default(), RemoteHttpPlugin::default()));
|
||||
#[cfg(feature = "bevy_debugging")]
|
||||
{
|
||||
app.add_plugins((RemotePlugin::default(), RemoteHttpPlugin::default()));
|
||||
}
|
||||
// the Stardust server plugins
|
||||
// infra plugins
|
||||
app.add_plugins(EntityHandlePlugin);
|
||||
|
||||
@@ -27,7 +27,7 @@ pub struct LinesNodePlugin;
|
||||
|
||||
impl Plugin for LinesNodePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Update, (build_line_mesh, update_visibillity).chain());
|
||||
app.add_systems(Update, (build_line_mesh/* , update_visibillity */).chain());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ impl Plugin for ModelNodePlugin {
|
||||
app.add_systems(Update, load_models);
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
(gen_model_parts, apply_materials, update_visibillity).chain(),
|
||||
(gen_model_parts, apply_materials/* , update_visibillity */).chain(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
BevyMaterial,
|
||||
core::{
|
||||
bevy_channel::{BevyChannel, BevyChannelReader},
|
||||
client::Client,
|
||||
@@ -9,10 +10,12 @@ use crate::{
|
||||
resource::get_resource_file,
|
||||
},
|
||||
nodes::{
|
||||
drawable::XAlign, spatial::{Spatial, SpatialNode}, Node
|
||||
}, BevyMaterial,
|
||||
Node,
|
||||
drawable::XAlign,
|
||||
spatial::{Spatial, SpatialNode},
|
||||
},
|
||||
};
|
||||
use bevy::{platform::collections::HashMap, prelude::*};
|
||||
use bevy::{platform::collections::HashMap, prelude::*, render::mesh::MeshAabb};
|
||||
use bevy_mesh_text_3d::{
|
||||
Align, Attrs, MeshTextPlugin, Settings as FontSettings, generate_meshes,
|
||||
text_glyphs::TextGlyphs,
|
||||
@@ -40,25 +43,7 @@ impl Plugin for TextNodePlugin {
|
||||
|
||||
SPAWN_TEXT.init(app);
|
||||
app.init_resource::<MaterialRegistry>();
|
||||
app.add_systems(Update, (spawn_text, update_visibillity).chain());
|
||||
}
|
||||
}
|
||||
|
||||
fn update_visibillity(mut cmds: Commands) {
|
||||
for text in TEXT_REGISTRY.get_valid_contents().into_iter() {
|
||||
let Some(entity) = text.entity.lock().as_deref().copied() else {
|
||||
continue;
|
||||
};
|
||||
match text.spatial.node().map(|n| n.enabled()).unwrap_or(false) {
|
||||
true => {
|
||||
cmds.entity(entity)
|
||||
.insert_recursive::<Children>(Visibility::Visible);
|
||||
}
|
||||
false => {
|
||||
cmds.entity(entity)
|
||||
.insert_recursive::<Children>(Visibility::Hidden);
|
||||
}
|
||||
}
|
||||
app.add_systems(Update, spawn_text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,15 +119,25 @@ fn spawn_text(
|
||||
if let Some(db) = old_db {
|
||||
mem::swap(font_settings.font_system.db_mut(), db);
|
||||
}
|
||||
let Ok(meshes) = char_meshes.inspect_err(|err| error!("unable to create text meshes: {err}"))
|
||||
let Ok(char_meshes) =
|
||||
char_meshes.inspect_err(|err| error!("unable to create text meshes: {err}"))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let dist = meshes
|
||||
.iter()
|
||||
.fold(f32::MAX, |dist, v| dist.min(v.transform.translation.x));
|
||||
let dist = char_meshes.iter().fold(f32::MAX, |dist, v| {
|
||||
dist.min(
|
||||
v.transform.translation.x
|
||||
- meshes
|
||||
.get(&v.mesh)
|
||||
.unwrap()
|
||||
.compute_aabb()
|
||||
.unwrap_or_default()
|
||||
.half_extents
|
||||
.x,
|
||||
)
|
||||
});
|
||||
// TODO: text align
|
||||
let letters = meshes
|
||||
let letters = char_meshes
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
cmds.spawn((
|
||||
|
||||
@@ -6,6 +6,8 @@ mod method;
|
||||
mod pointer;
|
||||
mod tip;
|
||||
|
||||
use bevy::tasks::ComputeTaskPool;
|
||||
use bevy::tasks::ParallelSlice;
|
||||
pub use handler::*;
|
||||
pub use method::*;
|
||||
use tracing::debug_span;
|
||||
@@ -120,55 +122,60 @@ pub fn process_input() {
|
||||
};
|
||||
node.enabled()
|
||||
});
|
||||
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
|
||||
let _span = debug_span!("handle input handler").entered();
|
||||
for method_alias in handler.method_aliases.get_aliases() {
|
||||
method_alias.set_enabled(false);
|
||||
}
|
||||
INPUT_HANDLER_REGISTRY
|
||||
.get_valid_contents()
|
||||
.into_iter()
|
||||
.par_splat_map(ComputeTaskPool::get(), None, |_, handlers| {
|
||||
for handler in handlers {
|
||||
let _span = debug_span!("handle input handler").entered();
|
||||
for method_alias in handler.method_aliases.get_aliases() {
|
||||
method_alias.set_enabled(false);
|
||||
}
|
||||
|
||||
let Some(handler_node) = handler.spatial.node() else {
|
||||
continue;
|
||||
};
|
||||
if !handler_node.enabled() {
|
||||
continue;
|
||||
}
|
||||
if let Some(handler_field_node) = handler.field.spatial.node() {
|
||||
if !handler_field_node.enabled() {
|
||||
continue;
|
||||
let Some(handler_node) = handler.spatial.node() else {
|
||||
continue;
|
||||
};
|
||||
if !handler_node.enabled() {
|
||||
continue;
|
||||
}
|
||||
if let Some(handler_field_node) = handler.field.spatial.node() {
|
||||
if !handler_field_node.enabled() {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let ser_span = debug_span!("serializing input").entered();
|
||||
let (methods, datas) = methods
|
||||
.clone()
|
||||
// filter out methods without the handler in their handler order
|
||||
.filter(|a| {
|
||||
a.handler_order
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|h| h.ptr_eq(&Arc::downgrade(&handler)))
|
||||
})
|
||||
// filter out methods without the proper alias
|
||||
.filter_map(|m| {
|
||||
Some((
|
||||
handler
|
||||
.method_aliases
|
||||
.get_from_original_node(m.spatial.node.clone())?,
|
||||
m,
|
||||
))
|
||||
})
|
||||
// make sure the input method alias is enabled
|
||||
.inspect(|(a, _)| {
|
||||
a.set_enabled(true);
|
||||
})
|
||||
// serialize the data
|
||||
.map(|(a, m)| (a.clone(), m.serialize(a.get_id(), &handler)))
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
drop(ser_span);
|
||||
|
||||
let _span = debug_span!("client input").entered();
|
||||
let _ = input_handler_client::input(&handler_node, &methods, &datas);
|
||||
}
|
||||
};
|
||||
|
||||
let ser_span = debug_span!("serializing input").entered();
|
||||
let (methods, datas) = methods
|
||||
.clone()
|
||||
// filter out methods without the handler in their handler order
|
||||
.filter(|a| {
|
||||
a.handler_order
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|h| h.ptr_eq(&Arc::downgrade(&handler)))
|
||||
})
|
||||
// filter out methods without the proper alias
|
||||
.filter_map(|m| {
|
||||
Some((
|
||||
handler
|
||||
.method_aliases
|
||||
.get_from_original_node(m.spatial.node.clone())?,
|
||||
m,
|
||||
))
|
||||
})
|
||||
// make sure the input method alias is enabled
|
||||
.inspect(|(a, _)| {
|
||||
a.set_enabled(true);
|
||||
})
|
||||
// serialize the data
|
||||
.map(|(a, m)| (a.clone(), m.serialize(a.get_id(), &handler)))
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
drop(ser_span);
|
||||
|
||||
let _span = debug_span!("client input").entered();
|
||||
let _ = input_handler_client::input(&handler_node, &methods, &datas);
|
||||
}
|
||||
});
|
||||
for method in methods {
|
||||
method.cull_capture_attempts();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use mint::Vector3;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::fmt::Debug;
|
||||
|
🛠️ Refactor suggestion Consider implementing entity cleanup for dead spatial references. The comment raises a valid concern. When the spatial weak reference can't be upgraded, the entity is orphaned and should be despawned to prevent resource leaks. Note: This would require adding
🤖 Prompt for AI Agents_🛠️ Refactor suggestion_
**Consider implementing entity cleanup for dead spatial references.**
The comment raises a valid concern. When the spatial weak reference can't be upgraded, the entity is orphaned and should be despawned to prevent resource leaks.
```diff
let Some(spatial) = spatial_node.0.upgrade() else {
- // should we despawn the entity?
+ cmds.entity(entity).despawn_recursive();
return;
};
```
Note: This would require adding `Commands` to the system parameters.
> Committable suggestion skipped: line range outside the PR's diff.
<details>
<summary>🤖 Prompt for AI Agents</summary>
```
In src/nodes/spatial/mod.rs around lines 41 to 44, the code currently returns
early when the spatial weak reference cannot be upgraded, potentially leaving
orphaned entities. To fix this, modify the system to accept Commands as a
parameter and use it to despawn the entity when the spatial reference is dead,
ensuring proper cleanup and preventing resource leaks.
```
</details>
<!-- This is an auto-generated comment by CodeRabbit -->
<!-- fingerprinting:phantom:medusa:lion -->
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, OnceLock, Weak};
|
||||
use std::{f32, ptr};
|
||||
|
||||
@@ -32,17 +33,42 @@ impl Plugin for SpatialNodePlugin {
|
||||
}
|
||||
|
||||
fn update_spatial_nodes(
|
||||
mut query: Query<(&mut BevyTransform, &SpatialNode, Option<&ChildOf>)>,
|
||||
mut query: Query<(
|
||||
&mut BevyTransform,
|
||||
&SpatialNode,
|
||||
Option<&ChildOf>,
|
||||
&mut Visibility,
|
||||
)>,
|
||||
parent_query: Query<&GlobalTransform>,
|
||||
) {
|
||||
query
|
||||
.par_iter_mut()
|
||||
.for_each(|(mut transform, spatial_node, child_of)| {
|
||||
.for_each(|(mut transform, spatial_node, child_of, mut vis)| {
|
||||
let _span = debug_span!("updating spatial node").entered();
|
||||
let Some(spatial) = spatial_node.0.upgrade() else {
|
||||
// should we despawn the entity?
|
||||
return;
|
||||
};
|
||||
let mat4 = spatial.global_transform();
|
||||
if spatial
|
||||
.node()
|
||||
.is_some_and(|v| !v.enabled.load(Ordering::Relaxed))
|
||||
{
|
||||
if !matches!(*vis, Visibility::Hidden) {
|
||||
*vis = Visibility::Hidden;
|
||||
}
|
||||
return;
|
||||
}
|
||||
let mat4 =
|
||||
debug_span!("getting global transform").in_scope(|| spatial.global_transform());
|
||||
let (scale, _, _) = mat4.to_scale_rotation_translation();
|
||||
match (*vis, scale == Vec3::ZERO) {
|
||||
(Visibility::Inherited | Visibility::Visible, true) => {
|
||||
*vis = Visibility::Hidden;
|
||||
}
|
||||
(Visibility::Hidden, false) => {
|
||||
*vis = Visibility::Inherited;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
match child_of {
|
||||
Some(child_of) => {
|
||||
let Ok(parent) = parent_query.get(child_of.0) else {
|
||||
@@ -60,7 +86,7 @@ fn update_spatial_nodes(
|
||||
}
|
||||
|
||||
#[derive(Clone, Component, Debug)]
|
||||
#[require(BevyTransform)]
|
||||
#[require(BevyTransform, Visibility)]
|
||||
pub struct SpatialNode(pub Weak<Spatial>);
|
||||
|
||||
stardust_xr_server_codegen::codegen_spatial_protocol!();
|
||||
|
||||
@@ -39,6 +39,7 @@ use std::{
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
};
|
||||
use tracing::instrument;
|
||||
use zbus::Connection;
|
||||
pub struct ControllerPlugin;
|
||||
const CURSOR_MODEL_PATH: &str = "/tmp/stardust_server/models/cursor.glb";
|
||||
@@ -152,9 +153,11 @@ fn update(
|
||||
controllers.right.set_enabled(false);
|
||||
return;
|
||||
};
|
||||
session
|
||||
.sync_actions(&[ActiveActionSet::new(&actions.set)])
|
||||
.unwrap();
|
||||
debug_span!("sync actions").in_scope(|| {
|
||||
session
|
||||
.sync_actions(&[ActiveActionSet::new(&actions.set)])
|
||||
.unwrap();
|
||||
});
|
||||
let time = state.predicted_display_time;
|
||||
// stupid bevy gltf loading issue (rotated 180 degrees on the y axis)
|
||||
controllers
|
||||
@@ -299,6 +302,7 @@ impl SkController {
|
||||
space: None,
|
||||
})
|
||||
}
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn set_enabled(&self, enabled: bool) {
|
||||
if let Some(node) = self.input.spatial.node() {
|
||||
node.set_enabled(enabled);
|
||||
@@ -321,6 +325,7 @@ impl SkController {
|
||||
let Some(space) = self.space.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let _span = debug_span!("locate space").entered();
|
||||
let Ok(location) = session
|
||||
.locate_space(space, &ref_space, time)
|
||||
.inspect_err(|err| error!("error while locating controller space: {err}"))
|
||||
@@ -333,6 +338,7 @@ impl SkController {
|
||||
| SpaceLocationFlags::ORIENTATION_VALID
|
||||
| SpaceLocationFlags::ORIENTATION_TRACKED,
|
||||
);
|
||||
drop(_span);
|
||||
self.set_enabled(enabled);
|
||||
if enabled {
|
||||
let world_transform = Mat4::from(Affine3A::from(location.pose.to_xr_pose()));
|
||||
@@ -377,6 +383,7 @@ impl SkController {
|
||||
.map(|v| v.current_state)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
let _span = debug_span!("apply datamap").entered();
|
||||
self.datamap = ControllerDatamap {
|
||||
select: get(session, path, &actions.trigger),
|
||||
middle: get(session, path, &actions.stick_click) as u32 as f32,
|
||||
@@ -385,6 +392,7 @@ impl SkController {
|
||||
scroll: get(session, path, &actions.stick).to_vec2(),
|
||||
};
|
||||
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap();
|
||||
drop(_span);
|
||||
|
||||
let distance_calculator = |space: &Arc<Spatial>, _data: &InputDataType, field: &Field| {
|
||||
Some(field.distance(space, [0.0; 3].into()).abs())
|
||||
|
||||
Reference in New Issue
Block a user
⚠️ Potential issue
Breaking change: Wayland no longer in default features.
Removing
waylandfrom default features might break existing users. Consider documenting this change prominently or keeping it as default if it's commonly used.🤖 Prompt for AI Agents