Bevy Rewrite, attempt 2 #46
@@ -24,8 +24,8 @@ path = "src/main.rs"
|
|||||||
default = []
|
default = []
|
||||||
wayland = ["dep:smithay", "dep:wayland-scanner", "dep:wayland-backend"]
|
wayland = ["dep:smithay", "dep:wayland-scanner", "dep:wayland-backend"]
|
||||||
|
|
|||||||
profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
|
profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
|
||||||
profile_app = ["dep:tracing-tracy", "bevy/trace_tracy"]
|
profile_app = ["dep:tracing-tracy", "bevy/trace_tracy", "bevy/trace"]
|
||||||
change_tracking = ["bevy/track_location"]
|
bevy_debugging = ["bevy/bevy_remote", "bevy/track_location"]
|
||||||
|
|
||||||
[package.metadata.appimage]
|
[package.metadata.appimage]
|
||||||
auto_link = true
|
auto_link = true
|
||||||
@@ -64,7 +64,7 @@ color-eyre = { version = "0.6.3", default-features = false }
|
|||||||
clap = { version = "4.5.13", features = ["derive"] }
|
clap = { version = "4.5.13", features = ["derive"] }
|
||||||
console-subscriber = { version = "0.4.0", optional = true }
|
console-subscriber = { version = "0.4.0", optional = true }
|
||||||
thiserror = "2.0.9"
|
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-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
tracing-tracy = { version = "0.11.1", optional = true }
|
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"] }
|
tokio = { version = "1.39.2", features = ["rt-multi-thread", "signal", "time"] }
|
||||||
|
|
||||||
# bevy
|
# 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_xr = "0.3"
|
||||||
bevy_mod_openxr = "0.3"
|
bevy_mod_openxr = "0.3"
|
||||||
# bevy_sk.git = "https://github.com/MalekiRe/bevy_sk"
|
# bevy_sk.git = "https://github.com/MalekiRe/bevy_sk"
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ use bevy::gizmos::GizmoPlugin;
|
|||||||
use bevy::gltf::GltfPlugin;
|
use bevy::gltf::GltfPlugin;
|
||||||
use bevy::input::InputPlugin;
|
use bevy::input::InputPlugin;
|
||||||
use bevy::pbr::PbrPlugin;
|
use bevy::pbr::PbrPlugin;
|
||||||
use bevy::remote::RemotePlugin;
|
|
||||||
use bevy::remote::http::RemoteHttpPlugin;
|
|
||||||
use bevy::render::{RenderDebugFlags, RenderPlugin};
|
use bevy::render::{RenderDebugFlags, RenderPlugin};
|
||||||
use bevy::scene::ScenePlugin;
|
use bevy::scene::ScenePlugin;
|
||||||
use bevy::text::FontLoader;
|
use bevy::text::FontLoader;
|
||||||
@@ -378,7 +376,10 @@ fn bevy_loop(
|
|||||||
app.add_schedule(pre_frame_wait);
|
app.add_schedule(pre_frame_wait);
|
||||||
app.insert_resource(ClearColor(Color::BLACK.with_alpha(0.0)));
|
app.insert_resource(ClearColor(Color::BLACK.with_alpha(0.0)));
|
||||||
app.insert_resource(ObjectRegistryRes(object_registry));
|
app.insert_resource(ObjectRegistryRes(object_registry));
|
||||||
|
#[cfg(feature = "bevy_debugging")]
|
||||||
|
{
|
||||||
app.add_plugins((RemotePlugin::default(), RemoteHttpPlugin::default()));
|
app.add_plugins((RemotePlugin::default(), RemoteHttpPlugin::default()));
|
||||||
|
}
|
||||||
// the Stardust server plugins
|
// the Stardust server plugins
|
||||||
// infra plugins
|
// infra plugins
|
||||||
app.add_plugins(EntityHandlePlugin);
|
app.add_plugins(EntityHandlePlugin);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub struct LinesNodePlugin;
|
|||||||
|
|
||||||
impl Plugin for LinesNodePlugin {
|
impl Plugin for LinesNodePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
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(Update, load_models);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
PostUpdate,
|
PostUpdate,
|
||||||
(gen_model_parts, apply_materials, update_visibillity).chain(),
|
(gen_model_parts, apply_materials/* , update_visibillity */).chain(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
BevyMaterial,
|
||||||
core::{
|
core::{
|
||||||
bevy_channel::{BevyChannel, BevyChannelReader},
|
bevy_channel::{BevyChannel, BevyChannelReader},
|
||||||
client::Client,
|
client::Client,
|
||||||
@@ -9,10 +10,12 @@ use crate::{
|
|||||||
resource::get_resource_file,
|
resource::get_resource_file,
|
||||||
},
|
},
|
||||||
nodes::{
|
nodes::{
|
||||||
drawable::XAlign, spatial::{Spatial, SpatialNode}, Node
|
Node,
|
||||||
}, BevyMaterial,
|
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::{
|
use bevy_mesh_text_3d::{
|
||||||
Align, Attrs, MeshTextPlugin, Settings as FontSettings, generate_meshes,
|
Align, Attrs, MeshTextPlugin, Settings as FontSettings, generate_meshes,
|
||||||
text_glyphs::TextGlyphs,
|
text_glyphs::TextGlyphs,
|
||||||
@@ -40,25 +43,7 @@ impl Plugin for TextNodePlugin {
|
|||||||
|
|
||||||
SPAWN_TEXT.init(app);
|
SPAWN_TEXT.init(app);
|
||||||
app.init_resource::<MaterialRegistry>();
|
app.init_resource::<MaterialRegistry>();
|
||||||
app.add_systems(Update, (spawn_text, update_visibillity).chain());
|
app.add_systems(Update, spawn_text);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,15 +119,25 @@ fn spawn_text(
|
|||||||
if let Some(db) = old_db {
|
if let Some(db) = old_db {
|
||||||
mem::swap(font_settings.font_system.db_mut(), 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 {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let dist = meshes
|
let dist = char_meshes.iter().fold(f32::MAX, |dist, v| {
|
||||||
.iter()
|
dist.min(
|
||||||
.fold(f32::MAX, |dist, v| dist.min(v.transform.translation.x));
|
v.transform.translation.x
|
||||||
|
- meshes
|
||||||
|
.get(&v.mesh)
|
||||||
|
.unwrap()
|
||||||
|
.compute_aabb()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.half_extents
|
||||||
|
.x,
|
||||||
|
)
|
||||||
|
});
|
||||||
// TODO: text align
|
// TODO: text align
|
||||||
let letters = meshes
|
let letters = char_meshes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
cmds.spawn((
|
cmds.spawn((
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ mod method;
|
|||||||
mod pointer;
|
mod pointer;
|
||||||
mod tip;
|
mod tip;
|
||||||
|
|
||||||
|
use bevy::tasks::ComputeTaskPool;
|
||||||
|
use bevy::tasks::ParallelSlice;
|
||||||
pub use handler::*;
|
pub use handler::*;
|
||||||
pub use method::*;
|
pub use method::*;
|
||||||
use tracing::debug_span;
|
use tracing::debug_span;
|
||||||
@@ -120,7 +122,11 @@ pub fn process_input() {
|
|||||||
};
|
};
|
||||||
node.enabled()
|
node.enabled()
|
||||||
});
|
});
|
||||||
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
|
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();
|
let _span = debug_span!("handle input handler").entered();
|
||||||
for method_alias in handler.method_aliases.get_aliases() {
|
for method_alias in handler.method_aliases.get_aliases() {
|
||||||
method_alias.set_enabled(false);
|
method_alias.set_enabled(false);
|
||||||
@@ -169,6 +175,7 @@ pub fn process_input() {
|
|||||||
let _span = debug_span!("client input").entered();
|
let _span = debug_span!("client input").entered();
|
||||||
let _ = input_handler_client::input(&handler_node, &methods, &datas);
|
let _ = input_handler_client::input(&handler_node, &methods, &datas);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
for method in methods {
|
for method in methods {
|
||||||
method.cull_capture_attempts();
|
method.cull_capture_attempts();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use mint::Vector3;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::fmt::Debug;
|
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::sync::{Arc, OnceLock, Weak};
|
||||||
use std::{f32, ptr};
|
use std::{f32, ptr};
|
||||||
|
|
||||||
@@ -32,17 +33,42 @@ impl Plugin for SpatialNodePlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_spatial_nodes(
|
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>,
|
parent_query: Query<&GlobalTransform>,
|
||||||
) {
|
) {
|
||||||
query
|
query
|
||||||
.par_iter_mut()
|
.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 {
|
let Some(spatial) = spatial_node.0.upgrade() else {
|
||||||
// should we despawn the entity?
|
|
||||||
return;
|
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 {
|
match child_of {
|
||||||
Some(child_of) => {
|
Some(child_of) => {
|
||||||
let Ok(parent) = parent_query.get(child_of.0) else {
|
let Ok(parent) = parent_query.get(child_of.0) else {
|
||||||
@@ -60,7 +86,7 @@ fn update_spatial_nodes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Component, Debug)]
|
#[derive(Clone, Component, Debug)]
|
||||||
#[require(BevyTransform)]
|
#[require(BevyTransform, Visibility)]
|
||||||
pub struct SpatialNode(pub Weak<Spatial>);
|
pub struct SpatialNode(pub Weak<Spatial>);
|
||||||
|
|
||||||
stardust_xr_server_codegen::codegen_spatial_protocol!();
|
stardust_xr_server_codegen::codegen_spatial_protocol!();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ use std::{
|
|||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
use tracing::instrument;
|
||||||
use zbus::Connection;
|
use zbus::Connection;
|
||||||
pub struct ControllerPlugin;
|
pub struct ControllerPlugin;
|
||||||
const CURSOR_MODEL_PATH: &str = "/tmp/stardust_server/models/cursor.glb";
|
const CURSOR_MODEL_PATH: &str = "/tmp/stardust_server/models/cursor.glb";
|
||||||
@@ -152,9 +153,11 @@ fn update(
|
|||||||
controllers.right.set_enabled(false);
|
controllers.right.set_enabled(false);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
debug_span!("sync actions").in_scope(|| {
|
||||||
session
|
session
|
||||||
.sync_actions(&[ActiveActionSet::new(&actions.set)])
|
.sync_actions(&[ActiveActionSet::new(&actions.set)])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
});
|
||||||
let time = state.predicted_display_time;
|
let time = state.predicted_display_time;
|
||||||
// stupid bevy gltf loading issue (rotated 180 degrees on the y axis)
|
// stupid bevy gltf loading issue (rotated 180 degrees on the y axis)
|
||||||
controllers
|
controllers
|
||||||
@@ -299,6 +302,7 @@ impl SkController {
|
|||||||
space: None,
|
space: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
pub fn set_enabled(&self, enabled: bool) {
|
pub fn set_enabled(&self, enabled: bool) {
|
||||||
if let Some(node) = self.input.spatial.node() {
|
if let Some(node) = self.input.spatial.node() {
|
||||||
node.set_enabled(enabled);
|
node.set_enabled(enabled);
|
||||||
@@ -321,6 +325,7 @@ impl SkController {
|
|||||||
let Some(space) = self.space.as_ref() else {
|
let Some(space) = self.space.as_ref() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let _span = debug_span!("locate space").entered();
|
||||||
let Ok(location) = session
|
let Ok(location) = session
|
||||||
.locate_space(space, &ref_space, time)
|
.locate_space(space, &ref_space, time)
|
||||||
.inspect_err(|err| error!("error while locating controller space: {err}"))
|
.inspect_err(|err| error!("error while locating controller space: {err}"))
|
||||||
@@ -333,6 +338,7 @@ impl SkController {
|
|||||||
| SpaceLocationFlags::ORIENTATION_VALID
|
| SpaceLocationFlags::ORIENTATION_VALID
|
||||||
| SpaceLocationFlags::ORIENTATION_TRACKED,
|
| SpaceLocationFlags::ORIENTATION_TRACKED,
|
||||||
);
|
);
|
||||||
|
drop(_span);
|
||||||
self.set_enabled(enabled);
|
self.set_enabled(enabled);
|
||||||
if enabled {
|
if enabled {
|
||||||
let world_transform = Mat4::from(Affine3A::from(location.pose.to_xr_pose()));
|
let world_transform = Mat4::from(Affine3A::from(location.pose.to_xr_pose()));
|
||||||
@@ -377,6 +383,7 @@ impl SkController {
|
|||||||
.map(|v| v.current_state)
|
.map(|v| v.current_state)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
let _span = debug_span!("apply datamap").entered();
|
||||||
self.datamap = ControllerDatamap {
|
self.datamap = ControllerDatamap {
|
||||||
select: get(session, path, &actions.trigger),
|
select: get(session, path, &actions.trigger),
|
||||||
middle: get(session, path, &actions.stick_click) as u32 as f32,
|
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(),
|
scroll: get(session, path, &actions.stick).to_vec2(),
|
||||||
};
|
};
|
||||||
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap();
|
*self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap();
|
||||||
|
drop(_span);
|
||||||
|
|
||||||
let distance_calculator = |space: &Arc<Spatial>, _data: &InputDataType, field: &Field| {
|
let distance_calculator = |space: &Arc<Spatial>, _data: &InputDataType, field: &Field| {
|
||||||
Some(field.distance(space, [0.0; 3].into()).abs())
|
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