diff --git a/client/Cargo.toml b/client/Cargo.toml index a373ba7..49aeea4 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -23,4 +23,5 @@ rayon = "1.10.0" bincode = "1.3" bevy_app_compute = "0.16" bytemuck = { version = "1.14", features = ["derive"] } +futures-lite = "2" diff --git a/client/src/plugins/environment/environment_plugin.rs b/client/src/plugins/environment/environment_plugin.rs index 52ba190..e9aafcb 100644 --- a/client/src/plugins/environment/environment_plugin.rs +++ b/client/src/plugins/environment/environment_plugin.rs @@ -1,4 +1,3 @@ -use std::path::Path; use crate::plugins::environment::systems::voxels::debug::{draw_grid, visualize_octree_system}; use crate::plugins::environment::systems::voxels::lod::update_chunk_lods; use crate::plugins::environment::systems::voxels::meshing_gpu::{ @@ -11,6 +10,7 @@ use crate::plugins::environment::systems::voxels::queue_systems::{ }; use crate::plugins::environment::systems::voxels::render_chunks::rebuild_dirty_chunks; use crate::plugins::environment::systems::voxels::atlas::{VoxelTextureAtlas}; +use crate::plugins::environment::systems::voxel_system::attach_octree_from_task; use crate::plugins::environment::systems::voxels::structure::{ ChunkBudget, ChunkCullingCfg, ChunkQueue, MeshBufferPool, PrevCameraChunk, SparseVoxelOctree, SpawnedChunks, @@ -54,6 +54,7 @@ impl Plugin for EnvironmentPlugin { .add_systems( Update, ( + attach_octree_from_task, /* ---------- culling & streaming ---------- */ enqueue_visible_chunks, process_chunk_queue.after(enqueue_visible_chunks), diff --git a/client/src/plugins/environment/systems/voxel_system.rs b/client/src/plugins/environment/systems/voxel_system.rs index 181fb35..b903589 100644 --- a/client/src/plugins/environment/systems/voxel_system.rs +++ b/client/src/plugins/environment/systems/voxel_system.rs @@ -6,23 +6,22 @@ use noise::{NoiseFn, Perlin}; use rand::{thread_rng, Rng}; use rayon::prelude::*; use std::path::Path; -use std::thread; +use bevy::tasks::{AsyncComputeTaskPool, Task}; +use futures_lite::future; + +#[derive(Resource)] +pub struct OctreeTask(pub Task); -pub fn setup(mut commands: Commands, root: Res) { - let builder = thread::Builder::new() - .name("octree-build".into()) - // Reduced stack size now that octree operations are iterative - .stack_size(8 * 1024 * 1024); - - let handle = builder - .spawn(move || { - // Octree parameters - let unit_size = 1.0_f32; - let octree_base_size = 64.0 * unit_size; - let octree_depth = 10; +pub fn setup(mut commands: Commands) { + let pool = AsyncComputeTaskPool::get(); + let task: Task = pool.spawn(async move { + // Octree parameters + let unit_size = 1.0_f32; + let octree_base_size = 64.0 * unit_size; + let octree_depth = 10; let path = Path::new("octree.bin"); @@ -57,17 +56,10 @@ pub fn setup(mut commands: Commands, root: Res) { tree }; - octree - }) - .expect("failed to spawn octree build thread") - .join(); - - let octree = handle.expect("Failed to join octree build thread"); - - // Attach octree to the scene graph - commands.entity(root.0).with_children(|parent| { - parent.spawn((Transform::default(), octree)); + octree }); + + commands.insert_resource(OctreeTask(task)); } @@ -239,3 +231,20 @@ pub fn generate_solid_plane_with_noise( } } } + +pub fn attach_octree_from_task( + mut commands: Commands, + mut task: Option>, + root: Res, +) { + let Some(mut task) = task else { + return; + }; + + if let Some(octree) = future::block_on(future::poll_once(&mut task.0)) { + commands.entity(root.0).with_children(|parent| { + parent.spawn((Transform::default(), octree)); + }); + commands.remove_resource::(); + } +}