Skip to content

Commit

Permalink
Async-ifying lod generation
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyTornetta committed Sep 10, 2023
1 parent ac23b9e commit 75a27f5
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 96 deletions.
4 changes: 2 additions & 2 deletions cosmos_client/src/rendering/lod_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ fn vec_eq(v1: Vec3, v2: Vec3) -> bool {
(v1.x - v2.x).abs() < EPSILON && (v1.y - v2.y).abs() < EPSILON && (v1.z - v2.z).abs() < EPSILON
}

fn poll_generating_lods(
fn poll_rendering_lods(
mut commands: Commands,
structure_lod_meshes_query: Query<&LodMeshes>,
mut meshes: ResMut<Assets<Mesh>>,
Expand Down Expand Up @@ -654,7 +654,7 @@ pub(super) fn register(app: &mut App) {
(
monitor_lods_needs_rendered_system,
trigger_lod_render,
poll_generating_lods,
poll_rendering_lods,
hide_lod,
)
.chain()
Expand Down
10 changes: 6 additions & 4 deletions cosmos_client/src/rendering/structure_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,6 @@ fn monitor_needs_rendered_system(
return;
};

// by making the Vec an Option<Vec> I can take ownership of it later, which I cannot do with
// just a plain Mutex<Vec>.
// https://stackoverflow.com/questions/30573188/cannot-move-data-out-of-a-mutex

for (entity, ce, _) in chunks_need_rendered
.iter()
.map(|(x, y, transform)| (x, y, transform.translation().distance_squared(local_transform.translation())))
Expand All @@ -392,6 +388,10 @@ fn monitor_needs_rendered_system(

let coords = ce.chunk_location;

// I assure you officer, cloning 7 chunks to render 1 is very necessary
//
// please someone fix this when they feel inspired

let Some(chunk) = structure.chunk_from_chunk_coordinates(coords).cloned() else {
continue;
};
Expand All @@ -405,6 +405,8 @@ fn monitor_needs_rendered_system(
let back = structure.chunk_from_chunk_coordinates_unbound(unbound.back()).cloned();
let front = structure.chunk_from_chunk_coordinates_unbound(unbound.front()).cloned();

// "gee, you sure have a way with the borrow checker"

let atlas = atlas.clone();
let materials = materials.clone();
let blocks = blocks.clone();
Expand Down
1 change: 0 additions & 1 deletion cosmos_core/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
pub mod array_utils;
pub mod quat_math;
pub mod resource_wrapper;
pub mod smooth_clamp;
pub mod timer;
7 changes: 0 additions & 7 deletions cosmos_core/src/utils/resource_wrapper.rs

This file was deleted.

33 changes: 29 additions & 4 deletions cosmos_server/src/init/init_world.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
//! Handles the initialization of the server world
use std::{fs, num::Wrapping};
use std::{
fs,
num::Wrapping,
sync::{Arc, RwLock, RwLockReadGuard},
};

use bevy::prelude::*;
use cosmos_core::{netty::cosmos_encoder, utils::resource_wrapper::ResourceWrapper};
use cosmos_core::netty::cosmos_encoder;
use serde::{Deserialize, Serialize};

#[derive(Debug, Resource, Deref, Serialize, Deserialize, Clone, Copy)]
Expand Down Expand Up @@ -35,6 +39,25 @@ impl ServerSeed {
}
}

#[derive(Resource, Debug, Clone, Deref, DerefMut)]
/// A pre-seeded structure to create noise values. Uses simplex noise as the backend
///
/// This cannot be sent across threads - use ReadOnlyNoise to send use across threads.
pub struct Noise(noise::OpenSimplex);

#[derive(Resource, Debug, Clone)]
/// A thread-safe pre-seeded structure to create noise values. Uses simplex noise as the backend
///
/// To use across threads, just clone this and call the `inner` method to get the Noise struct this encapsulates
pub struct ReadOnlyNoise(Arc<RwLock<Noise>>);

impl ReadOnlyNoise {
/// Returns the `Noise` instance this encapsulates
pub fn inner(&self) -> RwLockReadGuard<Noise> {
self.0.read().expect("Failed to read")
}
}

pub(super) fn register(app: &mut App) {
let server_seed = if let Ok(seed) = fs::read("./world/seed.dat") {
cosmos_encoder::deserialize::<ServerSeed>(&seed).expect("Unable to understand './world/seed.dat' seed file. Is it corrupted?")
Expand All @@ -47,6 +70,8 @@ pub(super) fn register(app: &mut App) {
seed
};

app.insert_resource(ResourceWrapper(noise::OpenSimplex::new(server_seed.as_u32())))
.insert_resource(server_seed);
let noise = Noise(noise::OpenSimplex::new(server_seed.as_u32()));
let read_noise = ReadOnlyNoise(Arc::new(RwLock::new(noise.clone())));

app.insert_resource(noise).insert_resource(read_noise).insert_resource(server_seed);
}
5 changes: 2 additions & 3 deletions cosmos_server/src/structure/asteroid/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ use cosmos_core::{
structure_iterator::ChunkIteratorResult,
ChunkInitEvent, Structure,
},
utils::resource_wrapper::ResourceWrapper,
};
use futures_lite::future;
use noise::NoiseFn;

use crate::state::GameState;
use crate::{init::init_world::Noise, state::GameState};

#[derive(Component)]
struct AsyncStructureGeneration {
Expand Down Expand Up @@ -72,7 +71,7 @@ fn notify_when_done_generating(

fn start_generating_asteroid(
query: Query<(Entity, &Structure, &Location), With<AsteroidNeedsCreated>>,
noise: Res<ResourceWrapper<noise::OpenSimplex>>,
noise: Res<Noise>,
blocks: Res<Registry<Block>>,
mut commands: Commands,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::{marker::PhantomData, mem::swap};

use bevy::{
prelude::{Component, Entity, Event, EventReader, EventWriter, Query, Res, ResMut, Resource, With},
prelude::{App, Commands, Component, DespawnRecursiveExt, Entity, Event, EventReader, EventWriter, Query, Res, ResMut, Resource, With},
tasks::AsyncComputeTaskPool,
};
use cosmos_core::{
Expand All @@ -18,13 +18,16 @@ use cosmos_core::{
planet::{ChunkFaces, Planet},
Structure,
},
utils::{array_utils::flatten_2d, resource_wrapper::ResourceWrapper},
utils::array_utils::flatten_2d,
};
use futures_lite::future;
use noise::NoiseFn;
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};

use crate::structure::planet::lods::generate_lods::{GeneratingLod, PlayerGeneratingLod};
use crate::{
init::init_world::{Noise, ReadOnlyNoise},
structure::planet::lods::generate_lods::{GeneratingLod, GeneratingLods, LodNeedsGeneratedForPlayer},
};

use super::{GeneratingChunk, GeneratingChunks, TGenerateChunkEvent};

Expand Down Expand Up @@ -1045,7 +1048,7 @@ fn recurse<T: Component + Default + Clone, S: BiosphereGenerationStrategy + 'sta
first_block_coord: BlockCoordinate,
s_dimensions: CoordinateType,
scale: CoordinateType,
noise_generator: &noise::OpenSimplex,
noise_generator: &Noise,
block_ranges: &BlockLayers<T>,
) {
match generating_lod {
Expand Down Expand Up @@ -1093,39 +1096,57 @@ fn recurse<T: Component + Default + Clone, S: BiosphereGenerationStrategy + 'sta
}
}

pub(crate) fn generate_lods<T: Component + Default + Clone, S: BiosphereGenerationStrategy + 'static>(
mut query: Query<&mut PlayerGeneratingLod>,
pub(crate) fn start_generating_lods<T: Component + Default + Clone, S: BiosphereGenerationStrategy + 'static>(
query: Query<(Entity, &LodNeedsGeneratedForPlayer)>,
is_biosphere: Query<(&Structure, &Location), With<T>>,
noise_generator: Res<ResourceWrapper<noise::OpenSimplex>>,
noise_generator: Res<ReadOnlyNoise>,
block_ranges: Res<BlockLayers<T>>,
mut currently_generating: ResMut<GeneratingLods>,
mut commands: Commands,
) {
query.par_iter_mut().for_each_mut(|mut generating_lod| {
for (entity, generating_lod) in query.iter() {
commands.entity(entity).despawn_recursive();

let Ok((structure, location)) = is_biosphere.get(generating_lod.structure_entity) else {
return;
};

let task_pool = AsyncComputeTaskPool::get();

let structure_coords = location.absolute_coords_f64();

let dimensions = structure.block_dimensions().x;

recurse::<T, S>(
&mut generating_lod.generating_lod,
(structure_coords.x, structure_coords.y, structure_coords.z),
BlockCoordinate::new(0, 0, 0),
dimensions,
dimensions / CHUNK_DIMENSIONS,
&noise_generator,
&block_ranges,
);
});
let mut generating_lod = generating_lod.clone();
let noise_generator = noise_generator.clone();
let block_ranges = block_ranges.clone();

let task = task_pool.spawn(async move {
let noise = noise_generator.inner();

recurse::<T, S>(
&mut generating_lod.generating_lod,
(structure_coords.x, structure_coords.y, structure_coords.z),
BlockCoordinate::new(0, 0, 0),
dimensions,
dimensions / CHUNK_DIMENSIONS,
&noise,
&block_ranges,
);

generating_lod
});

currently_generating.push(task);
}
}

/// Calls generate_face_chunk, generate_edge_chunk, and generate_corner_chunk to generate the chunks of a planet.
pub fn generate_planet<T: Component + Clone + Default, E: TGenerateChunkEvent + Send + Sync + 'static, S: BiosphereGenerationStrategy>(
mut query: Query<(&mut Structure, &Location)>,
mut generating: ResMut<GeneratingChunks<T>>,
mut events: EventReader<E>,
noise_generator: Res<ResourceWrapper<noise::OpenSimplex>>,
noise_generator: Res<ReadOnlyNoise>,
block_ranges: Res<BlockLayers<T>>,
) {
let chunks = events
Expand Down Expand Up @@ -1168,9 +1189,11 @@ pub fn generate_planet<T: Component + Clone + Default, E: TGenerateChunkEvent +
if !chunks.is_empty() {
for (mut chunk, s_dimensions, location, structure_entity) in chunks {
let block_ranges = block_ranges.clone();
let noise_generator = **noise_generator;

let noise = noise_generator.clone();

let task = thread_pool.spawn(async move {
let noise_generator = noise.inner();
// let timer = UtilsTimer::start();

let actual_pos = location.absolute_coords_f64();
Expand Down Expand Up @@ -1233,3 +1256,7 @@ pub fn generate_planet<T: Component + Clone + Default, E: TGenerateChunkEvent +
}
}
}

pub(super) fn register(app: &mut App) {
app.init_resource::<GeneratingLods>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ use cosmos_core::{
planet::Planet,
rotate, ChunkInitEvent, Structure,
},
utils::resource_wrapper::ResourceWrapper,
};
use noise::NoiseFn;

use crate::GameState;
use crate::{init::init_world::Noise, GameState};

use super::{
biosphere_generation::{BlockLayers, DefaultBiosphereGenerationStrategy, GenerateChunkFeaturesEvent},
Expand Down Expand Up @@ -139,7 +138,7 @@ fn redwood_tree(
location: &Location,
block_event_writer: &mut EventWriter<BlockChangedEvent>,
blocks: &Registry<Block>,
noise_generator: &ResourceWrapper<noise::OpenSimplex>,
noise_generator: &Noise,
) {
let log = blocks.from_id("cosmos:redwood_log").unwrap();
let leaf = blocks.from_id("cosmos:redwood_leaf").unwrap();
Expand Down Expand Up @@ -439,7 +438,7 @@ fn trees(
location: &Location,
block_event_writer: &mut EventWriter<BlockChangedEvent>,
blocks: &Registry<Block>,
noise_generator: &ResourceWrapper<noise::OpenSimplex>,
noise_generator: &Noise,
) {
let Structure::Dynamic(planet) = structure else {
panic!("A planet must be dynamic!");
Expand Down Expand Up @@ -565,7 +564,7 @@ pub fn generate_chunk_features(
mut block_event_writer: EventWriter<BlockChangedEvent>,
mut structure_query: Query<(&mut Structure, &Location)>,
blocks: Res<Registry<Block>>,
noise_generator: Res<ResourceWrapper<noise::OpenSimplex>>,
noise_generator: Res<Noise>,
) {
for ev in event_reader.iter() {
if let Ok((mut structure, location)) = structure_query.get_mut(ev.structure_entity) {
Expand Down
5 changes: 3 additions & 2 deletions cosmos_server/src/structure/planet/biosphere/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::{
};

use self::biosphere_generation::{
generate_lods, generate_planet, notify_when_done_generating_terrain, BiosphereGenerationStrategy, GenerateChunkFeaturesEvent,
generate_planet, notify_when_done_generating_terrain, start_generating_lods, BiosphereGenerationStrategy, GenerateChunkFeaturesEvent,
};

use super::generation::planet_generator::check_needs_generated_system;
Expand Down Expand Up @@ -152,7 +152,7 @@ pub fn register_biosphere<
(
generate_planet::<T, E, S>,
notify_when_done_generating_terrain::<T>,
generate_lods::<T, S>,
start_generating_lods::<T, S>,
check_needs_generated_system::<E, T>,
)
.run_if(in_state(GameState::Playing)),
Expand Down Expand Up @@ -244,4 +244,5 @@ pub(super) fn register(app: &mut App) {
grass_biosphere::register(app);
molten_biosphere::register(app);
ice_biosphere::register(app);
biosphere_generation::register(app);
}
Loading

0 comments on commit 75a27f5

Please sign in to comment.