From 1c9d6af6e18b1deafd4f2112d0d8b85aaa2ae5fa Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Thu, 30 Jan 2025 16:04:27 +0100 Subject: [PATCH 01/68] Dyn link --- Cargo.lock | 10 ++++++++++ Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4549452b..d1919199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -375,6 +375,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb2a21c9f3306676077a88700bb8f354be779cf9caba9c21e94da9e696751af4" dependencies = [ + "bevy_dylib", "bevy_internal", ] @@ -639,6 +640,15 @@ dependencies = [ "sysinfo", ] +[[package]] +name = "bevy_dylib" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b120f96b1f18f3aac28729b6d7765114486b64df4c2af3314fe2bf30d4eb11c3" +dependencies = [ + "bevy_internal", +] + [[package]] name = "bevy_ecs" version = "0.15.1" diff --git a/Cargo.toml b/Cargo.toml index 5e90fafc..5ef3c780 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,4 +45,4 @@ renet_visualizer = [] physics_debug = [] raycast_debug = [] visual_debug = ["wireframe", "physics_debug", "raycast_debug"] - +dynamic_linking = ["bevy/dynamic_linking"] From d626f82c895d1b6d1f4646acc7c8862e9a2d928d Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Thu, 30 Jan 2025 16:04:41 +0100 Subject: [PATCH 02/68] Feature flag chat system --- Cargo.toml | 2 ++ src/client/main.rs | 1 + src/client/networking/systems.rs | 8 ++++++-- src/server/main.rs | 1 + src/server/networking/systems.rs | 16 +++++++++++++--- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5ef3c780..3b613f6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,8 @@ name = "server" path = "src/server/main.rs" [features] +chat = ["bevy/dynamic_linking"] + wireframe = [] debug_ui = [] renet_visualizer = [] diff --git a/src/client/main.rs b/src/client/main.rs index 08c89f58..258ef725 100644 --- a/src/client/main.rs +++ b/src/client/main.rs @@ -62,6 +62,7 @@ fn main() { collider::ColliderPlugin, player::PlayerPlugin, remote_player::RemotePlayerPlugin, + #[cfg(feature = "chat")] chat::ChatPlugin, )); app.insert_state(GameState::Playing); diff --git a/src/client/networking/systems.rs b/src/client/networking/systems.rs index 1b6cbaa4..d5491b34 100644 --- a/src/client/networking/systems.rs +++ b/src/client/networking/systems.rs @@ -9,8 +9,10 @@ pub fn receive_message_system( mut block_update_events: ResMut>, mut chunk_manager: ResMut, mut chunk_mesh_events: ResMut>, - mut chat_events: ResMut>, - mut single_chat_events: ResMut>, + #[cfg(feature = "chat")] mut chat_events: ResMut>, + #[cfg(feature = "chat")] mut single_chat_events: ResMut< + Events, + >, mut spawn_area_loaded: ResMut, ) { while let Some(message) = client.receive_message(DefaultChannel::ReliableOrdered) { @@ -35,10 +37,12 @@ pub fn receive_message_system( from_network: true, }); } + #[cfg(feature = "chat")] NetworkingMessage::ChatMessageSync(messages) => { info!("Client received {} chat messages", messages.len()); chat_events.send(chat_events::ChatSyncEvent(messages)); } + #[cfg(feature = "chat")] NetworkingMessage::SingleChatMessageSync(message) => { info!("Client received chat message {}", message.message); single_chat_events.send(chat_events::SingleChatSendEvent(message)); diff --git a/src/server/main.rs b/src/server/main.rs index deffdd63..64b68368 100644 --- a/src/server/main.rs +++ b/src/server/main.rs @@ -26,6 +26,7 @@ fn main() { app.add_plugins(player::PlayerPlugin); app.add_plugins(networking::NetworkingPlugin); app.add_plugins(terrain::TerrainPlugin); + #[cfg(feature = "chat")] app.add_plugins(chat::ChatPlugin); app.run(); } diff --git a/src/server/networking/systems.rs b/src/server/networking/systems.rs index c0e009f1..30b4ee82 100644 --- a/src/server/networking/systems.rs +++ b/src/server/networking/systems.rs @@ -5,7 +5,9 @@ pub fn receive_message_system( mut player_states: ResMut, mut past_block_updates: ResMut, chunk_manager: ResMut, - mut chat_message_events: EventWriter, + #[cfg(feature = "chat")] mut chat_message_events: EventWriter< + chat_events::PlayerChatMessageSendEvent, + >, ) { for client_id in server.clients_id() { while let Some(message) = server.receive_message(client_id, DefaultChannel::ReliableOrdered) @@ -29,6 +31,7 @@ pub fn receive_message_system( .unwrap(), ); } + #[cfg(feature = "chat")] NetworkingMessage::ChatMessageSend(message) => { info!("Received chat message from {}", client_id); chat_message_events @@ -102,8 +105,12 @@ pub fn handle_events_system( mut server_events: EventReader, mut player_states: ResMut, past_block_updates: Res, - mut chat_message_events: EventWriter, - mut chat_sync_events: EventWriter, + #[cfg(feature = "chat")] mut chat_message_events: EventWriter< + chat_events::PlayerChatMessageSendEvent, + >, + #[cfg(feature = "chat")] mut chat_sync_events: EventWriter< + chat_events::SyncPlayerChatMessagesEvent, + >, ) { for event in server_events.read() { match event { @@ -117,10 +124,12 @@ pub fn handle_events_system( }, ); + #[cfg(feature = "chat")] chat_sync_events.send(chat_events::SyncPlayerChatMessagesEvent { client_id: *client_id, }); + #[cfg(feature = "chat")] chat_message_events.send(chat_events::PlayerChatMessageSendEvent { client_id: SERVER_MESSAGE_ID, message: format!("Player {} joined the game", *client_id), @@ -147,6 +156,7 @@ pub fn handle_events_system( println!("Client {client_id} disconnected: {reason}"); player_states.players.remove(client_id); + #[cfg(feature = "chat")] chat_message_events.send(chat_events::PlayerChatMessageSendEvent { client_id: SERVER_MESSAGE_ID, message: format!("Player {} left the game", client_id), From 0bf2dbef394fc45357f34c1d4ea33687a6e8700f Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Thu, 30 Jan 2025 16:26:57 +0100 Subject: [PATCH 03/68] Impl 2d perlin sample --- src/server/terrain/util/generator.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 18953009..2d8f5422 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -79,6 +79,27 @@ impl Generator { density } + + fn sample_2d(&self, position: Vec2, octaves: i32) -> f64 { + let mut height = 0.0; + let lacuranity = 2.0; + let mut frequency = 1.0 / 60.0; + let mut amplitude = 10.0; + let mut persistence = 0.5; + + for _ in 0..octaves { + height += self.perlin.get([ + position.x as f64 * frequency, + position.y as f64 * frequency, + ]) * amplitude; + + amplitude *= persistence; + frequency *= lacuranity; + persistence *= 0.5; + } + + height + } } #[cfg(test)] From 0489a639a74e4e56350e8b1e6bf3485090d5e1c9 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Thu, 30 Jan 2025 16:36:19 +0100 Subject: [PATCH 04/68] Extract generator params --- src/server/terrain/util/generator.rs | 96 ++++++++++++++++++---------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 2d8f5422..57ee4c3d 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -32,30 +32,48 @@ impl Generator { } fn generate_block(&self, position: Vec3) -> BlockId { - let base_height = -50.0; - let mut density = self.sample_3d( - Vec3 { + let default_params = GeneratorParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 60.0, + amplitude: 10.0, + persistence: 0.5, + }; + + let terrain_height = self.sample_2d( + Vec2 { x: position.x, - y: position.y + base_height, - z: position.z, + y: position.z, }, - 4, + default_params ); - density -= position.y as f64 * 0.02; - if density > 0.7 { - BlockId::Stone - } else if density > 0.40 { - BlockId::Dirt - } else if density > 0.0 { - if self.generate_block(position + Vec3::new(0.0, 1.0, 0.0)) == BlockId::Air { - BlockId::Grass - } else { - BlockId::Dirt - } - } else { - BlockId::Air + + if (position.y as f64) < terrain_height + 20.0 { + return BlockId::Stone; } + + + // density -= position.y as f64 * 0.02; + // + // let base_block = BlockId::Stone; + + // if density > 0.7 { + // BlockId::Stone + // } else if density > 0.40 { + // BlockId::Dirt + // } else if density > 0.0 { + // if self.generate_block(position + Vec3::new(0.0, 1.0, 0.0)) == BlockId::Air { + // BlockId::Grass + // } else { + // BlockId::Dirt + // } + // } else { + // BlockId::Air + // } + + BlockId::Air } fn sample_3d(&self, position: Vec3, octaves: i32) -> f64 { @@ -80,28 +98,36 @@ impl Generator { density } - fn sample_2d(&self, position: Vec2, octaves: i32) -> f64 { - let mut height = 0.0; - let lacuranity = 2.0; - let mut frequency = 1.0 / 60.0; - let mut amplitude = 10.0; - let mut persistence = 0.5; - - for _ in 0..octaves { - height += self.perlin.get([ - position.x as f64 * frequency, - position.y as f64 * frequency, - ]) * amplitude; + fn sample_2d(&self, position: Vec2, params: GeneratorParams) -> f64 { + let sample = self.perlin.get([ + position.x as f64 * params.frequency, + position.y as f64 * params.frequency, + ]) * params.amplitude; - amplitude *= persistence; - frequency *= lacuranity; - persistence *= 0.5; + if params.octaves == 0 { + return sample; } - height + sample + self.sample_2d(position, GeneratorParams { + octaves: params.octaves - 1, + height: params.height + sample, + lacuranity: params.lacuranity, + frequency: params.frequency, + amplitude: params.amplitude * params.persistence, + persistence: params.persistence * 0.5, + }) } } +struct GeneratorParams { + octaves: i32, + height: f64, + lacuranity: f64, + frequency: f64, + amplitude: f64, + persistence: f64, +} + #[cfg(test)] mod tests { use super::*; From f6a6269a372ad19820230fad6997f17e73637bbd Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Fri, 31 Jan 2025 16:53:56 +0100 Subject: [PATCH 05/68] Update stuff (break stuff) --- src/client/player/systems/controller.rs | 6 ++-- src/server/networking/systems.rs | 3 ++ src/server/terrain/mod.rs | 1 + src/server/terrain/systems.rs | 13 ++++++-- src/server/terrain/util/generator.rs | 27 ++++------------ src/shared/networking.rs | 42 ++++++++++++++++++++++++- 6 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/client/player/systems/controller.rs b/src/client/player/systems/controller.rs index 9a39c41a..fd0ff690 100644 --- a/src/client/player/systems/controller.rs +++ b/src/client/player/systems/controller.rs @@ -36,7 +36,7 @@ pub fn setup_controller_on_area_ready_system( }, ActiveEvents::COLLISION_EVENTS, Velocity::zero(), - RigidBody::Dynamic, + RigidBody::Fixed, Sleeping::disabled(), LockedAxes::ROTATION_LOCKED, AdditionalMassProperties::Mass(1.0), @@ -45,8 +45,8 @@ pub fn setup_controller_on_area_ready_system( Transform::from_translation(SPAWN_POINT), LogicalPlayer, FpsControllerInput { - pitch: -TAU / 12.0, - yaw: TAU * 5.0 / 8.0, + pitch: -TAU / 20.0, + yaw: TAU * 5.0 / 12.0, ..default() }, FpsController { diff --git a/src/server/networking/systems.rs b/src/server/networking/systems.rs index 30b4ee82..b5fe9dd2 100644 --- a/src/server/networking/systems.rs +++ b/src/server/networking/systems.rs @@ -56,6 +56,9 @@ pub fn receive_message_system( client_id, player.position ); player_states.players.insert(client_id, player); + } + NetworkingMessage::UpdateGeneratorParams(params) => { + } NetworkingMessage::ChunkBatchRequest(positions) => { info!( diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index ae05e3c0..d96f56d8 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -13,5 +13,6 @@ impl Plugin for TerrainPlugin { app.add_event::(); app.insert_resource(resources::PastBlockUpdates::new()); app.add_systems(Startup, terrain_systems::setup_world_system); + app.insert_resource(TerrainGeneratorParams::default()); } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 83708e96..496fc633 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -1,7 +1,16 @@ use crate::prelude::*; -pub fn setup_world_system(mut chunk_manager: ResMut) { - let generator = terrain_util::generator::Generator::new(0); +pub fn setup_world_system( + mut chunk_manager: ResMut, + params: Res, +) { + let generator = terrain_util::generator::Generator::new( + 0, + TerrainGeneratorParams { + height_params: params.height_params, + density_params: params.density_params, + }, + ); let render_distance = Vec3::new(12.0, 2.0, 12.0); diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 57ee4c3d..2abee230 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -3,13 +3,15 @@ use crate::prelude::*; pub struct Generator { pub seed: u32, perlin: Perlin, + params: TerrainGeneratorParams, } impl Generator { - pub fn new(seed: u32) -> Generator { + pub fn new(seed: u32, params: TerrainGeneratorParams) -> Generator { Generator { seed, perlin: Perlin::new(seed), + params, } } @@ -32,15 +34,7 @@ impl Generator { } fn generate_block(&self, position: Vec3) -> BlockId { - - let default_params = GeneratorParams { - octaves: 4, - height: 0.0, - lacuranity: 2.0, - frequency: 1.0 / 60.0, - amplitude: 10.0, - persistence: 0.5, - }; + let default_params = &self.params.height_params; let terrain_height = self.sample_2d( Vec2 { @@ -98,7 +92,7 @@ impl Generator { density } - fn sample_2d(&self, position: Vec2, params: GeneratorParams) -> f64 { + fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { let sample = self.perlin.get([ position.x as f64 * params.frequency, position.y as f64 * params.frequency, @@ -108,7 +102,7 @@ impl Generator { return sample; } - sample + self.sample_2d(position, GeneratorParams { + sample + self.sample_2d(position, &NoiseFunctionParams { octaves: params.octaves - 1, height: params.height + sample, lacuranity: params.lacuranity, @@ -119,15 +113,6 @@ impl Generator { } } -struct GeneratorParams { - octaves: i32, - height: f64, - lacuranity: f64, - frequency: f64, - amplitude: f64, - persistence: f64, -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/shared/networking.rs b/src/shared/networking.rs index 5857faef..a91be3f5 100644 --- a/src/shared/networking.rs +++ b/src/shared/networking.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use bevy::math::{Quat, Vec3}; +use bevy::{math::{Quat, Vec3}, prelude::Resource}; use chrono::DateTime; use renet::{ChannelConfig, ClientId, ConnectionConfig, SendType}; use serde::{Deserialize, Serialize}; @@ -50,6 +50,46 @@ pub enum NetworkingMessage { SingleChatMessageSync(ChatMessage), ChatMessageSync(Vec), BlockUpdate { position: Vec3, block: BlockId }, + UpdateGeneratorParams(TerrainGeneratorParams), +} + +#[derive(Serialize, Deserialize, Debug, Resource, Copy, Clone)] +pub struct TerrainGeneratorParams { + pub height_params: NoiseFunctionParams, + pub density_params: NoiseFunctionParams, +} + +impl Default for TerrainGeneratorParams { + fn default() -> Self { + Self { + height_params: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 60.0, + amplitude: 10.0, + persistence: 0.5, + }, + density_params: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 60.0, + amplitude: 10.0, + persistence: 0.5, + }, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Copy, Clone)] +pub struct NoiseFunctionParams { + pub octaves: i32, + pub height: f64, + pub lacuranity: f64, + pub frequency: f64, + pub amplitude: f64, + pub persistence: f64, } const CHANNELS: [ChannelConfig; 3] = [ From a7c5806c263a7073088fcf2e05ca62f074d2ed15 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Fri, 31 Jan 2025 17:31:38 +0100 Subject: [PATCH 06/68] Attempt add visualizer --- src/server/terrain/systems.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 496fc633..2f205fee 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -1,3 +1,6 @@ +use bevy::ui::Node; +use bevy_flair::style::components::NodeStyleSheet; + use crate::prelude::*; pub fn setup_world_system( @@ -25,3 +28,24 @@ pub fn setup_world_system( chunk_manager.insert_chunks(chunks); } + +// visualizer + +struct NoiseImageNode {} + +pub fn setup_visualizer_system( + mut commands: Commands, + mut asset_server: ResMut, +) { + commands.spawn(( + Node::default(), + Name::new("visualizer"), + NodeStyleSheet::new(asset_server.load("visualizer.css")), + )).with_children(|parent| { + parent.spawn(( + Node::default(), + ImageNode::new(), + Name::new("noise_image"), + ) + }) +} From 4ada873bf03d445125ae54745cb7e2a230f3c230 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Fri, 31 Jan 2025 17:46:42 +0100 Subject: [PATCH 07/68] Implement generator resource, add egui system boilerplate --- src/server/networking/systems.rs | 8 +---- src/server/terrain/mod.rs | 5 ++- src/server/terrain/resources.rs | 41 +++++++++++++++++++++ src/server/terrain/systems.rs | 39 ++++++-------------- src/server/terrain/util/generator.rs | 53 +++++++++++++--------------- src/server/terrain/util/mod.rs | 1 - src/shared/networking.rs | 32 +---------------- 7 files changed, 81 insertions(+), 98 deletions(-) diff --git a/src/server/networking/systems.rs b/src/server/networking/systems.rs index b5fe9dd2..d713da48 100644 --- a/src/server/networking/systems.rs +++ b/src/server/networking/systems.rs @@ -8,6 +8,7 @@ pub fn receive_message_system( #[cfg(feature = "chat")] mut chat_message_events: EventWriter< chat_events::PlayerChatMessageSendEvent, >, + generator: Res, ) { for client_id in server.clients_id() { while let Some(message) = server.receive_message(client_id, DefaultChannel::ReliableOrdered) @@ -56,9 +57,6 @@ pub fn receive_message_system( client_id, player.position ); player_states.players.insert(client_id, player); - } - NetworkingMessage::UpdateGeneratorParams(params) => { - } NetworkingMessage::ChunkBatchRequest(positions) => { info!( @@ -75,11 +73,7 @@ pub fn receive_message_system( Some(chunk) => *chunk, None => { let mut chunk = Chunk::new(position); - - let generator = terrain_util::generator::Generator::new(0); - generator.generate_chunk(&mut chunk); - chunk } } diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index d96f56d8..78629adb 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -13,6 +13,9 @@ impl Plugin for TerrainPlugin { app.add_event::(); app.insert_resource(resources::PastBlockUpdates::new()); app.add_systems(Startup, terrain_systems::setup_world_system); - app.insert_resource(TerrainGeneratorParams::default()); + app.insert_resource(resources::Generator::default()); + + // visualizer + app.add_systems(Update, terrain_systems::render_visualizer_system); } } diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index c817bb53..8108eb60 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -20,3 +20,44 @@ impl PastBlockUpdates { } } } + +#[derive(Resource)] +pub struct Generator { + pub seed: u32, + pub perlin: Perlin, // TODO: reduce visibility of attributes on this struct decl + pub params: TerrainGeneratorParams, +} + +impl Default for Generator { + fn default() -> Self { + Self::new(0) + } +} + +pub struct TerrainGeneratorParams { + pub height_params: NoiseFunctionParams, + pub density_params: NoiseFunctionParams, +} + +impl Default for TerrainGeneratorParams { + fn default() -> Self { + Self { + height_params: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 60.0, + amplitude: 10.0, + persistence: 0.5, + }, + density_params: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 60.0, + amplitude: 10.0, + persistence: 0.5, + }, + } + } +} diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 2f205fee..513a2d85 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -1,20 +1,9 @@ -use bevy::ui::Node; -use bevy_flair::style::components::NodeStyleSheet; - use crate::prelude::*; pub fn setup_world_system( mut chunk_manager: ResMut, - params: Res, + generator: Res, ) { - let generator = terrain_util::generator::Generator::new( - 0, - TerrainGeneratorParams { - height_params: params.height_params, - density_params: params.density_params, - }, - ); - let render_distance = Vec3::new(12.0, 2.0, 12.0); info!("Generating chunks"); @@ -29,23 +18,15 @@ pub fn setup_world_system( chunk_manager.insert_chunks(chunks); } -// visualizer +pub use visualizer::*; -struct NoiseImageNode {} +mod visualizer { -pub fn setup_visualizer_system( - mut commands: Commands, - mut asset_server: ResMut, -) { - commands.spawn(( - Node::default(), - Name::new("visualizer"), - NodeStyleSheet::new(asset_server.load("visualizer.css")), - )).with_children(|parent| { - parent.spawn(( - Node::default(), - ImageNode::new(), - Name::new("noise_image"), - ) - }) + use bevy_inspector_egui::{bevy_egui::EguiContexts, egui}; + + pub fn render_visualizer_system(mut contexts: EguiContexts) { + egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { + ui.label("world"); + }); + } } diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 2abee230..9074f687 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -1,13 +1,13 @@ -use crate::prelude::*; +use terrain_resources::{Generator, TerrainGeneratorParams}; -pub struct Generator { - pub seed: u32, - perlin: Perlin, - params: TerrainGeneratorParams, -} +use crate::prelude::*; impl Generator { - pub fn new(seed: u32, params: TerrainGeneratorParams) -> Generator { + pub fn new(seed: u32) -> Generator { + Self::new_with_params(seed, TerrainGeneratorParams::default()) + } + + pub fn new_with_params(seed: u32, params: TerrainGeneratorParams) -> Generator { Generator { seed, perlin: Perlin::new(seed), @@ -41,14 +41,13 @@ impl Generator { x: position.x, y: position.z, }, - default_params + default_params, ); if (position.y as f64) < terrain_height + 20.0 { return BlockId::Stone; } - // density -= position.y as f64 * 0.02; // // let base_block = BlockId::Stone; @@ -67,7 +66,7 @@ impl Generator { // BlockId::Air // } - BlockId::Air + BlockId::Air } fn sample_3d(&self, position: Vec3, octaves: i32) -> f64 { @@ -102,32 +101,29 @@ impl Generator { return sample; } - sample + self.sample_2d(position, &NoiseFunctionParams { - octaves: params.octaves - 1, - height: params.height + sample, - lacuranity: params.lacuranity, - frequency: params.frequency, - amplitude: params.amplitude * params.persistence, - persistence: params.persistence * 0.5, - }) + sample + + self.sample_2d( + position, + &NoiseFunctionParams { + octaves: params.octaves - 1, + height: params.height + sample, + lacuranity: params.lacuranity, + frequency: params.frequency, + amplitude: params.amplitude * params.persistence, + persistence: params.persistence * 0.5, + }, + ) } } #[cfg(test)] mod tests { use super::*; - - #[test] - fn test_generator_new() { - let seed = 42; - let generator = Generator::new(seed); - assert_eq!(generator.seed, seed); - } + use terrain_resources::Generator; #[test] fn test_generate_chunk() { - let seed = 42; - let generator = Generator::new(seed); + let generator = Generator::default(); let mut chunk = Chunk::new(Vec3::new(0.0, 0.0, 0.0)); generator.generate_chunk(&mut chunk); @@ -137,8 +133,7 @@ mod tests { #[test] fn test_sample_3d() { - let seed = 42; - let generator = Generator::new(seed); + let generator = Generator::default(); let position = Vec3::new(0.0, 0.0, 0.0); let density = generator.sample_3d(position, 4); diff --git a/src/server/terrain/util/mod.rs b/src/server/terrain/util/mod.rs index 48962a8a..37fda818 100644 --- a/src/server/terrain/util/mod.rs +++ b/src/server/terrain/util/mod.rs @@ -2,4 +2,3 @@ pub mod blocks; pub mod generator; pub use blocks::*; -pub use generator::*; diff --git a/src/shared/networking.rs b/src/shared/networking.rs index a91be3f5..f0f3ddfe 100644 --- a/src/shared/networking.rs +++ b/src/shared/networking.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use bevy::{math::{Quat, Vec3}, prelude::Resource}; +use bevy::math::{Quat, Vec3}; use chrono::DateTime; use renet::{ChannelConfig, ClientId, ConnectionConfig, SendType}; use serde::{Deserialize, Serialize}; @@ -50,36 +50,6 @@ pub enum NetworkingMessage { SingleChatMessageSync(ChatMessage), ChatMessageSync(Vec), BlockUpdate { position: Vec3, block: BlockId }, - UpdateGeneratorParams(TerrainGeneratorParams), -} - -#[derive(Serialize, Deserialize, Debug, Resource, Copy, Clone)] -pub struct TerrainGeneratorParams { - pub height_params: NoiseFunctionParams, - pub density_params: NoiseFunctionParams, -} - -impl Default for TerrainGeneratorParams { - fn default() -> Self { - Self { - height_params: NoiseFunctionParams { - octaves: 4, - height: 0.0, - lacuranity: 2.0, - frequency: 1.0 / 60.0, - amplitude: 10.0, - persistence: 0.5, - }, - density_params: NoiseFunctionParams { - octaves: 4, - height: 0.0, - lacuranity: 2.0, - frequency: 1.0 / 60.0, - amplitude: 10.0, - persistence: 0.5, - }, - } - } } #[derive(Serialize, Deserialize, Debug, Copy, Clone)] From 4b346db69ba7bd2b2d541ee52e40aa3ea2331a8c Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 00:04:15 +0100 Subject: [PATCH 08/68] Update terrain gen, break stuff --- src/server/terrain/mod.rs | 2 + src/server/terrain/resources.rs | 18 +++++++++ src/server/terrain/systems.rs | 56 +++++++++++++++++++++++++++- src/server/terrain/util/generator.rs | 2 +- 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index 78629adb..5da5c48a 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -16,6 +16,8 @@ impl Plugin for TerrainPlugin { app.insert_resource(resources::Generator::default()); // visualizer + app.insert_resource(resources::NoiseTexture::default()); app.add_systems(Update, terrain_systems::render_visualizer_system); + // app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); } } diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 8108eb60..cfc50a19 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -1,5 +1,6 @@ use crate::prelude::*; +use bevy::{asset::Handle, image::Image}; use terrain_events::BlockUpdateEvent; #[derive(Resource)] @@ -61,3 +62,20 @@ impl Default for TerrainGeneratorParams { } } } + +// visualizer + +#[derive(Resource)] +pub struct NoiseTexture { + pub texture: Handle, + pub size: Vec2, +} + +impl Default for NoiseTexture { + fn default() -> Self { + NoiseTexture { + texture: Handle::default(), + size: Vec2::ZERO, + } + } +} diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 513a2d85..a0cfd4a0 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -6,6 +6,8 @@ pub fn setup_world_system( ) { let render_distance = Vec3::new(12.0, 2.0, 12.0); + return; + info!("Generating chunks"); let mut chunks = ChunkManager::instantiate_chunks(Vec3::ZERO, render_distance); @@ -22,11 +24,61 @@ pub use visualizer::*; mod visualizer { - use bevy_inspector_egui::{bevy_egui::EguiContexts, egui}; + use bevy::{ + asset::RenderAssetUsages, image::Image, log::info, math::{Vec2, Vec3}, prelude::Res, render::render_resource::{Extent3d, TextureDimension, TextureFormat} + }; + use bevy_inspector_egui::{ + bevy_egui::EguiContexts, + egui::{self, load::SizedTexture, Color32, ColorImage, ImageData, TextureOptions}, + }; + + use super::terrain_resources; + + fn generate_terrain_heightmap( + generator: &terrain_resources::Generator, + origin: Vec3, + size: Vec3, + ) -> ImageData { + let mut data = vec![0; (size.x * size.z) as usize]; + + let width = size.x as usize; + let height = size.z as usize; + + for x in 0..width { + for z in 0..height { + let sample_position = Vec2::new((origin.x + x as f32) / 20.0, (origin.z + z as f32) / 20.0); + let value = generator.sample_2d( + sample_position.try_into().unwrap(), + &generator.params.height_params, + ); + let value = value * size.y as f64; + let value = value as u8; + data[(x + z * width) as usize] = value; + } + } + + let color_data: Vec = data.iter().map(|&value| Color32::from_gray(value)).collect(); + + let color_image: ColorImage = ColorImage { + size: [width, height], + pixels: color_data, + }; + + ImageData::Color(color_image.into()) + } + + pub fn render_visualizer_system( + mut contexts: EguiContexts, + generator: Res, + ) { + let image_data = + generate_terrain_heightmap(&generator, Vec3::ZERO, Vec3::new(128.0, 128.0, 128.0)); + + let texture_handle = contexts.ctx_mut().load_texture("Foo", image_data, TextureOptions::default()); - pub fn render_visualizer_system(mut contexts: EguiContexts) { egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { ui.label("world"); + ui.image(&texture_handle); }); } } diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 9074f687..2ea6d10e 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -91,7 +91,7 @@ impl Generator { density } - fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { + pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { let sample = self.perlin.get([ position.x as f64 * params.frequency, position.y as f64 * params.frequency, From 4a571830d138406550da6610a13bee3cf3b89d6e Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 00:51:08 +0100 Subject: [PATCH 09/68] Implement basic visualizer system --- src/server/terrain/mod.rs | 2 +- src/server/terrain/resources.rs | 7 +++-- src/server/terrain/systems.rs | 50 +++++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index 5da5c48a..aada014c 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -17,7 +17,7 @@ impl Plugin for TerrainPlugin { // visualizer app.insert_resource(resources::NoiseTexture::default()); + app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); app.add_systems(Update, terrain_systems::render_visualizer_system); - // app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); } } diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index cfc50a19..37817bbf 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -1,6 +1,9 @@ +use std::sync::Arc; + use crate::prelude::*; use bevy::{asset::Handle, image::Image}; +use bevy_inspector_egui::egui::{epaint::TextureManager, mutex::RwLock, TextureHandle}; use terrain_events::BlockUpdateEvent; #[derive(Resource)] @@ -67,14 +70,14 @@ impl Default for TerrainGeneratorParams { #[derive(Resource)] pub struct NoiseTexture { - pub texture: Handle, + pub texture: Option, pub size: Vec2, } impl Default for NoiseTexture { fn default() -> Self { NoiseTexture { - texture: Handle::default(), + texture: None, size: Vec2::ZERO, } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index a0cfd4a0..a43eb0f5 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -25,14 +25,19 @@ pub use visualizer::*; mod visualizer { use bevy::{ - asset::RenderAssetUsages, image::Image, log::info, math::{Vec2, Vec3}, prelude::Res, render::render_resource::{Extent3d, TextureDimension, TextureFormat} + asset::RenderAssetUsages, + image::Image, + log::info, + math::{Vec2, Vec3}, + prelude::{Res, ResMut}, + render::render_resource::{Extent3d, TextureDimension, TextureFormat}, }; use bevy_inspector_egui::{ bevy_egui::EguiContexts, egui::{self, load::SizedTexture, Color32, ColorImage, ImageData, TextureOptions}, }; - use super::terrain_resources; + use super::{chat_resources, player_resources, terrain_resources}; fn generate_terrain_heightmap( generator: &terrain_resources::Generator, @@ -46,7 +51,8 @@ mod visualizer { for x in 0..width { for z in 0..height { - let sample_position = Vec2::new((origin.x + x as f32) / 20.0, (origin.z + z as f32) / 20.0); + let sample_position = + Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); let value = generator.sample_2d( sample_position.try_into().unwrap(), &generator.params.height_params, @@ -57,7 +63,10 @@ mod visualizer { } } - let color_data: Vec = data.iter().map(|&value| Color32::from_gray(value)).collect(); + let color_data: Vec = data + .iter() + .map(|&value| Color32::from_gray(value)) + .collect(); let color_image: ColorImage = ColorImage { size: [width, height], @@ -67,18 +76,37 @@ mod visualizer { ImageData::Color(color_image.into()) } - pub fn render_visualizer_system( + pub fn prepare_visualizer_texture_system( mut contexts: EguiContexts, - generator: Res, + generator: ResMut, + mut noise_texture: ResMut, ) { let image_data = generate_terrain_heightmap(&generator, Vec3::ZERO, Vec3::new(128.0, 128.0, 128.0)); - let texture_handle = contexts.ctx_mut().load_texture("Foo", image_data, TextureOptions::default()); + noise_texture.texture = Some(contexts.ctx_mut().load_texture( + "terrain-texture", + image_data, + TextureOptions::default(), + )); + noise_texture.size = Vec2::new(128.0, 128.0); + } - egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { - ui.label("world"); - ui.image(&texture_handle); - }); + pub fn render_visualizer_system( + mut contexts: EguiContexts, + noise_texture: ResMut, + ) { + match &noise_texture.texture { + Some(texture_handle) => { + egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { + ui.label("world"); + ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( + texture_handle.id(), + texture_handle.size_vec2(), + ))); + }); + } + None => { } + } } } From 5c083265c4bd1a1d85baa3b20f9d5b788f142d96 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 01:11:04 +0100 Subject: [PATCH 10/68] Update visualizer --- src/server/terrain/events.rs | 4 ++ src/server/terrain/mod.rs | 3 ++ src/server/terrain/systems.rs | 77 ++++++++++++++++++++++++++++------- 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/src/server/terrain/events.rs b/src/server/terrain/events.rs index 872816c7..4d453006 100644 --- a/src/server/terrain/events.rs +++ b/src/server/terrain/events.rs @@ -5,3 +5,7 @@ pub struct BlockUpdateEvent { pub position: Vec3, pub block: BlockId, } + +// visualizer +#[derive(Event)] +pub struct RegenerateHeightMapEvent; diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index aada014c..3336f6f1 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -19,5 +19,8 @@ impl Plugin for TerrainPlugin { app.insert_resource(resources::NoiseTexture::default()); app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); app.add_systems(Update, terrain_systems::render_visualizer_system); + app.add_systems(Update, terrain_systems::regenerate_heightmap_system); + + app.add_event::(); } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index a43eb0f5..d779c8a1 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -29,7 +29,7 @@ mod visualizer { image::Image, log::info, math::{Vec2, Vec3}, - prelude::{Res, ResMut}, + prelude::{EventReader, EventWriter, Res, ResMut}, render::render_resource::{Extent3d, TextureDimension, TextureFormat}, }; use bevy_inspector_egui::{ @@ -37,7 +37,7 @@ mod visualizer { egui::{self, load::SizedTexture, Color32, ColorImage, ImageData, TextureOptions}, }; - use super::{chat_resources, player_resources, terrain_resources}; + use super::{chat_resources, player_resources, terrain_events, terrain_resources}; fn generate_terrain_heightmap( generator: &terrain_resources::Generator, @@ -76,37 +76,86 @@ mod visualizer { ImageData::Color(color_image.into()) } - pub fn prepare_visualizer_texture_system( - mut contexts: EguiContexts, + pub fn regenerate_heightmap_system( + mut events: EventReader, generator: ResMut, mut noise_texture: ResMut, + mut contexts: EguiContexts, ) { - let image_data = - generate_terrain_heightmap(&generator, Vec3::ZERO, Vec3::new(128.0, 128.0, 128.0)); - - noise_texture.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), - )); - noise_texture.size = Vec2::new(128.0, 128.0); + + for _ in events.read() { + let width = 1024; + let height = 1024; + let depth = 1024; + + let image_data = generate_terrain_heightmap( + &generator, + Vec3::ZERO, + Vec3::new(width as f32, height as f32, depth as f32), + ); + + noise_texture.texture = Some(contexts.ctx_mut().load_texture( + "terrain-texture", + image_data, + TextureOptions::default(), + )); + noise_texture.size = Vec2::new(width as f32, height as f32); + } + } + + pub fn prepare_visualizer_texture_system( + mut event_writer: EventWriter, + ) { + event_writer.send(terrain_events::RegenerateHeightMapEvent); } pub fn render_visualizer_system( mut contexts: EguiContexts, noise_texture: ResMut, + mut generator: ResMut, + mut event_writer: EventWriter, ) { match &noise_texture.texture { Some(texture_handle) => { egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { ui.label("world"); + + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.octaves, + 1..=8, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.height, + 0.0..=10.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.lacuranity, + 0.0..=4.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.frequency, + 0.0..=1.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.amplitude, + 0.0..=20.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.persistence, + 0.0..=1.0, + )); + + if ui.button("Regenerate").clicked() { + event_writer.send(terrain_events::RegenerateHeightMapEvent); + }; + ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( texture_handle.id(), texture_handle.size_vec2(), ))); }); } - None => { } + None => {} } } } From c9166eb45422539a7559230bd0f0dd33e9ace617 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 01:11:12 +0100 Subject: [PATCH 11/68] Fix linter --- src/server/terrain/resources.rs | 5 +- src/server/terrain/systems.rs | 100 +++++++++++++++----------------- 2 files changed, 47 insertions(+), 58 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 37817bbf..f61beaae 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -1,9 +1,6 @@ -use std::sync::Arc; - use crate::prelude::*; -use bevy::{asset::Handle, image::Image}; -use bevy_inspector_egui::egui::{epaint::TextureManager, mutex::RwLock, TextureHandle}; +use bevy_inspector_egui::egui::TextureHandle; use terrain_events::BlockUpdateEvent; #[derive(Resource)] diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index d779c8a1..daa7ddd4 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -1,7 +1,7 @@ use crate::prelude::*; pub fn setup_world_system( - mut chunk_manager: ResMut, + chunk_manager: ResMut, generator: Res, ) { let render_distance = Vec3::new(12.0, 2.0, 12.0); @@ -25,19 +25,15 @@ pub use visualizer::*; mod visualizer { use bevy::{ - asset::RenderAssetUsages, - image::Image, - log::info, math::{Vec2, Vec3}, - prelude::{EventReader, EventWriter, Res, ResMut}, - render::render_resource::{Extent3d, TextureDimension, TextureFormat}, + prelude::{EventReader, EventWriter, ResMut}, }; use bevy_inspector_egui::{ bevy_egui::EguiContexts, - egui::{self, load::SizedTexture, Color32, ColorImage, ImageData, TextureOptions}, + egui::{self, Color32, ColorImage, ImageData, TextureOptions}, }; - use super::{chat_resources, player_resources, terrain_events, terrain_resources}; + use super::{terrain_events, terrain_resources}; fn generate_terrain_heightmap( generator: &terrain_resources::Generator, @@ -59,7 +55,7 @@ mod visualizer { ); let value = value * size.y as f64; let value = value as u8; - data[(x + z * width) as usize] = value; + data[x + z * width] = value; } } @@ -82,7 +78,6 @@ mod visualizer { mut noise_texture: ResMut, mut contexts: EguiContexts, ) { - for _ in events.read() { let width = 1024; let height = 1024; @@ -95,9 +90,9 @@ mod visualizer { ); noise_texture.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), + "terrain-texture", + image_data, + TextureOptions::default(), )); noise_texture.size = Vec2::new(width as f32, height as f32); } @@ -115,47 +110,44 @@ mod visualizer { mut generator: ResMut, mut event_writer: EventWriter, ) { - match &noise_texture.texture { - Some(texture_handle) => { - egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { - ui.label("world"); - - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.octaves, - 1..=8, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.height, - 0.0..=10.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.lacuranity, - 0.0..=4.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.frequency, - 0.0..=1.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.amplitude, - 0.0..=20.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.persistence, - 0.0..=1.0, - )); - - if ui.button("Regenerate").clicked() { - event_writer.send(terrain_events::RegenerateHeightMapEvent); - }; - - ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( - texture_handle.id(), - texture_handle.size_vec2(), - ))); - }); - } - None => {} + if let Some(texture_handle) = &noise_texture.texture { + egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { + ui.label("world"); + + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.octaves, + 1..=8, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.height, + 0.0..=10.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.lacuranity, + 0.0..=4.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.frequency, + 0.0..=1.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.amplitude, + 0.0..=20.0, + )); + ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.persistence, + 0.0..=1.0, + )); + + if ui.button("Regenerate").clicked() { + event_writer.send(terrain_events::RegenerateHeightMapEvent); + }; + + ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( + texture_handle.id(), + texture_handle.size_vec2(), + ))); + }); } } } From 30b19706f811e29019a971e8a45e0c48974f55c0 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 01:32:24 +0100 Subject: [PATCH 12/68] Update visualizer --- src/server/terrain/systems.rs | 60 ++++++++++++++-------------- src/server/terrain/util/generator.rs | 2 +- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index daa7ddd4..06b0b5f7 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -79,9 +79,9 @@ mod visualizer { mut contexts: EguiContexts, ) { for _ in events.read() { - let width = 1024; - let height = 1024; - let depth = 1024; + let width = 512; + let height = 512; + let depth = 512; let image_data = generate_terrain_heightmap( &generator, @@ -114,32 +114,34 @@ mod visualizer { egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { ui.label("world"); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.octaves, - 1..=8, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.height, - 0.0..=10.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.lacuranity, - 0.0..=4.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.frequency, - 0.0..=1.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.amplitude, - 0.0..=20.0, - )); - ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.persistence, - 0.0..=1.0, - )); - - if ui.button("Regenerate").clicked() { + let mut changed = false; + + changed |= ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.octaves, + 1..=8, + ).text("octaves")).changed(); + changed |= ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.height, + 0.0..=10.0, + ).text("height")).changed(); + changed |= ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.lacuranity, + 0.0..=4.0, + ).text("lacuranity")).changed(); + changed |= ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.frequency, + 0.0..=1.0, + ).text("frequency")).changed(); + changed |= ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.amplitude, + 0.0..=20.0, + ).text("amplitude")).changed(); + changed |= ui.add(egui::widgets::Slider::new( + &mut generator.params.height_params.persistence, + 0.0..=1.0, + ).text("persistence")).changed(); + + if changed { event_writer.send(terrain_events::RegenerateHeightMapEvent); }; diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 2ea6d10e..c0e8f96c 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -112,7 +112,7 @@ impl Generator { amplitude: params.amplitude * params.persistence, persistence: params.persistence * 0.5, }, - ) + ) * params.persistence } } From 35e3920bbaece62a76a6346c94c2853098f942e6 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 01:48:54 +0100 Subject: [PATCH 13/68] Update generator, fix fractal noise --- src/server/terrain/systems.rs | 78 +++++++++++++++++++--------- src/server/terrain/util/generator.rs | 9 ++-- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 06b0b5f7..3394bbfe 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -116,30 +116,60 @@ mod visualizer { let mut changed = false; - changed |= ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.octaves, - 1..=8, - ).text("octaves")).changed(); - changed |= ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.height, - 0.0..=10.0, - ).text("height")).changed(); - changed |= ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.lacuranity, - 0.0..=4.0, - ).text("lacuranity")).changed(); - changed |= ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.frequency, - 0.0..=1.0, - ).text("frequency")).changed(); - changed |= ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.amplitude, - 0.0..=20.0, - ).text("amplitude")).changed(); - changed |= ui.add(egui::widgets::Slider::new( - &mut generator.params.height_params.persistence, - 0.0..=1.0, - ).text("persistence")).changed(); + changed |= ui + .add( + egui::widgets::Slider::new( + &mut generator.params.height_params.octaves, + 1..=8, + ) + .text("octaves"), + ) + .changed(); + changed |= ui + .add( + egui::widgets::Slider::new( + &mut generator.params.height_params.height, + 0.0..=10.0, + ) + .text("height"), + ) + .changed(); + changed |= ui + .add( + egui::widgets::Slider::new( + &mut generator.params.height_params.lacuranity, + 0.0..=4.0, + ) + .text("lacuranity"), + ) + .changed(); + changed |= ui + .add( + egui::widgets::Slider::new( + &mut generator.params.height_params.frequency, + 0.0..=1.0, + ) + .text("frequency"), + ) + .changed(); + changed |= ui + .add( + egui::widgets::Slider::new( + &mut generator.params.height_params.amplitude, + 0.0..=20.0, + ) + .text("amplitude"), + ) + .changed(); + changed |= ui + .add( + egui::widgets::Slider::new( + &mut generator.params.height_params.persistence, + 0.0..=1.0, + ) + .text("persistence"), + ) + .changed(); if changed { event_writer.send(terrain_events::RegenerateHeightMapEvent); diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index c0e8f96c..7210fe18 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -103,14 +103,17 @@ impl Generator { sample + self.sample_2d( - position, + Vec2 { + x: position.x * params.lacuranity as f32, + y: position.y * params.lacuranity as f32, + }, &NoiseFunctionParams { octaves: params.octaves - 1, height: params.height + sample, lacuranity: params.lacuranity, frequency: params.frequency, - amplitude: params.amplitude * params.persistence, - persistence: params.persistence * 0.5, + amplitude: params.amplitude, + persistence: params.persistence, }, ) * params.persistence } From 83816e690c34c610cb79e3245fd434511aa9f993 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 01:51:14 +0100 Subject: [PATCH 14/68] Radd terrain gen, improve params --- src/server/terrain/resources.rs | 4 ++-- src/server/terrain/systems.rs | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index f61beaae..bcc8cd9f 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -47,8 +47,8 @@ impl Default for TerrainGeneratorParams { octaves: 4, height: 0.0, lacuranity: 2.0, - frequency: 1.0 / 60.0, - amplitude: 10.0, + frequency: 1.0 / 120.0, + amplitude: 20.0, persistence: 0.5, }, density_params: NoiseFunctionParams { diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 3394bbfe..be070981 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -1,13 +1,11 @@ use crate::prelude::*; pub fn setup_world_system( - chunk_manager: ResMut, + mut chunk_manager: ResMut, generator: Res, ) { let render_distance = Vec3::new(12.0, 2.0, 12.0); - return; - info!("Generating chunks"); let mut chunks = ChunkManager::instantiate_chunks(Vec3::ZERO, render_distance); From 4bed5dc914de907ae313a82283c2b41cc9ae3882 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 02:08:10 +0100 Subject: [PATCH 15/68] Update terrain --- src/server/terrain/resources.rs | 2 +- src/server/terrain/util/generator.rs | 49 +++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index bcc8cd9f..89faa693 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -48,7 +48,7 @@ impl Default for TerrainGeneratorParams { height: 0.0, lacuranity: 2.0, frequency: 1.0 / 120.0, - amplitude: 20.0, + amplitude: 30.0, persistence: 0.5, }, density_params: NoiseFunctionParams { diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 7210fe18..65f38196 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -45,9 +45,17 @@ impl Generator { ); if (position.y as f64) < terrain_height + 20.0 { - return BlockId::Stone; + let max_slope = self.calculate_max_slope(position, &default_params); + if max_slope > 3.0 { + return BlockId::Stone; + } else if max_slope > 1.0 { + return BlockId::Dirt; + } else { + return BlockId::Grass; + } } + // density -= position.y as f64 * 0.02; // // let base_block = BlockId::Stone; @@ -69,6 +77,45 @@ impl Generator { BlockId::Air } + fn get_sample_positions(&self, position: Vec3, epsilon: f32) -> [Vec2; 5] { + let mut positions = [Vec2::ZERO; 5]; + + let Vec3 { x, y: _, z: y } = position; + + positions[0] = Vec2 { x, y }; + positions[1] = Vec2 { x: x + epsilon, y }; + positions[2] = Vec2 { x: x - epsilon, y }; + positions[3] = Vec2 { x, y: y + epsilon }; + positions[4] = Vec2 { x, y: y - epsilon }; + + positions + } + + fn get_terrain_samples(&self, position: Vec3, params: &NoiseFunctionParams) -> [f64; 5] { + let sample_positions = self.get_sample_positions(position, 1.0); + + sample_positions.map(|sample_position| { + self.sample_2d(sample_position, ¶ms).abs() + }) + } + + fn calculate_max_slope(&self, position: Vec3, params: &NoiseFunctionParams) -> f64 { + let samples = self.get_terrain_samples(position, params); + + let mut max = 0.0; + + let main_sample = samples[0]; + + for i in 1..samples.len() { + let sample = samples[i]; + if main_sample - sample > max { + max = main_sample - sample; + } + } + + max + } + fn sample_3d(&self, position: Vec3, octaves: i32) -> f64 { let mut density = 0.0; let lacuranity = 2.0; From 33adfcc2d5003788cd630f8444d04e5a4929d394 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 11:14:57 +0100 Subject: [PATCH 16/68] Update world regeneration --- src/client/networking/systems.rs | 7 +++++++ src/client/terrain/events.rs | 3 +++ src/client/terrain/mod.rs | 1 + src/client/terrain/systems.rs | 11 +++++++++-- src/server/networking/systems.rs | 21 ++++++++++++++------- src/server/terrain/util/generator.rs | 26 +++----------------------- src/shared/networking.rs | 4 +++- src/shared/terrain.rs | 15 +++++++++++++++ 8 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/client/networking/systems.rs b/src/client/networking/systems.rs index d5491b34..4eeb9e73 100644 --- a/src/client/networking/systems.rs +++ b/src/client/networking/systems.rs @@ -9,6 +9,8 @@ pub fn receive_message_system( mut block_update_events: ResMut>, mut chunk_manager: ResMut, mut chunk_mesh_events: ResMut>, + // visualizer + mut world_regenerate_events: ResMut>, #[cfg(feature = "chat")] mut chat_events: ResMut>, #[cfg(feature = "chat")] mut single_chat_events: ResMut< Events, @@ -95,6 +97,11 @@ pub fn receive_message_system( player_sync_events .send(remote_player_events::RemotePlayerSyncEvent { players: event }); } + // visualizer + NetworkingMessage::ServerAsksClientNicelyToRerequestChunkBatch() => { + info!("Client asked for chunk batch."); + world_regenerate_events.send(terrain_events::WorldRegenerateEvent); + } _ => { warn!("Received unknown message type. (ReliableUnordered)"); } diff --git a/src/client/terrain/events.rs b/src/client/terrain/events.rs index 5b3fb25e..9280405e 100644 --- a/src/client/terrain/events.rs +++ b/src/client/terrain/events.rs @@ -11,3 +11,6 @@ pub struct BlockUpdateEvent { pub block: BlockId, pub from_network: bool, } + +#[derive(Event)] +pub struct WorldRegenerateEvent; diff --git a/src/client/terrain/mod.rs b/src/client/terrain/mod.rs index 0660635e..1cf3d69e 100644 --- a/src/client/terrain/mod.rs +++ b/src/client/terrain/mod.rs @@ -16,6 +16,7 @@ impl Plugin for TerrainPlugin { app.insert_resource(util::TextureManager::new()); app.add_event::(); app.add_event::(); + app.add_event::(); app.add_systems(Startup, terrain_systems::prepare_spawn_area_system); app.add_systems(Startup, terrain_systems::generate_world_system); app.add_systems(Update, terrain_systems::handle_chunk_mesh_update_events); diff --git a/src/client/terrain/systems.rs b/src/client/terrain/systems.rs index 478299ad..74c011db 100644 --- a/src/client/terrain/systems.rs +++ b/src/client/terrain/systems.rs @@ -6,7 +6,7 @@ pub fn prepare_spawn_area_system(mut client: ResMut) { let chunks = ChunkManager::instantiate_chunks(Vec3::ZERO, Vec3::ONE); let positions: Vec = chunks.into_iter().map(|chunk| chunk.position).collect(); - let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest(positions)); + let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest{ positions, force: false }); info!("requesting world"); client.send_message(DefaultChannel::ReliableUnordered, message.unwrap()); } @@ -32,7 +32,7 @@ pub fn generate_world_system( "Sending chunk batch request for {:?}", request_positions.len() ); - let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest(request_positions)); + let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest{ positions: request_positions, force: false }); info!("requesting chunks #{}", index); client.send_message(DefaultChannel::ReliableUnordered, message.unwrap()); }); @@ -162,3 +162,10 @@ fn spawn_chunk( }, )); } + +// visualizer +pub fn handle_terrain_regeneration_events( + mut client: ResMut, + mut world_regenerate_events: ResMut>, +) { +} diff --git a/src/server/networking/systems.rs b/src/server/networking/systems.rs index d713da48..4356708d 100644 --- a/src/server/networking/systems.rs +++ b/src/server/networking/systems.rs @@ -58,7 +58,7 @@ pub fn receive_message_system( ); player_states.players.insert(client_id, player); } - NetworkingMessage::ChunkBatchRequest(positions) => { + NetworkingMessage::ChunkBatchRequest { positions, force } => { info!( "Received chunk batch request at {:?} from client {}", positions, client_id @@ -69,12 +69,19 @@ pub fn receive_message_system( .map(|position| { let chunk = chunk_manager.get_chunk(position); - match chunk { - Some(chunk) => *chunk, - None => { - let mut chunk = Chunk::new(position); - generator.generate_chunk(&mut chunk); - chunk + // visualizer? + if force { + let mut chunk = Chunk::new(position); + generator.generate_chunk(&mut chunk); + chunk + } else { + match chunk { + Some(chunk) => *chunk, + None => { + let mut chunk = Chunk::new(position); + generator.generate_chunk(&mut chunk); + chunk + } } } }) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 65f38196..6498e870 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -46,7 +46,7 @@ impl Generator { if (position.y as f64) < terrain_height + 20.0 { let max_slope = self.calculate_max_slope(position, &default_params); - if max_slope > 3.0 { + if max_slope > 4.0 { return BlockId::Stone; } else if max_slope > 1.0 { return BlockId::Dirt; @@ -55,25 +55,6 @@ impl Generator { } } - - // density -= position.y as f64 * 0.02; - // - // let base_block = BlockId::Stone; - - // if density > 0.7 { - // BlockId::Stone - // } else if density > 0.40 { - // BlockId::Dirt - // } else if density > 0.0 { - // if self.generate_block(position + Vec3::new(0.0, 1.0, 0.0)) == BlockId::Air { - // BlockId::Grass - // } else { - // BlockId::Dirt - // } - // } else { - // BlockId::Air - // } - BlockId::Air } @@ -92,7 +73,7 @@ impl Generator { } fn get_terrain_samples(&self, position: Vec3, params: &NoiseFunctionParams) -> [f64; 5] { - let sample_positions = self.get_sample_positions(position, 1.0); + let sample_positions = self.get_sample_positions(position, 0.001); sample_positions.map(|sample_position| { self.sample_2d(sample_position, ¶ms).abs() @@ -106,8 +87,7 @@ impl Generator { let main_sample = samples[0]; - for i in 1..samples.len() { - let sample = samples[i]; + for sample in samples.iter().skip(1) { if main_sample - sample > max { max = main_sample - sample; } diff --git a/src/shared/networking.rs b/src/shared/networking.rs index f0f3ddfe..6c7ad27a 100644 --- a/src/shared/networking.rs +++ b/src/shared/networking.rs @@ -44,12 +44,14 @@ pub enum NetworkingMessage { PlayerLeave(ClientId), PlayerUpdate(PlayerState), PlayerSync(HashMap), - ChunkBatchRequest(Vec), + ChunkBatchRequest{ positions: Vec, force: bool }, ChunkBatchResponse(Vec), ChatMessageSend(String), SingleChatMessageSync(ChatMessage), ChatMessageSync(Vec), BlockUpdate { position: Vec3, block: BlockId }, + // visualizer + ServerAsksClientNicelyToRerequestChunkBatch(), } #[derive(Serialize, Deserialize, Debug, Copy, Clone)] diff --git a/src/shared/terrain.rs b/src/shared/terrain.rs index 8437828a..7173001c 100644 --- a/src/shared/terrain.rs +++ b/src/shared/terrain.rs @@ -195,6 +195,10 @@ impl ChunkManager { let chunk_position = position / CHUNK_SIZE as f32; self.get_chunk_mut(chunk_position) } + + pub fn get_all_chunk_positions(&self) -> Vec { + self.chunks.keys().into_iter().map(|key| Vec3::new(key[0] as f32, key[1] as f32, key[2] as f32)).collect() + } } #[cfg(test)] @@ -269,4 +273,15 @@ mod tests { let retrieved_block = chunk_manager.get_block(block_position).unwrap(); assert_eq!(retrieved_block, block_id); } + + #[test] + fn test_get_all_chunk_positions() { + let mut chunk_manager = ChunkManager::new(); + chunk_manager.set_chunk(Vec3::new(0.0, 0.0, 0.0), Chunk::default()); + chunk_manager.set_chunk(Vec3::new(2.0, 0.0, 0.0), Chunk::default()); + chunk_manager.set_chunk(Vec3::new(1.0, 0.0, 3.0), Chunk::default()); + + let retrieved_chunk_positions = chunk_manager.get_all_chunk_positions(); + assert_eq!(retrieved_chunk_positions.len(), 3); + } } From b8c39424ad3e00ae2e2fa17ede1c0afd6c6ece5c Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 11:15:12 +0100 Subject: [PATCH 17/68] Update comment --- src/server/networking/systems.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/networking/systems.rs b/src/server/networking/systems.rs index 4356708d..9dc1eaa1 100644 --- a/src/server/networking/systems.rs +++ b/src/server/networking/systems.rs @@ -69,7 +69,7 @@ pub fn receive_message_system( .map(|position| { let chunk = chunk_manager.get_chunk(position); - // visualizer? + // visualizer? I don't think we want to allow this in prod if force { let mut chunk = Chunk::new(position); generator.generate_chunk(&mut chunk); From d5e53525c8df3f6ca4bb7249ce2555028822086b Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 11:39:19 +0100 Subject: [PATCH 18/68] Update terrain generation --- src/client/terrain/mod.rs | 1 + src/client/terrain/systems.rs | 14 ++++-- src/server/networking/systems.rs | 21 +++------ src/server/terrain/events.rs | 3 ++ src/server/terrain/mod.rs | 2 + src/server/terrain/systems.rs | 58 +++++++++++++++++++++--- src/server/terrain/util/generator.rs | 66 ++++++++++++++-------------- src/shared/networking.rs | 2 +- src/shared/terrain.rs | 5 ++- 9 files changed, 113 insertions(+), 59 deletions(-) diff --git a/src/client/terrain/mod.rs b/src/client/terrain/mod.rs index 1cf3d69e..04588a01 100644 --- a/src/client/terrain/mod.rs +++ b/src/client/terrain/mod.rs @@ -20,5 +20,6 @@ impl Plugin for TerrainPlugin { app.add_systems(Startup, terrain_systems::prepare_spawn_area_system); app.add_systems(Startup, terrain_systems::generate_world_system); app.add_systems(Update, terrain_systems::handle_chunk_mesh_update_events); + app.add_systems(Update, terrain_systems::handle_terrain_regeneration_events); } } diff --git a/src/client/terrain/systems.rs b/src/client/terrain/systems.rs index 74c011db..7b297262 100644 --- a/src/client/terrain/systems.rs +++ b/src/client/terrain/systems.rs @@ -6,7 +6,7 @@ pub fn prepare_spawn_area_system(mut client: ResMut) { let chunks = ChunkManager::instantiate_chunks(Vec3::ZERO, Vec3::ONE); let positions: Vec = chunks.into_iter().map(|chunk| chunk.position).collect(); - let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest{ positions, force: false }); + let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest(positions)); info!("requesting world"); client.send_message(DefaultChannel::ReliableUnordered, message.unwrap()); } @@ -32,7 +32,7 @@ pub fn generate_world_system( "Sending chunk batch request for {:?}", request_positions.len() ); - let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest{ positions: request_positions, force: false }); + let message = bincode::serialize(&NetworkingMessage::ChunkBatchRequest(request_positions)); info!("requesting chunks #{}", index); client.send_message(DefaultChannel::ReliableUnordered, message.unwrap()); }); @@ -166,6 +166,14 @@ fn spawn_chunk( // visualizer pub fn handle_terrain_regeneration_events( mut client: ResMut, - mut world_regenerate_events: ResMut>, + mut world_regenerate_events: EventReader, + chunk_manager: ResMut, ) { + for _ in world_regenerate_events.read() { + info!("Rerequesting all chunks from server"); + let all_chunk_positions = chunk_manager.get_all_chunk_positions(); + let message = + bincode::serialize(&NetworkingMessage::ChunkBatchRequest(all_chunk_positions)); + client.send_message(DefaultChannel::ReliableUnordered, message.unwrap()); + } } diff --git a/src/server/networking/systems.rs b/src/server/networking/systems.rs index 9dc1eaa1..d713da48 100644 --- a/src/server/networking/systems.rs +++ b/src/server/networking/systems.rs @@ -58,7 +58,7 @@ pub fn receive_message_system( ); player_states.players.insert(client_id, player); } - NetworkingMessage::ChunkBatchRequest { positions, force } => { + NetworkingMessage::ChunkBatchRequest(positions) => { info!( "Received chunk batch request at {:?} from client {}", positions, client_id @@ -69,19 +69,12 @@ pub fn receive_message_system( .map(|position| { let chunk = chunk_manager.get_chunk(position); - // visualizer? I don't think we want to allow this in prod - if force { - let mut chunk = Chunk::new(position); - generator.generate_chunk(&mut chunk); - chunk - } else { - match chunk { - Some(chunk) => *chunk, - None => { - let mut chunk = Chunk::new(position); - generator.generate_chunk(&mut chunk); - chunk - } + match chunk { + Some(chunk) => *chunk, + None => { + let mut chunk = Chunk::new(position); + generator.generate_chunk(&mut chunk); + chunk } } }) diff --git a/src/server/terrain/events.rs b/src/server/terrain/events.rs index 4d453006..f3978b29 100644 --- a/src/server/terrain/events.rs +++ b/src/server/terrain/events.rs @@ -9,3 +9,6 @@ pub struct BlockUpdateEvent { // visualizer #[derive(Event)] pub struct RegenerateHeightMapEvent; + +#[derive(Event)] +pub struct WorldRegenerateEvent; diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index 3336f6f1..ec48d625 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -20,7 +20,9 @@ impl Plugin for TerrainPlugin { app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); app.add_systems(Update, terrain_systems::render_visualizer_system); app.add_systems(Update, terrain_systems::regenerate_heightmap_system); + app.add_systems(Update, terrain_systems::handle_regenerate_event_system); app.add_event::(); + app.add_event::(); } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index be070981..86781770 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -4,7 +4,7 @@ pub fn setup_world_system( mut chunk_manager: ResMut, generator: Res, ) { - let render_distance = Vec3::new(12.0, 2.0, 12.0); + let render_distance = Vec3::new(6.0, 2.0, 6.0); info!("Generating chunks"); @@ -21,8 +21,8 @@ pub fn setup_world_system( pub use visualizer::*; mod visualizer { - use bevy::{ + log::info, math::{Vec2, Vec3}, prelude::{EventReader, EventWriter, ResMut}, }; @@ -30,6 +30,11 @@ mod visualizer { bevy_egui::EguiContexts, egui::{self, Color32, ColorImage, ImageData, TextureOptions}, }; + use rayon::iter::IntoParallelIterator; + + use rayon::iter::ParallelIterator; + use renet::{DefaultChannel, RenetServer}; + use rsmc::{Chunk, ChunkManager, NetworkingMessage}; use super::{terrain_events, terrain_resources}; @@ -47,10 +52,7 @@ mod visualizer { for z in 0..height { let sample_position = Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); - let value = generator.sample_2d( - sample_position.try_into().unwrap(), - &generator.params.height_params, - ); + let value = generator.sample_2d(sample_position, &generator.params.height_params); let value = value * size.y as f64; let value = value as u8; data[x + z * width] = value; @@ -70,6 +72,43 @@ mod visualizer { ImageData::Color(color_image.into()) } + pub fn handle_regenerate_event_system( + mut events: EventReader, + mut chunk_manager: ResMut, + generator: ResMut, + mut server: ResMut, + ) { + for _ in events.read() { + info!("Regenerating world"); + let existing_chunk_positions = chunk_manager.get_all_chunk_positions(); + + let new_chunks: Vec = existing_chunk_positions + .into_par_iter() + .map(|chunk_position| { + let mut chunk = Chunk::new(chunk_position); + info!("Generating chunk at {:?}", chunk_position); + generator.generate_chunk(&mut chunk); + chunk + }) + .collect(); + + new_chunks.into_iter().for_each(|chunk| { + chunk_manager.insert_chunk(chunk); + }); + + info!("Successfully regenerated world"); + info!("Sending chunk requests for all chunks"); + + server.broadcast_message( + DefaultChannel::ReliableUnordered, + bincode::serialize( + &NetworkingMessage::ServerAsksClientNicelyToRerequestChunkBatch(), + ) + .unwrap(), + ); + } + } + pub fn regenerate_heightmap_system( mut events: EventReader, generator: ResMut, @@ -107,6 +146,7 @@ mod visualizer { noise_texture: ResMut, mut generator: ResMut, mut event_writer: EventWriter, + mut world_regenerate_event_writer: EventWriter, ) { if let Some(texture_handle) = &noise_texture.texture { egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { @@ -173,6 +213,12 @@ mod visualizer { event_writer.send(terrain_events::RegenerateHeightMapEvent); }; + ui.label(format!("{:?}", generator.params.height_params)); + + if ui.button("Regenerate world").clicked() { + world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); + } + ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( texture_handle.id(), texture_handle.size_vec2(), diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 6498e870..af24061a 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -45,7 +45,7 @@ impl Generator { ); if (position.y as f64) < terrain_height + 20.0 { - let max_slope = self.calculate_max_slope(position, &default_params); + let max_slope = self.calculate_max_slope(position, default_params); if max_slope > 4.0 { return BlockId::Stone; } else if max_slope > 1.0 { @@ -75,9 +75,7 @@ impl Generator { fn get_terrain_samples(&self, position: Vec3, params: &NoiseFunctionParams) -> [f64; 5] { let sample_positions = self.get_sample_positions(position, 0.001); - sample_positions.map(|sample_position| { - self.sample_2d(sample_position, ¶ms).abs() - }) + sample_positions.map(|sample_position| self.sample_2d(sample_position, params).abs()) } fn calculate_max_slope(&self, position: Vec3, params: &NoiseFunctionParams) -> f64 { @@ -96,27 +94,27 @@ impl Generator { max } - fn sample_3d(&self, position: Vec3, octaves: i32) -> f64 { - let mut density = 0.0; - let lacuranity = 2.0; - let mut frequency = 0.04; - let mut amplitude = 1.0; - let mut persistence = 0.5; - - for _ in 0..octaves { - density += self.perlin.get([ - position.x as f64 * frequency, - position.y as f64 * frequency, - position.z as f64 * frequency, - ]) * amplitude; - - amplitude *= persistence; - frequency *= lacuranity; - persistence *= 0.5; - } - - density - } + // fn sample_3d(&self, position: Vec3, octaves: i32) -> f64 { + // let mut density = 0.0; + // let lacuranity = 2.0; + // let mut frequency = 0.04; + // let mut amplitude = 1.0; + // let mut persistence = 0.5; + // + // for _ in 0..octaves { + // density += self.perlin.get([ + // position.x as f64 * frequency, + // position.y as f64 * frequency, + // position.z as f64 * frequency, + // ]) * amplitude; + // + // amplitude *= persistence; + // frequency *= lacuranity; + // persistence *= 0.5; + // } + // + // density + // } pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { let sample = self.perlin.get([ @@ -161,13 +159,13 @@ mod tests { assert_ne!(chunk.get(0, 0, 0), BlockId::Air); } - #[test] - fn test_sample_3d() { - let generator = Generator::default(); - - let position = Vec3::new(0.0, 0.0, 0.0); - let density = generator.sample_3d(position, 4); - - assert!((0.0..=1.0).contains(&density)); - } + // #[test] + // fn test_sample_3d() { + // let generator = Generator::default(); + // + // let position = Vec3::new(0.0, 0.0, 0.0); + // let density = generator.sample_3d(position, 4); + // + // assert!((0.0..=1.0).contains(&density)); + // } } diff --git a/src/shared/networking.rs b/src/shared/networking.rs index 6c7ad27a..ca526d1e 100644 --- a/src/shared/networking.rs +++ b/src/shared/networking.rs @@ -44,7 +44,7 @@ pub enum NetworkingMessage { PlayerLeave(ClientId), PlayerUpdate(PlayerState), PlayerSync(HashMap), - ChunkBatchRequest{ positions: Vec, force: bool }, + ChunkBatchRequest(Vec), ChunkBatchResponse(Vec), ChatMessageSend(String), SingleChatMessageSync(ChatMessage), diff --git a/src/shared/terrain.rs b/src/shared/terrain.rs index 7173001c..4e41fef5 100644 --- a/src/shared/terrain.rs +++ b/src/shared/terrain.rs @@ -197,7 +197,10 @@ impl ChunkManager { } pub fn get_all_chunk_positions(&self) -> Vec { - self.chunks.keys().into_iter().map(|key| Vec3::new(key[0] as f32, key[1] as f32, key[2] as f32)).collect() + self.chunks + .keys() + .map(|key| Vec3::new(key[0] as f32, key[1] as f32, key[2] as f32)) + .collect() } } From c139bfe03ae3b70b2d52b1b0fffa8e37c7f707ec Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 11:45:38 +0100 Subject: [PATCH 19/68] Refactor ui with macros --- src/server/terrain/systems.rs | 69 ++++++++--------------------------- 1 file changed, 15 insertions(+), 54 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 86781770..d7237a7d 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -141,6 +141,15 @@ mod visualizer { event_writer.send(terrain_events::RegenerateHeightMapEvent); } + macro_rules! add_slider { + ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ + $changed |= $ui + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; + } + + #[rustfmt::skip] pub fn render_visualizer_system( mut contexts: EguiContexts, noise_texture: ResMut, @@ -154,60 +163,12 @@ mod visualizer { let mut changed = false; - changed |= ui - .add( - egui::widgets::Slider::new( - &mut generator.params.height_params.octaves, - 1..=8, - ) - .text("octaves"), - ) - .changed(); - changed |= ui - .add( - egui::widgets::Slider::new( - &mut generator.params.height_params.height, - 0.0..=10.0, - ) - .text("height"), - ) - .changed(); - changed |= ui - .add( - egui::widgets::Slider::new( - &mut generator.params.height_params.lacuranity, - 0.0..=4.0, - ) - .text("lacuranity"), - ) - .changed(); - changed |= ui - .add( - egui::widgets::Slider::new( - &mut generator.params.height_params.frequency, - 0.0..=1.0, - ) - .text("frequency"), - ) - .changed(); - changed |= ui - .add( - egui::widgets::Slider::new( - &mut generator.params.height_params.amplitude, - 0.0..=20.0, - ) - .text("amplitude"), - ) - .changed(); - changed |= ui - .add( - egui::widgets::Slider::new( - &mut generator.params.height_params.persistence, - 0.0..=1.0, - ) - .text("persistence"), - ) - .changed(); + add_slider!(ui, changed, &mut generator.params.height_params.octaves, 1..=8, "octaves"); + add_slider!(ui, changed, &mut generator.params.height_params.height, 0.0..=10.0, "height"); + add_slider!(ui, changed, &mut generator.params.height_params.lacuranity, 0.0..=4.0, "lacuranity"); + add_slider!(ui, changed, &mut generator.params.height_params.frequency, 0.0..=1.0, "frequency"); + add_slider!(ui, changed, &mut generator.params.height_params.amplitude, 0.0..=20.0, "amplitude"); + add_slider!(ui, changed, &mut generator.params.height_params.persistence, 0.0..=1.0, "persistence"); if changed { event_writer.send(terrain_events::RegenerateHeightMapEvent); From 5d74c9af78aefd385e68d74cda4ddd237734a15e Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 13:07:48 +0100 Subject: [PATCH 20/68] Basic spline impl --- src/server/terrain/resources.rs | 16 ++++ src/server/terrain/systems.rs | 16 ++-- src/server/terrain/util/generator.rs | 110 ++++++++++++++++----------- src/shared/networking.rs | 10 --- 4 files changed, 91 insertions(+), 61 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 89faa693..c35fda0d 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -29,6 +29,16 @@ pub struct Generator { pub params: TerrainGeneratorParams, } +#[derive(Debug, Copy, Clone)] +pub struct NoiseFunctionParams { + pub octaves: i32, + pub height: f64, + pub lacuranity: f64, + pub frequency: f64, + pub amplitude: f64, + pub persistence: f64, +} + impl Default for Generator { fn default() -> Self { Self::new(0) @@ -36,6 +46,7 @@ impl Default for Generator { } pub struct TerrainGeneratorParams { + pub splines: Vec, pub height_params: NoiseFunctionParams, pub density_params: NoiseFunctionParams, } @@ -43,6 +54,11 @@ pub struct TerrainGeneratorParams { impl Default for TerrainGeneratorParams { fn default() -> Self { Self { + splines: vec![ + Vec2::new(0.0, 0.0), + Vec2::new(0.5, 50.0), + Vec2::new(1.0, 100.0) + ], height_params: NoiseFunctionParams { octaves: 4, height: 0.0, diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index d7237a7d..5af8ad6d 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -141,14 +141,6 @@ mod visualizer { event_writer.send(terrain_events::RegenerateHeightMapEvent); } - macro_rules! add_slider { - ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ - $changed |= $ui - .add(egui::widgets::Slider::new($value, $range).text($text)) - .changed(); - }}; - } - #[rustfmt::skip] pub fn render_visualizer_system( mut contexts: EguiContexts, @@ -161,6 +153,14 @@ mod visualizer { egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { ui.label("world"); + macro_rules! add_slider { + ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ + $changed |= $ui + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; + } + let mut changed = false; add_slider!(ui, changed, &mut generator.params.height_params.octaves, 1..=8, "octaves"); diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index af24061a..f4c4f2bb 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -1,4 +1,4 @@ -use terrain_resources::{Generator, TerrainGeneratorParams}; +use terrain_resources::{Generator, NoiseFunctionParams, TerrainGeneratorParams}; use crate::prelude::*; @@ -36,26 +36,75 @@ impl Generator { fn generate_block(&self, position: Vec3) -> BlockId { let default_params = &self.params.height_params; - let terrain_height = self.sample_2d( + let terrain_height = self.determine_terrain_height(position); + + if (position.y as f64) < terrain_height { + return BlockId::Stone; + } + + // let terrain_height = self.sample_2d( + // Vec2 { + // x: position.x, + // y: position.z, + // }, + // default_params, + // ); + + // if (position.y as f64) < terrain_height + 20.0 { + // let max_slope = self.calculate_max_slope(position, default_params); + // if max_slope > 4.0 { + // return BlockId::Stone; + // } else if max_slope > 1.0 { + // return BlockId::Dirt; + // } else { + // return BlockId::Grass; + // } + // } + + BlockId::Air + } + + fn determine_terrain_height(&self, position: Vec3) -> f64 { + let noise_value = self.sample_2d_normalized( Vec2 { x: position.x, y: position.z, }, - default_params, + &self.params.height_params, ); + let lerped_height = self.spline_lerp(noise_value); + + lerped_height + } + + fn spline_lerp(&self, x: f64) -> f64 { + // x is the noise function value + // y is the mapped terrain height + + let x: f32 = x as f32; - if (position.y as f64) < terrain_height + 20.0 { - let max_slope = self.calculate_max_slope(position, default_params); - if max_slope > 4.0 { - return BlockId::Stone; - } else if max_slope > 1.0 { - return BlockId::Dirt; - } else { - return BlockId::Grass; + assert!(self.params.splines.len() > 2); + + let min_x = self.params.splines[0].x; + let max_x = self.params.splines[self.params.splines.len() - 1].x; + + assert!(min_x == 0.0); + assert!(max_x == 1.0); + + for i in 0..self.params.splines.len() - 1 { + let current = self.params.splines[i]; + let next = self.params.splines[i + 1]; + + if x >= current.x && x <= next.x { + return self.lerp(current, x, next); } } - BlockId::Air + panic!("Could not find matching spline points for x value {}", x); + } + + fn lerp(&self, point0: Vec2, x: f32, point1: Vec2) -> f64 { + ((point0.y * (point1.x - x) + point1.y * (x - point0.x)) / (point1.x - point0.x)) as f64 } fn get_sample_positions(&self, position: Vec3, epsilon: f32) -> [Vec2; 5] { @@ -94,27 +143,12 @@ impl Generator { max } - // fn sample_3d(&self, position: Vec3, octaves: i32) -> f64 { - // let mut density = 0.0; - // let lacuranity = 2.0; - // let mut frequency = 0.04; - // let mut amplitude = 1.0; - // let mut persistence = 0.5; - // - // for _ in 0..octaves { - // density += self.perlin.get([ - // position.x as f64 * frequency, - // position.y as f64 * frequency, - // position.z as f64 * frequency, - // ]) * amplitude; - // - // amplitude *= persistence; - // frequency *= lacuranity; - // persistence *= 0.5; - // } - // - // density - // } + pub fn sample_2d_normalized(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { + self.perlin.get([ + position.x as f64 * params.frequency, + position.y as f64 * params.frequency, + ]) / 2.0 + 0.5 + } pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { let sample = self.perlin.get([ @@ -158,14 +192,4 @@ mod tests { assert_ne!(chunk.get(0, 0, 0), BlockId::Air); } - - // #[test] - // fn test_sample_3d() { - // let generator = Generator::default(); - // - // let position = Vec3::new(0.0, 0.0, 0.0); - // let density = generator.sample_3d(position, 4); - // - // assert!((0.0..=1.0).contains(&density)); - // } } diff --git a/src/shared/networking.rs b/src/shared/networking.rs index ca526d1e..11a16c31 100644 --- a/src/shared/networking.rs +++ b/src/shared/networking.rs @@ -54,16 +54,6 @@ pub enum NetworkingMessage { ServerAsksClientNicelyToRerequestChunkBatch(), } -#[derive(Serialize, Deserialize, Debug, Copy, Clone)] -pub struct NoiseFunctionParams { - pub octaves: i32, - pub height: f64, - pub lacuranity: f64, - pub frequency: f64, - pub amplitude: f64, - pub persistence: f64, -} - const CHANNELS: [ChannelConfig; 3] = [ ChannelConfig { channel_id: 0, From fa4ed41bcfb2c83b6917354e73693be005496ab6 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 14:43:30 +0100 Subject: [PATCH 21/68] Fix egui, add egui_plot --- Cargo.lock | 64 +++++++++++++++++++++++++++++++----------------------- Cargo.toml | 11 ++++++---- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1919199..521dad86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "bevy-inspector-egui" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36172627eb6fd8586600972bcbba2880ed6f59e4e243dcf2ed7ff68d987577ce" +checksum = "b3d3ea87310d78bacc94471bcf5a8b63ead43e7263d404571832c2297458b856" dependencies = [ "bevy-inspector-egui-derive", "bevy_app", @@ -410,14 +410,15 @@ dependencies = [ "fuzzy-matcher", "image", "smallvec", + "uuid", "winit", ] [[package]] name = "bevy-inspector-egui-derive" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afc67826e0a4347414545e022e748f42550a577a502b26af44e6d03742c9266" +checksum = "a7259e525c7844b23f10fd2b2efaa3eea57996f101cc30e833070d139e2b4e4d" dependencies = [ "proc-macro2", "quote", @@ -686,9 +687,9 @@ dependencies = [ [[package]] name = "bevy_egui" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "954fbe8551af4b40767ea9390ec7d32fe1070a6ab55d524cf0868c17f8469a55" +checksum = "6a4b8df063d7c4d4171bc853e5ea0d67c7f1b5edd3b014d43acbfe3042dd6cf4" dependencies = [ "arboard", "bevy_app", @@ -699,6 +700,7 @@ dependencies = [ "bevy_input", "bevy_log", "bevy_math", + "bevy_picking", "bevy_reflect", "bevy_render", "bevy_time", @@ -710,7 +712,6 @@ dependencies = [ "egui", "encase", "js-sys", - "log", "thread_local", "wasm-bindgen", "wasm-bindgen-futures", @@ -1245,8 +1246,7 @@ dependencies = [ [[package]] name = "bevy_renet" version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eef73d8b44abe4852fe772f30eb7215beeac60e53ef94b3cb5a63e162bda4f51" +source = "git+https://github.com/CuddlyBunion341/renet.git#01fce875fab05aabebcb6d1e8725bf15424883a0" dependencies = [ "bevy_app", "bevy_ecs", @@ -2281,9 +2281,9 @@ dependencies = [ [[package]] name = "ecolor" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b" +checksum = "7d72e9c39f6e11a2e922d04a34ec5e7ef522ea3f5a1acfca7a19d16ad5fe50f5" dependencies = [ "bytemuck", "emath", @@ -2291,14 +2291,26 @@ dependencies = [ [[package]] name = "egui" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974" +checksum = "252d52224d35be1535d7fd1d6139ce071fb42c9097773e79f7665604f5596b5e" dependencies = [ "ahash", "emath", "epaint", "nohash-hasher", + "profiling", +] + +[[package]] +name = "egui_plot" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c226cae80a6ee10c4d3aaf9e33bd9e9b2f1c0116b6036bdc2a1cfc9d2d0dcc10" +dependencies = [ + "ahash", + "egui", + "emath", ] [[package]] @@ -2309,9 +2321,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "emath" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3" +checksum = "c4fe73c1207b864ee40aa0b0c038d6092af1030744678c60188a05c28553515d" dependencies = [ "bytemuck", ] @@ -2359,9 +2371,9 @@ dependencies = [ [[package]] name = "epaint" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a32af8da821bd4f43f2c137e295459ee2e1661d87ca8779dfa0eaf45d870e20f" +checksum = "5666f8d25236293c966fbb3635eac18b04ad1914e3bab55bc7d44b9980cafcac" dependencies = [ "ab_glyph", "ahash", @@ -2371,13 +2383,14 @@ dependencies = [ "epaint_default_fonts", "nohash-hasher", "parking_lot", + "profiling", ] [[package]] name = "epaint_default_fonts" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "483440db0b7993cf77a20314f08311dbe95675092405518c0677aa08c151a3ea" +checksum = "66f6ddac3e6ac6fd4c3d48bb8b1943472f8da0f43a4303bcd8a18aa594401c80" [[package]] name = "equivalent" @@ -4340,8 +4353,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "renet" version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b4ff6af5dc5497f1155a2856c2a8db3cf4f94c0e2ed83614e3cef2fde48c0f9" +source = "git+https://github.com/CuddlyBunion341/renet.git#01fce875fab05aabebcb6d1e8725bf15424883a0" dependencies = [ "bevy_ecs", "bytes", @@ -4352,8 +4364,7 @@ dependencies = [ [[package]] name = "renet_netcode" version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e34e6acd4d01155558d24609c1d0e8f8eafaf58bf805ecf1ecd7ac613d6528a" +source = "git+https://github.com/CuddlyBunion341/renet.git#01fce875fab05aabebcb6d1e8725bf15424883a0" dependencies = [ "bevy_ecs", "log", @@ -4364,8 +4375,7 @@ dependencies = [ [[package]] name = "renet_visualizer" version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3000d08a1d1682a01bc76a7b8d4d8172f5e7ea3eee18546d7c22c76eb36c609b" +source = "git+https://github.com/CuddlyBunion341/renet.git#01fce875fab05aabebcb6d1e8725bf15424883a0" dependencies = [ "bevy_ecs", "egui", @@ -4375,8 +4385,7 @@ dependencies = [ [[package]] name = "renetcode" version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "118d456f815f7fd5bd12713a9e69a0b0f8b45806bd515e05bb60146f1867310d" +source = "git+https://github.com/CuddlyBunion341/renet.git#01fce875fab05aabebcb6d1e8725bf15424883a0" dependencies = [ "chacha20poly1305", "log", @@ -4431,6 +4440,7 @@ dependencies = [ "bincode", "cgmath", "chrono", + "egui_plot", "iyes_perf_ui", "noise", "rand", diff --git a/Cargo.toml b/Cargo.toml index 3b613f6f..9e251edb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,17 +12,20 @@ bevy_rapier3d = "0.28.0" cgmath = "0.18.0" iyes_perf_ui = { git = "https://github.com/IyesGames/iyes_perf_ui.git", branch = "main" } noise = "0.9.0" -bevy_renet = { version = "1.0.0" } +bevy_renet = { git = "https://github.com/CuddlyBunion341/renet.git" } bincode = "1.3.3" rand = "0.8.5" -renet = "1.0.0" +renet = { git = "https://github.com/CuddlyBunion341/renet.git" } serde = { version = "1.0.203", features = ["derive"] } serde-big-array = "0.5.1" chrono = "0.4.38" rayon = "1.10.0" bevy_flair = "0.1.0" -bevy-inspector-egui = "0.28.1" -renet_visualizer = { version = "1.0.0", features = ["bevy"] } +bevy-inspector-egui = "0.29" +renet_visualizer = { git = "https://github.com/CuddlyBunion341/renet.git", features = [ + "bevy", +] } +egui_plot = "0.30.0" [profile.dev.package."*"] opt-level = 3 From db0d861bc079414674af5aef58d266c51e24766a Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 1 Feb 2025 14:44:20 +0100 Subject: [PATCH 22/68] Impl egui_plot --- src/server/networking/systems.rs | 1 + src/server/terrain/resources.rs | 2 +- src/server/terrain/systems.rs | 15 +++++++++++++++ src/server/terrain/util/generator.rs | 6 +++--- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/server/networking/systems.rs b/src/server/networking/systems.rs index d713da48..cccb61b1 100644 --- a/src/server/networking/systems.rs +++ b/src/server/networking/systems.rs @@ -172,6 +172,7 @@ pub use server_visualizer::*; #[cfg(feature = "renet_visualizer")] pub mod server_visualizer { + use crate::prelude::*; use bevy_inspector_egui::bevy_egui::EguiContexts; use renet_visualizer::RenetServerVisualizer; diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index c35fda0d..cc56c9cf 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -57,7 +57,7 @@ impl Default for TerrainGeneratorParams { splines: vec![ Vec2::new(0.0, 0.0), Vec2::new(0.5, 50.0), - Vec2::new(1.0, 100.0) + Vec2::new(1.0, 100.0), ], height_params: NoiseFunctionParams { octaves: 4, diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 5af8ad6d..c78f2970 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -30,6 +30,7 @@ mod visualizer { bevy_egui::EguiContexts, egui::{self, Color32, ColorImage, ImageData, TextureOptions}, }; + use egui_plot::{Line, PlotPoint, PlotPoints}; use rayon::iter::IntoParallelIterator; use rayon::iter::ParallelIterator; @@ -170,6 +171,20 @@ mod visualizer { add_slider!(ui, changed, &mut generator.params.height_params.amplitude, 0.0..=20.0, "amplitude"); add_slider!(ui, changed, &mut generator.params.height_params.persistence, 0.0..=1.0, "persistence"); + generator.params.splines.iter_mut().for_each(|spline| { + add_slider!(ui, changed, &mut spline.x, 0.0..=1.0, "x"); + add_slider!(ui, changed, &mut spline.y, 0.0..=100.0, "y"); + }); + + + egui_plot::Plot::new("splines") + .show(ui, |plot_ui| { + let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let line_chart = Line::new(PlotPoints::Owned(plot_points)); + plot_ui.line(line_chart); + }); + + if changed { event_writer.send(terrain_events::RegenerateHeightMapEvent); }; diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index f4c4f2bb..52da00d8 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -72,9 +72,8 @@ impl Generator { }, &self.params.height_params, ); - let lerped_height = self.spline_lerp(noise_value); - lerped_height + self.spline_lerp(noise_value) } fn spline_lerp(&self, x: f64) -> f64 { @@ -147,7 +146,8 @@ impl Generator { self.perlin.get([ position.x as f64 * params.frequency, position.y as f64 * params.frequency, - ]) / 2.0 + 0.5 + ]) / 2.0 + + 0.5 } pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { From 5b12b1faf15ec62e851fd9462fa825315881efa3 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 2 Feb 2025 10:10:04 +0100 Subject: [PATCH 23/68] Normalize preview, make preview affected by splines --- src/server/terrain/resources.rs | 5 +- src/server/terrain/systems.rs | 59 ++++++++++++++------ src/server/terrain/util/generator.rs | 80 +++++++++++++++++----------- 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index cc56c9cf..85d2a47b 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -55,9 +55,8 @@ impl Default for TerrainGeneratorParams { fn default() -> Self { Self { splines: vec![ - Vec2::new(0.0, 0.0), - Vec2::new(0.5, 50.0), - Vec2::new(1.0, 100.0), + Vec2::new(-1.0, 0.0), + Vec2::new(1.0, 50.0), ], height_params: NoiseFunctionParams { octaves: 4, diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index c78f2970..e9249239 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -35,7 +35,7 @@ mod visualizer { use rayon::iter::ParallelIterator; use renet::{DefaultChannel, RenetServer}; - use rsmc::{Chunk, ChunkManager, NetworkingMessage}; + use rsmc::{Chunk, ChunkManager, NetworkingMessage, CHUNK_SIZE}; use super::{terrain_events, terrain_resources}; @@ -49,13 +49,23 @@ mod visualizer { let width = size.x as usize; let height = size.z as usize; + let draw_chunk_border = true; + for x in 0..width { for z in 0..height { let sample_position = Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); - let value = generator.sample_2d(sample_position, &generator.params.height_params); - let value = value * size.y as f64; - let value = value as u8; + // let value = generator.sample_2d(sample_position, &generator.params.height_params); + let value = generator.normalized_spline_terrain_sample(sample_position); + let value = ( value * size.y as f64 ) / 2.0 + 0.5; + let mut value = value as u8; + + if draw_chunk_border { + if x % CHUNK_SIZE == 0 || z % CHUNK_SIZE == 0 { + value = 255; + } + } + data[x + z * width] = value; } } @@ -164,25 +174,25 @@ mod visualizer { let mut changed = false; + generator.params.height_params.frequency = 1.0 / generator.params.height_params.frequency; + add_slider!(ui, changed, &mut generator.params.height_params.octaves, 1..=8, "octaves"); - add_slider!(ui, changed, &mut generator.params.height_params.height, 0.0..=10.0, "height"); add_slider!(ui, changed, &mut generator.params.height_params.lacuranity, 0.0..=4.0, "lacuranity"); - add_slider!(ui, changed, &mut generator.params.height_params.frequency, 0.0..=1.0, "frequency"); - add_slider!(ui, changed, &mut generator.params.height_params.amplitude, 0.0..=20.0, "amplitude"); + add_slider!(ui, changed, &mut generator.params.height_params.frequency, 10.0..=300.0, "frequency"); add_slider!(ui, changed, &mut generator.params.height_params.persistence, 0.0..=1.0, "persistence"); - generator.params.splines.iter_mut().for_each(|spline| { - add_slider!(ui, changed, &mut spline.x, 0.0..=1.0, "x"); - add_slider!(ui, changed, &mut spline.y, 0.0..=100.0, "y"); - }); + generator.params.height_params.frequency = 1.0 / generator.params.height_params.frequency; + let length = generator.params.splines.len(); + + for index in 0..length { + if index != 0 && index != length - 1 { + // Ensure range from 0 to 1 by locking the first and last splines + add_slider!(ui, changed, &mut generator.params.splines[index].x, -1.0..=1.0, format!("x{}", index)); + } + add_slider!(ui, changed, &mut generator.params.splines[index].y, -40.0..=40.0, format!("y{}", index)); + } - egui_plot::Plot::new("splines") - .show(ui, |plot_ui| { - let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); - let line_chart = Line::new(PlotPoints::Owned(plot_points)); - plot_ui.line(line_chart); - }); if changed { @@ -199,7 +209,22 @@ mod visualizer { texture_handle.id(), texture_handle.size_vec2(), ))); + + egui_plot::Plot::new("splines") + .show(ui, |plot_ui| { + let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let line_chart = Line::new(PlotPoints::Owned(plot_points)); + plot_ui.line(line_chart); + }); }); + + // egui::Window::new("Heightmap").show(contexts.ctx_mut(), |ui| { + // ui.label(format!("{:?}", noise_texture.size)); + // ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( + // noise_texture.texture.unwrap().id(), + // noise_texture.size_vec2(), + // ))); + // }); } } } diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 52da00d8..3bb882a3 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -65,29 +65,43 @@ impl Generator { } fn determine_terrain_height(&self, position: Vec3) -> f64 { - let noise_value = self.sample_2d_normalized( + let noise_value = self.sample_2d( Vec2 { x: position.x, y: position.z, }, &self.params.height_params, - ); + ).abs(); self.spline_lerp(noise_value) } + pub fn normalized_spline_terrain_sample(&self, position: Vec2) -> f64 { + let noise_value = self.sample_2d( + position, + &self.params.height_params, + ); + + let min_height = self.params.splines[0].y as f64; + let max_height = self.params.splines[self.params.splines.len() - 1].y as f64; + + let splined_value = self.spline_lerp(noise_value); + + (splined_value - min_height) / (max_height - min_height) + } + fn spline_lerp(&self, x: f64) -> f64 { // x is the noise function value // y is the mapped terrain height let x: f32 = x as f32; - assert!(self.params.splines.len() > 2); + assert!(self.params.splines.len() >= 2); let min_x = self.params.splines[0].x; let max_x = self.params.splines[self.params.splines.len() - 1].x; - assert!(min_x == 0.0); + assert!(min_x == -1.0); assert!(max_x == 1.0); for i in 0..self.params.splines.len() - 1 { @@ -142,39 +156,43 @@ impl Generator { max } - pub fn sample_2d_normalized(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { - self.perlin.get([ - position.x as f64 * params.frequency, - position.y as f64 * params.frequency, - ]) / 2.0 - + 0.5 - } + // pub fn sample_2d_normalized(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { + // let mut height = self.perlin.get([ + // position.x as f64 * params.frequency, + // position.y as f64 * params.frequency, + // ]); + // + // for o in 0..params.octaves { + // height += self.perlin.get([ + // position.x as f64 * params.frequency * o as f64, + // position.y as f64 * params.frequency * o as f64, + // ]) * params.amplitude; + // } + // + // height + // } pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { - let sample = self.perlin.get([ - position.x as f64 * params.frequency, - position.y as f64 * params.frequency, - ]) * params.amplitude; + let mut den_sum = 0.0; + + let pers_f = 1.0 / params.persistence; + + for o in 0..params.octaves { + den_sum += pers_f.powi(o); + } + + let mut sample = 0.0; + + for o in 1..params.octaves { + let new_sample = self.perlin.get([ + position.x as f64 * params.frequency * params.lacuranity.powi(o) as f64, + position.y as f64 * params.frequency * params.lacuranity.powi(o) as f64, + ]); - if params.octaves == 0 { - return sample; + sample += new_sample * pers_f.powi(o) / den_sum; } sample - + self.sample_2d( - Vec2 { - x: position.x * params.lacuranity as f32, - y: position.y * params.lacuranity as f32, - }, - &NoiseFunctionParams { - octaves: params.octaves - 1, - height: params.height + sample, - lacuranity: params.lacuranity, - frequency: params.frequency, - amplitude: params.amplitude, - persistence: params.persistence, - }, - ) * params.persistence } } From 391d27f17871e38b9b3d081a9b8dd0db4f532649 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 2 Feb 2025 11:03:03 +0100 Subject: [PATCH 24/68] Update chunk visualization --- src/client/player/systems/controller.rs | 23 ++++++++++++++++++----- src/server/terrain/util/generator.rs | 9 ++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/client/player/systems/controller.rs b/src/client/player/systems/controller.rs index fd0ff690..93f690cb 100644 --- a/src/client/player/systems/controller.rs +++ b/src/client/player/systems/controller.rs @@ -1,14 +1,27 @@ use crate::prelude::*; -const SPAWN_POINT: Vec3 = Vec3::new(0.0, 32.0, 0.0); +// const SPAWN_POINT: Vec3 = Vec3::new(0.0, 32.0, 0.0); +const SPAWN_POINT: Vec3 = Vec3::new(128.0, 64.0, -128.0); pub fn setup_player_camera(mut commands: Commands) { commands.spawn(( + Name::new("Player cam?"), Camera3d::default(), - Projection::Perspective(PerspectiveProjection { - fov: TAU / 5.0, - ..default() - }), + // Projection::Perspective(PerspectiveProjection { + // fov: TAU / 5.0, + // ..default() + // }), + Projection::Orthographic( + OrthographicProjection { + scale: 0.125, + near: 0.0001, + far: 1000.0, + viewport_origin: Vec2::new(0.5, 0.5), + scaling_mode: ScalingMode::WindowSize, + area: Rect::new(-1.0, -1.0, 1.0, 1.0), + } + .into(), + ), RenderPlayer { logical_entity: Entity::from_raw(0), }, diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 3bb882a3..2a98070f 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -21,9 +21,12 @@ impl Generator { return; } - for x in 0..CHUNK_SIZE + 2 { - for y in 0..CHUNK_SIZE + 2 { - for z in 0..CHUNK_SIZE + 2 { + // for x in 0..CHUNK_SIZE + 2 { + // for y in 0..CHUNK_SIZE + 2 { + // for z in 0..CHUNK_SIZE + 2 { + for x in 1..CHUNK_SIZE + 1 { + for y in 1..CHUNK_SIZE + 1 { + for z in 1..CHUNK_SIZE + 1 { let local_position = Vec3::new(x as f32, y as f32, z as f32); let block_position = chunk_origin + local_position; let block = self.generate_block(block_position); From db4707e4ae319d4e1ef272aca576f0bfe7e0a74b Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 2 Feb 2025 11:03:18 +0100 Subject: [PATCH 25/68] Update terrain generator frequency --- src/server/terrain/systems.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index e9249239..aed6794b 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -178,7 +178,7 @@ mod visualizer { add_slider!(ui, changed, &mut generator.params.height_params.octaves, 1..=8, "octaves"); add_slider!(ui, changed, &mut generator.params.height_params.lacuranity, 0.0..=4.0, "lacuranity"); - add_slider!(ui, changed, &mut generator.params.height_params.frequency, 10.0..=300.0, "frequency"); + add_slider!(ui, changed, &mut generator.params.height_params.frequency, 10.0..=400.0, "frequency"); add_slider!(ui, changed, &mut generator.params.height_params.persistence, 0.0..=1.0, "persistence"); generator.params.height_params.frequency = 1.0 / generator.params.height_params.frequency; From a268ad998c4155b8650eaa1ef96b239c103f1145 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 2 Feb 2025 19:25:00 +0100 Subject: [PATCH 26/68] Refactor fractal sample to be more readable --- src/server/terrain/util/generator.rs | 40 +++++++++------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 2a98070f..aa4f37ae 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -159,42 +159,28 @@ impl Generator { max } - // pub fn sample_2d_normalized(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { - // let mut height = self.perlin.get([ - // position.x as f64 * params.frequency, - // position.y as f64 * params.frequency, - // ]); - // - // for o in 0..params.octaves { - // height += self.perlin.get([ - // position.x as f64 * params.frequency * o as f64, - // position.y as f64 * params.frequency * o as f64, - // ]) * params.amplitude; - // } - // - // height - // } - pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { - let mut den_sum = 0.0; - - let pers_f = 1.0 / params.persistence; + let mut sample = 0.0; - for o in 0..params.octaves { - den_sum += pers_f.powi(o); - } + let mut frequency = params.frequency; + let mut weight = 1.0; - let mut sample = 0.0; + let mut weight_sum = 0.0; - for o in 1..params.octaves { + for _ in 0..params.octaves { let new_sample = self.perlin.get([ - position.x as f64 * params.frequency * params.lacuranity.powi(o) as f64, - position.y as f64 * params.frequency * params.lacuranity.powi(o) as f64, + position.x as f64 * frequency, + position.y as f64 * frequency, ]); - sample += new_sample * pers_f.powi(o) / den_sum; + frequency *= params.lacuranity; + sample += new_sample * weight; + weight_sum += weight; + weight *= params.persistence; } + sample /= weight_sum; + sample } } From 4d68a3c1998d660d34625222a411e8969b5f7fc0 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 2 Feb 2025 22:15:34 +0100 Subject: [PATCH 27/68] Break a lot of shit --- src/client/player/systems/controller.rs | 8 +-- src/server/terrain/resources.rs | 16 +++++- src/server/terrain/systems.rs | 68 +++++++++++++++---------- src/server/terrain/util/generator.rs | 34 ++++++------- 4 files changed, 78 insertions(+), 48 deletions(-) diff --git a/src/client/player/systems/controller.rs b/src/client/player/systems/controller.rs index 93f690cb..9e8b1bb3 100644 --- a/src/client/player/systems/controller.rs +++ b/src/client/player/systems/controller.rs @@ -1,7 +1,7 @@ use crate::prelude::*; // const SPAWN_POINT: Vec3 = Vec3::new(0.0, 32.0, 0.0); -const SPAWN_POINT: Vec3 = Vec3::new(128.0, 64.0, -128.0); +const SPAWN_POINT: Vec3 = Vec3::new(128.0, 96.0, -128.0); pub fn setup_player_camera(mut commands: Commands) { commands.spawn(( @@ -58,8 +58,10 @@ pub fn setup_controller_on_area_ready_system( Transform::from_translation(SPAWN_POINT), LogicalPlayer, FpsControllerInput { - pitch: -TAU / 20.0, - yaw: TAU * 5.0 / 12.0, + // pitch: -TAU / 20.0, + // yaw: TAU * 5.0 / 12.0, + pitch: 0.0, + yaw: 0.0, ..default() }, FpsController { diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 85d2a47b..81f63688 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -48,6 +48,7 @@ impl Default for Generator { pub struct TerrainGeneratorParams { pub splines: Vec, pub height_params: NoiseFunctionParams, + pub height_adjust_params: NoiseFunctionParams, pub density_params: NoiseFunctionParams, } @@ -55,8 +56,11 @@ impl Default for TerrainGeneratorParams { fn default() -> Self { Self { splines: vec![ - Vec2::new(-1.0, 0.0), - Vec2::new(1.0, 50.0), + Vec2::new(-1.0, -20.0), + Vec2::new(-0.5, 0.0), + Vec2::new(0.0, 20.0), + Vec2::new(0.5, 40.0), + Vec2::new(1.0, 60.0), ], height_params: NoiseFunctionParams { octaves: 4, @@ -66,6 +70,14 @@ impl Default for TerrainGeneratorParams { amplitude: 30.0, persistence: 0.5, }, + height_adjust_params: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 120.0, + amplitude: 30.0, + persistence: 0.5, + }, density_params: NoiseFunctionParams { octaves: 4, height: 0.0, diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index aed6794b..9cd2e239 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -37,7 +37,7 @@ mod visualizer { use renet::{DefaultChannel, RenetServer}; use rsmc::{Chunk, ChunkManager, NetworkingMessage, CHUNK_SIZE}; - use super::{terrain_events, terrain_resources}; + use super::{terrain_events, terrain_resources::{self, NoiseFunctionParams}}; fn generate_terrain_heightmap( generator: &terrain_resources::Generator, @@ -49,7 +49,7 @@ mod visualizer { let width = size.x as usize; let height = size.z as usize; - let draw_chunk_border = true; + let draw_chunk_border = false; for x in 0..width { for z in 0..height { @@ -152,6 +152,29 @@ mod visualizer { event_writer.send(terrain_events::RegenerateHeightMapEvent); } + macro_rules! add_slider { + ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ + $changed = $changed || $ui + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; + } + + fn add_sliders_for_noise_params(ui: &mut egui::Ui, changed: &mut bool, params: &mut NoiseFunctionParams) { + params.frequency = 1.0 / params.frequency; + + let mut loc_changed = false; + + add_slider!(ui, loc_changed, &mut params.octaves, 1..=8, "octaves"); + add_slider!(ui, loc_changed, &mut params.lacuranity, 0.001..=4.0, "lacuranity"); + add_slider!(ui, loc_changed, &mut params.frequency, 10.0..=800.0, "frequency"); + add_slider!(ui, loc_changed, &mut params.persistence, 0.001..=1.0, "persistence"); + + params.frequency = 1.0 / params.frequency; + + *changed = *changed || loc_changed; + } + #[rustfmt::skip] pub fn render_visualizer_system( mut contexts: EguiContexts, @@ -161,27 +184,26 @@ mod visualizer { mut world_regenerate_event_writer: EventWriter, ) { if let Some(texture_handle) = &noise_texture.texture { - egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| { - ui.label("world"); - - macro_rules! add_slider { - ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ - $changed |= $ui - .add(egui::widgets::Slider::new($value, $range).text($text)) - .changed(); - }}; - } - let mut changed = false; + egui::Window::new("Splines").show(contexts.ctx_mut(), |ui| { + egui_plot::Plot::new("splines") + .show(ui, |plot_ui| { + let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let line_chart = Line::new(PlotPoints::Owned(plot_points)); + plot_ui.line(line_chart); + }); + }); - generator.params.height_params.frequency = 1.0 / generator.params.height_params.frequency; + egui::Window::new("Secondary Height Map").show(contexts.ctx_mut(), |ui| { + }); - add_slider!(ui, changed, &mut generator.params.height_params.octaves, 1..=8, "octaves"); - add_slider!(ui, changed, &mut generator.params.height_params.lacuranity, 0.0..=4.0, "lacuranity"); - add_slider!(ui, changed, &mut generator.params.height_params.frequency, 10.0..=400.0, "frequency"); - add_slider!(ui, changed, &mut generator.params.height_params.persistence, 0.0..=1.0, "persistence"); + egui::Window::new("Height Map").show(contexts.ctx_mut(), |ui| { + ui.label("Main height map"); + + + let mut changed = false; - generator.params.height_params.frequency = 1.0 / generator.params.height_params.frequency; + add_sliders_for_noise_params(ui, &mut changed, &mut generator.params.height_params); let length = generator.params.splines.len(); @@ -190,7 +212,7 @@ mod visualizer { // Ensure range from 0 to 1 by locking the first and last splines add_slider!(ui, changed, &mut generator.params.splines[index].x, -1.0..=1.0, format!("x{}", index)); } - add_slider!(ui, changed, &mut generator.params.splines[index].y, -40.0..=40.0, format!("y{}", index)); + add_slider!(ui, changed, &mut generator.params.splines[index].y, -40.0..=80.0, format!("y{}", index)); } @@ -210,12 +232,6 @@ mod visualizer { texture_handle.size_vec2(), ))); - egui_plot::Plot::new("splines") - .show(ui, |plot_ui| { - let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); - let line_chart = Line::new(PlotPoints::Owned(plot_points)); - plot_ui.line(line_chart); - }); }); // egui::Window::new("Heightmap").show(contexts.ctx_mut(), |ui| { diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index aa4f37ae..a6230ff9 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -68,25 +68,24 @@ impl Generator { } fn determine_terrain_height(&self, position: Vec3) -> f64 { - let noise_value = self.sample_2d( - Vec2 { - x: position.x, - y: position.z, - }, - &self.params.height_params, - ).abs(); + let noise_value = self + .sample_2d( + Vec2 { + x: position.x, + y: position.z, + }, + &self.params.height_params, + ) + .abs(); self.spline_lerp(noise_value) } pub fn normalized_spline_terrain_sample(&self, position: Vec2) -> f64 { - let noise_value = self.sample_2d( - position, - &self.params.height_params, - ); + let noise_value = self.sample_2d(position, &self.params.height_params); let min_height = self.params.splines[0].y as f64; - let max_height = self.params.splines[self.params.splines.len() - 1].y as f64; + let max_height = self.params.splines[self.params.splines.len() - 1].y as f64; let splined_value = self.spline_lerp(noise_value); @@ -168,10 +167,9 @@ impl Generator { let mut weight_sum = 0.0; for _ in 0..params.octaves { - let new_sample = self.perlin.get([ - position.x as f64 * frequency, - position.y as f64 * frequency, - ]); + let new_sample = self + .perlin + .get([position.x as f64 * frequency, position.y as f64 * frequency]); frequency *= params.lacuranity; sample += new_sample * weight; @@ -181,7 +179,9 @@ impl Generator { sample /= weight_sum; - sample + sample as f64 + + // sample.abs() * 2.0 - 1.0 } } From 1a1856be92460b5ce4f92575c3cb146df972b925 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 18:08:18 +0100 Subject: [PATCH 28/68] Update README with implementation notes --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 45dc6877..fd1c6d50 100644 --- a/README.md +++ b/README.md @@ -59,3 +59,21 @@ Strongly inspired by the [Bevy NixOS installation guide](https://github.com/bevy nix-shell --run "cargo run --bin server" nix-shell --run "cargo run --bin client" ``` + +## Implementation notes + +### Terrain generation + +1. Step (terrain shaping) +- 3D fractal perlin noise with low frequency, squash factor to determine terrain density at xyz. +- 2D fractal perlin noise with higher frequency serving as a base layer. Use splines for ridged height map. +- Subtract 3D fractal perlin noise to get cave generation. +- Use strongly flattened 3D noise perlin or worley noise for different rock layers. + +- Place stone (base) + +2. Step (Decorating) +- Place grass on blocks where there is air above +- Use white noise to place some ores, grow them randomly? + + From 0f034656ddba28d82318dd4da55071252ee74f2d Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 18:41:33 +0100 Subject: [PATCH 29/68] Update texturetype impl --- src/server/terrain/resources.rs | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 81f63688..12bc80cf 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -92,7 +92,42 @@ impl Default for TerrainGeneratorParams { // visualizer +#[derive(PartialEq, Hash, Eq, Clone)] +pub enum TextureType { + Height, + HeightAdjust, + Density +} + +impl Display for TextureType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result<&str> { + match self { + Self::Height => Ok("terrain-height-texture"), + Self::HeightAdjust => Ok("terrain-height-adjust-texture"), + Self::Density => Ok("terrain-density-texture") + } + } +} + #[derive(Resource)] +pub struct NoiseTextureList { + pub noise_textures: HashMap +} + +impl Default for NoiseTextureList { + fn default() -> Self { + let mut noise_textures = HashMap::new(); + + noise_textures.insert(TextureType::Height, NoiseTexture::default()); + noise_textures.insert(TextureType::HeightAdjust, NoiseTexture::default()); + noise_textures.insert(TextureType::Density, NoiseTexture::default()); + + NoiseTextureList { + noise_textures, + } + } +} + pub struct NoiseTexture { pub texture: Option, pub size: Vec2, From 1ba1e4f5e76dff9bbd1509b50baf28cc28ab5300 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 18:41:45 +0100 Subject: [PATCH 30/68] Remove display impl --- src/server/terrain/resources.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 12bc80cf..4237f648 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -1,5 +1,8 @@ +use std::fmt::Display; + use crate::prelude::*; +use bevy::utils::HashMap; use bevy_inspector_egui::egui::TextureHandle; use terrain_events::BlockUpdateEvent; @@ -99,16 +102,6 @@ pub enum TextureType { Density } -impl Display for TextureType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result<&str> { - match self { - Self::Height => Ok("terrain-height-texture"), - Self::HeightAdjust => Ok("terrain-height-adjust-texture"), - Self::Density => Ok("terrain-density-texture") - } - } -} - #[derive(Resource)] pub struct NoiseTextureList { pub noise_textures: HashMap From 99caf223f4e61474449ebccaa396e45a123172dd Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 19:22:05 +0100 Subject: [PATCH 31/68] Update texture gui handling --- src/server/terrain/events.rs | 4 +- src/server/terrain/mod.rs | 2 +- src/server/terrain/systems.rs | 129 +++++++++++++++++++--------------- 3 files changed, 76 insertions(+), 59 deletions(-) diff --git a/src/server/terrain/events.rs b/src/server/terrain/events.rs index f3978b29..e9a8054c 100644 --- a/src/server/terrain/events.rs +++ b/src/server/terrain/events.rs @@ -1,3 +1,5 @@ +use terrain_resources::TextureType; + use crate::prelude::*; #[derive(Event)] @@ -8,7 +10,7 @@ pub struct BlockUpdateEvent { // visualizer #[derive(Event)] -pub struct RegenerateHeightMapEvent; +pub struct RegenerateHeightMapEvent(pub TextureType); #[derive(Event)] pub struct WorldRegenerateEvent; diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index ec48d625..2ed877f1 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -16,7 +16,7 @@ impl Plugin for TerrainPlugin { app.insert_resource(resources::Generator::default()); // visualizer - app.insert_resource(resources::NoiseTexture::default()); + app.insert_resource(resources::NoiseTextureList::default()); app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); app.add_systems(Update, terrain_systems::render_visualizer_system); app.add_systems(Update, terrain_systems::regenerate_heightmap_system); diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 9cd2e239..486a2545 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -22,7 +22,7 @@ pub use visualizer::*; mod visualizer { use bevy::{ - log::info, + log::{info, warn}, math::{Vec2, Vec3}, prelude::{EventReader, EventWriter, ResMut}, }; @@ -37,7 +37,7 @@ mod visualizer { use renet::{DefaultChannel, RenetServer}; use rsmc::{Chunk, ChunkManager, NetworkingMessage, CHUNK_SIZE}; - use super::{terrain_events, terrain_resources::{self, NoiseFunctionParams}}; + use super::{terrain_events, terrain_resources::{self, NoiseFunctionParams, NoiseTexture, TextureType}}; fn generate_terrain_heightmap( generator: &terrain_resources::Generator, @@ -101,7 +101,7 @@ mod visualizer { generator.generate_chunk(&mut chunk); chunk }) - .collect(); + .collect(); new_chunks.into_iter().for_each(|chunk| { chunk_manager.insert_chunk(chunk); @@ -123,10 +123,12 @@ mod visualizer { pub fn regenerate_heightmap_system( mut events: EventReader, generator: ResMut, - mut noise_texture: ResMut, + mut noise_texture_list: ResMut, mut contexts: EguiContexts, ) { - for _ in events.read() { + for event in events.read() { + let texture_type = event.0.clone(); + let width = 512; let height = 512; let depth = 512; @@ -137,19 +139,23 @@ mod visualizer { Vec3::new(width as f32, height as f32, depth as f32), ); - noise_texture.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), + let entry = noise_texture_list.noise_textures.get_mut(&texture_type).expect("Noise texture not loaded, please initialize the resource properly."); + + entry.texture = Some(contexts.ctx_mut().load_texture( + "terrain-texture", + image_data, + TextureOptions::default(), )); - noise_texture.size = Vec2::new(width as f32, height as f32); + entry.size = Vec2::new(width as f32, height as f32); } } pub fn prepare_visualizer_texture_system( mut event_writer: EventWriter, ) { - event_writer.send(terrain_events::RegenerateHeightMapEvent); + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::HeightAdjust)); + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Density)); } macro_rules! add_slider { @@ -178,69 +184,78 @@ mod visualizer { #[rustfmt::skip] pub fn render_visualizer_system( mut contexts: EguiContexts, - noise_texture: ResMut, + noise_texture_list: ResMut, mut generator: ResMut, mut event_writer: EventWriter, mut world_regenerate_event_writer: EventWriter, ) { - if let Some(texture_handle) = &noise_texture.texture { - - egui::Window::new("Splines").show(contexts.ctx_mut(), |ui| { - egui_plot::Plot::new("splines") - .show(ui, |plot_ui| { - let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); - let line_chart = Line::new(PlotPoints::Owned(plot_points)); - plot_ui.line(line_chart); - }); - }); + egui::Window::new("Splines").show(contexts.ctx_mut(), |ui| { + egui_plot::Plot::new("splines") + .show(ui, |plot_ui| { + let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let line_chart = Line::new(PlotPoints::Owned(plot_points)); + plot_ui.line(line_chart); + }); + + let mut changed = false; + + let length = generator.params.splines.len(); + + for index in 0..length { + if index != 0 && index != length - 1 { + // Ensure range from 0 to 1 by locking the first and last splines + add_slider!(ui, changed, &mut generator.params.splines[index].x, -1.0..=1.0, format!("x{}", index)); + } + add_slider!(ui, changed, &mut generator.params.splines[index].y, -40.0..=80.0, format!("y{}", index)); + } - egui::Window::new("Secondary Height Map").show(contexts.ctx_mut(), |ui| { - }); + if changed { + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); + } - egui::Window::new("Height Map").show(contexts.ctx_mut(), |ui| { - ui.label("Main height map"); + if ui.button("Regenerate world").clicked() { + world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); + } + }); + let noise_textures = &noise_texture_list.noise_textures; - let mut changed = false; + for (texture_type, noise_texture) in noise_textures { + let texture_handle = noise_texture.texture.as_ref(); - add_sliders_for_noise_params(ui, &mut changed, &mut generator.params.height_params); + match texture_handle { + None => { + warn!("Noise texture handle could not be borrowed") + }, + Some(texture_handle) => { + let window_name = match texture_type { + TextureType::Height => "Base Height", + TextureType::HeightAdjust => "Height adjustment", + TextureType::Density => "Density", + }; - let length = generator.params.splines.len(); + egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { + ui.label(window_name); - for index in 0..length { - if index != 0 && index != length - 1 { - // Ensure range from 0 to 1 by locking the first and last splines - add_slider!(ui, changed, &mut generator.params.splines[index].x, -1.0..=1.0, format!("x{}", index)); - } - add_slider!(ui, changed, &mut generator.params.splines[index].y, -40.0..=80.0, format!("y{}", index)); - } + let mut changed = false; + add_sliders_for_noise_params(ui, &mut changed, &mut generator.params.height_params); - if changed { - event_writer.send(terrain_events::RegenerateHeightMapEvent); - }; + if changed { + event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); + }; - ui.label(format!("{:?}", generator.params.height_params)); + ui.label(format!("{:?}", generator.params.height_params)); - if ui.button("Regenerate world").clicked() { - world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); + ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( + texture_handle.id(), + texture_handle.size_vec2(), + ))); + }); } + } - ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( - texture_handle.id(), - texture_handle.size_vec2(), - ))); - - }); - - // egui::Window::new("Heightmap").show(contexts.ctx_mut(), |ui| { - // ui.label(format!("{:?}", noise_texture.size)); - // ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( - // noise_texture.texture.unwrap().id(), - // noise_texture.size_vec2(), - // ))); - // }); - } + }; } } From 043e97237a05c2fb89b0ce4cec77c06d4fd22c52 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 19:34:38 +0100 Subject: [PATCH 32/68] Update egui --- src/server/terrain/resources.rs | 2 +- src/server/terrain/systems.rs | 29 ++++++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 4237f648..b9f7d2c9 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -95,7 +95,7 @@ impl Default for TerrainGeneratorParams { // visualizer -#[derive(PartialEq, Hash, Eq, Clone)] +#[derive(PartialEq, Hash, Eq, Clone, Debug)] pub enum TextureType { Height, HeightAdjust, diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 486a2545..4d717974 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -129,6 +129,8 @@ mod visualizer { for event in events.read() { let texture_type = event.0.clone(); + info!("Regenerating noise preview for {:?}", texture_type); + let width = 512; let height = 512; let depth = 512; @@ -190,12 +192,9 @@ mod visualizer { mut world_regenerate_event_writer: EventWriter, ) { egui::Window::new("Splines").show(contexts.ctx_mut(), |ui| { - egui_plot::Plot::new("splines") - .show(ui, |plot_ui| { - let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); - let line_chart = Line::new(PlotPoints::Owned(plot_points)); - plot_ui.line(line_chart); - }); + if ui.button("Organize windows").clicked() { + ui.ctx().memory_mut(|mem| mem.reset_areas()); + } let mut changed = false; @@ -216,6 +215,13 @@ mod visualizer { if ui.button("Regenerate world").clicked() { world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); } + + egui_plot::Plot::new("splines") + .show(ui, |plot_ui| { + let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let line_chart = Line::new(PlotPoints::Owned(plot_points)); + plot_ui.line(line_chart); + }); }); let noise_textures = &noise_texture_list.noise_textures; @@ -234,19 +240,24 @@ mod visualizer { TextureType::Density => "Density", }; + let mut params = match texture_type { + TextureType::Height => generator.params.height_params, + TextureType::HeightAdjust => generator.params.height_adjust_params, + TextureType::Density => generator.params.density_params + }; + egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { ui.label(window_name); let mut changed = false; - add_sliders_for_noise_params(ui, &mut changed, &mut generator.params.height_params); - + add_sliders_for_noise_params(ui, &mut changed, &mut params); if changed { event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); }; - ui.label(format!("{:?}", generator.params.height_params)); + ui.label(format!("{:?}", params)); ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( texture_handle.id(), From 5d00f8fa071bf3c74d9efcb6f59fb77f565db173 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 19:50:52 +0100 Subject: [PATCH 33/68] Improve texture gen --- src/server/terrain/systems.rs | 45 +++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 4d717974..db9dee2e 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -39,34 +39,57 @@ mod visualizer { use super::{terrain_events, terrain_resources::{self, NoiseFunctionParams, NoiseTexture, TextureType}}; + fn map_range(value: f64, min: f64, max: f64, new_min: f64, new_max: f64) -> f64 { + ((value - min) / (max - min)) * (new_max - new_min) + new_min + } + fn generate_terrain_heightmap( generator: &terrain_resources::Generator, + texture_type: &TextureType, origin: Vec3, size: Vec3, + draw_chunk_border: bool, ) -> ImageData { let mut data = vec![0; (size.x * size.z) as usize]; let width = size.x as usize; let height = size.z as usize; - let draw_chunk_border = false; - for x in 0..width { for z in 0..height { - let sample_position = - Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); - // let value = generator.sample_2d(sample_position, &generator.params.height_params); - let value = generator.normalized_spline_terrain_sample(sample_position); - let value = ( value * size.y as f64 ) / 2.0 + 0.5; - let mut value = value as u8; + let index = x + z * width; if draw_chunk_border { if x % CHUNK_SIZE == 0 || z % CHUNK_SIZE == 0 { - value = 255; + data[index] = 255; + continue; } } - data[x + z * width] = value; + match texture_type { + TextureType::Height => { + let sample_position = Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); + let value = generator.normalized_spline_terrain_sample(sample_position); + let value = ( value * size.y as f64 ) / 2.0 + 0.5; + + data[index] = value as u8; + } + TextureType::HeightAdjust => { + let sample_position = Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); + let value = generator.sample_2d(sample_position, &generator.params.height_adjust_params); + let value = map_range(value, -1.0, 1.0, 0.0, 255.0); + + data[index] = value as u8; + } + TextureType::Density => { + // TODO: change to sample3D + let pos = Vec2::new(origin.x + x as f32, origin.z + z as f32); + let value = generator.sample_2d(pos, &generator.params.density_params); + let value = map_range(value, -1.0, 1.0, 0.0, 255.0); + + data[index] = value as u8; + } + }; } } @@ -137,8 +160,10 @@ mod visualizer { let image_data = generate_terrain_heightmap( &generator, + &texture_type, Vec3::ZERO, Vec3::new(width as f32, height as f32, depth as f32), + true ); let entry = noise_texture_list.noise_textures.get_mut(&texture_type).expect("Noise texture not loaded, please initialize the resource properly."); From 8a24e32bf84e6ab17ffb47db87667468d0c412e5 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 19:52:25 +0100 Subject: [PATCH 34/68] Fastcheck --- src/client/player/systems/controller.rs | 21 +++--- src/server/terrain/resources.rs | 10 +-- src/server/terrain/systems.rs | 96 ++++++++++++++++--------- src/server/terrain/util/generator.rs | 2 +- 4 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/client/player/systems/controller.rs b/src/client/player/systems/controller.rs index 9e8b1bb3..dfaecbfb 100644 --- a/src/client/player/systems/controller.rs +++ b/src/client/player/systems/controller.rs @@ -5,23 +5,20 @@ const SPAWN_POINT: Vec3 = Vec3::new(128.0, 96.0, -128.0); pub fn setup_player_camera(mut commands: Commands) { commands.spawn(( - Name::new("Player cam?"), + Name::new("Player cam?"), Camera3d::default(), // Projection::Perspective(PerspectiveProjection { // fov: TAU / 5.0, // ..default() // }), - Projection::Orthographic( - OrthographicProjection { - scale: 0.125, - near: 0.0001, - far: 1000.0, - viewport_origin: Vec2::new(0.5, 0.5), - scaling_mode: ScalingMode::WindowSize, - area: Rect::new(-1.0, -1.0, 1.0, 1.0), - } - .into(), - ), + Projection::Orthographic(OrthographicProjection { + scale: 0.125, + near: 0.0001, + far: 1000.0, + viewport_origin: Vec2::new(0.5, 0.5), + scaling_mode: ScalingMode::WindowSize, + area: Rect::new(-1.0, -1.0, 1.0, 1.0), + }), RenderPlayer { logical_entity: Entity::from_raw(0), }, diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index b9f7d2c9..960e4daa 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -1,5 +1,3 @@ -use std::fmt::Display; - use crate::prelude::*; use bevy::utils::HashMap; @@ -99,12 +97,12 @@ impl Default for TerrainGeneratorParams { pub enum TextureType { Height, HeightAdjust, - Density + Density, } #[derive(Resource)] pub struct NoiseTextureList { - pub noise_textures: HashMap + pub noise_textures: HashMap, } impl Default for NoiseTextureList { @@ -115,9 +113,7 @@ impl Default for NoiseTextureList { noise_textures.insert(TextureType::HeightAdjust, NoiseTexture::default()); noise_textures.insert(TextureType::Density, NoiseTexture::default()); - NoiseTextureList { - noise_textures, - } + NoiseTextureList { noise_textures } } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index db9dee2e..2afbdf67 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -37,7 +37,10 @@ mod visualizer { use renet::{DefaultChannel, RenetServer}; use rsmc::{Chunk, ChunkManager, NetworkingMessage, CHUNK_SIZE}; - use super::{terrain_events, terrain_resources::{self, NoiseFunctionParams, NoiseTexture, TextureType}}; + use super::{ + terrain_events, + terrain_resources::{self, NoiseFunctionParams, TextureType}, + }; fn map_range(value: f64, min: f64, max: f64, new_min: f64, new_max: f64) -> f64 { ((value - min) / (max - min)) * (new_max - new_min) + new_min @@ -46,7 +49,6 @@ mod visualizer { fn generate_terrain_heightmap( generator: &terrain_resources::Generator, texture_type: &TextureType, - origin: Vec3, size: Vec3, draw_chunk_border: bool, ) -> ImageData { @@ -59,31 +61,30 @@ mod visualizer { for z in 0..height { let index = x + z * width; - if draw_chunk_border { - if x % CHUNK_SIZE == 0 || z % CHUNK_SIZE == 0 { - data[index] = 255; - continue; - } + if draw_chunk_border && (x % CHUNK_SIZE == 0 || z % CHUNK_SIZE == 0) { + data[index] = 255; + continue; } match texture_type { TextureType::Height => { - let sample_position = Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); + let sample_position = Vec2::new(x as f32, z as f32); let value = generator.normalized_spline_terrain_sample(sample_position); - let value = ( value * size.y as f64 ) / 2.0 + 0.5; + let value = (value * size.y as f64) / 2.0 + 0.5; - data[index] = value as u8; + data[index] = value as u8; } TextureType::HeightAdjust => { - let sample_position = Vec2::new((origin.x + x as f32) / 1.0, (origin.z + z as f32) / 1.0); - let value = generator.sample_2d(sample_position, &generator.params.height_adjust_params); + let sample_position = Vec2::new(x as f32, z as f32); + let value = generator + .sample_2d(sample_position, &generator.params.height_adjust_params); let value = map_range(value, -1.0, 1.0, 0.0, 255.0); - data[index] = value as u8; + data[index] = value as u8; } TextureType::Density => { // TODO: change to sample3D - let pos = Vec2::new(origin.x + x as f32, origin.z + z as f32); + let pos = Vec2::new(x as f32, z as f32); let value = generator.sample_2d(pos, &generator.params.density_params); let value = map_range(value, -1.0, 1.0, 0.0, 255.0); @@ -124,7 +125,7 @@ mod visualizer { generator.generate_chunk(&mut chunk); chunk }) - .collect(); + .collect(); new_chunks.into_iter().for_each(|chunk| { chunk_manager.insert_chunk(chunk); @@ -161,17 +162,19 @@ mod visualizer { let image_data = generate_terrain_heightmap( &generator, &texture_type, - Vec3::ZERO, Vec3::new(width as f32, height as f32, depth as f32), - true + true, ); - let entry = noise_texture_list.noise_textures.get_mut(&texture_type).expect("Noise texture not loaded, please initialize the resource properly."); + let entry = noise_texture_list + .noise_textures + .get_mut(&texture_type) + .expect("Noise texture not loaded, please initialize the resource properly."); entry.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), + "terrain-texture", + image_data, + TextureOptions::default(), )); entry.size = Vec2::new(width as f32, height as f32); } @@ -180,28 +183,57 @@ mod visualizer { pub fn prepare_visualizer_texture_system( mut event_writer: EventWriter, ) { - event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); - event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::HeightAdjust)); - event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Density)); + event_writer.send(terrain_events::RegenerateHeightMapEvent( + TextureType::Height, + )); + event_writer.send(terrain_events::RegenerateHeightMapEvent( + TextureType::HeightAdjust, + )); + event_writer.send(terrain_events::RegenerateHeightMapEvent( + TextureType::Density, + )); } macro_rules! add_slider { ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ - $changed = $changed || $ui - .add(egui::widgets::Slider::new($value, $range).text($text)) - .changed(); - }}; + $changed = $changed + || $ui + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; } - fn add_sliders_for_noise_params(ui: &mut egui::Ui, changed: &mut bool, params: &mut NoiseFunctionParams) { + fn add_sliders_for_noise_params( + ui: &mut egui::Ui, + changed: &mut bool, + params: &mut NoiseFunctionParams, + ) { params.frequency = 1.0 / params.frequency; let mut loc_changed = false; add_slider!(ui, loc_changed, &mut params.octaves, 1..=8, "octaves"); - add_slider!(ui, loc_changed, &mut params.lacuranity, 0.001..=4.0, "lacuranity"); - add_slider!(ui, loc_changed, &mut params.frequency, 10.0..=800.0, "frequency"); - add_slider!(ui, loc_changed, &mut params.persistence, 0.001..=1.0, "persistence"); + add_slider!( + ui, + loc_changed, + &mut params.lacuranity, + 0.001..=4.0, + "lacuranity" + ); + add_slider!( + ui, + loc_changed, + &mut params.frequency, + 10.0..=800.0, + "frequency" + ); + add_slider!( + ui, + loc_changed, + &mut params.persistence, + 0.001..=1.0, + "persistence" + ); params.frequency = 1.0 / params.frequency; diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index a6230ff9..c69b3c03 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -179,7 +179,7 @@ impl Generator { sample /= weight_sum; - sample as f64 + sample // sample.abs() * 2.0 - 1.0 } From 3ac7c3a2c70a1b4381fe1d22f1719e12183305bb Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 20:52:27 +0100 Subject: [PATCH 35/68] Fix noise params it was an implicit clone which was causing the problem --- src/server/terrain/resources.rs | 2 +- src/server/terrain/systems.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 960e4daa..f181fc02 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -30,7 +30,7 @@ pub struct Generator { pub params: TerrainGeneratorParams, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub struct NoiseFunctionParams { pub octaves: i32, pub height: f64, diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 2afbdf67..42622a31 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -297,10 +297,10 @@ mod visualizer { TextureType::Density => "Density", }; - let mut params = match texture_type { - TextureType::Height => generator.params.height_params, - TextureType::HeightAdjust => generator.params.height_adjust_params, - TextureType::Density => generator.params.density_params + let params: &mut NoiseFunctionParams = match texture_type { + TextureType::Height => &mut generator.params.height_params, + TextureType::HeightAdjust => &mut generator.params.height_adjust_params, + TextureType::Density => &mut generator.params.density_params }; egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { @@ -308,7 +308,7 @@ mod visualizer { let mut changed = false; - add_sliders_for_noise_params(ui, &mut changed, &mut params); + add_sliders_for_noise_params(ui, &mut changed, params); if changed { event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); From dd0c99139eb65a427abd7f040f40f19d24c35c77 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 21:33:53 +0100 Subject: [PATCH 36/68] Improve feature flags :3 --- Cargo.toml | 17 +++++-- src/client/networking/systems.rs | 2 - src/client/player/systems/controller.rs | 10 ++-- src/client/terrain/systems.rs | 1 - src/server/main.rs | 16 ++++-- src/server/networking/mod.rs | 2 - src/server/terrain/events.rs | 19 ++++--- src/server/terrain/mod.rs | 18 ++++--- src/server/terrain/resources.rs | 66 ++++++++++++++----------- src/server/terrain/systems.rs | 3 ++ src/server/terrain/util/generator.rs | 20 ++++---- src/shared/networking.rs | 1 - 12 files changed, 104 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e251edb..60e45aa1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,12 +42,23 @@ name = "server" path = "src/server/main.rs" [features] -chat = ["bevy/dynamic_linking"] +default = ["chat", "player_controller"] +dynamic_linking = ["bevy/dynamic_linking"] + +# both +chat = ["dynamic_linking"] +# server +renet_visualizer = ["egui_layer"] +generator_visualizer = ["egui_layer"] +egui_layer = [] +skip_chunk_padding = [] + +# client wireframe = [] debug_ui = [] -renet_visualizer = [] +ortho_camera = [] +player_controller = [] physics_debug = [] raycast_debug = [] visual_debug = ["wireframe", "physics_debug", "raycast_debug"] -dynamic_linking = ["bevy/dynamic_linking"] diff --git a/src/client/networking/systems.rs b/src/client/networking/systems.rs index 4eeb9e73..10ee0fc7 100644 --- a/src/client/networking/systems.rs +++ b/src/client/networking/systems.rs @@ -9,7 +9,6 @@ pub fn receive_message_system( mut block_update_events: ResMut>, mut chunk_manager: ResMut, mut chunk_mesh_events: ResMut>, - // visualizer mut world_regenerate_events: ResMut>, #[cfg(feature = "chat")] mut chat_events: ResMut>, #[cfg(feature = "chat")] mut single_chat_events: ResMut< @@ -97,7 +96,6 @@ pub fn receive_message_system( player_sync_events .send(remote_player_events::RemotePlayerSyncEvent { players: event }); } - // visualizer NetworkingMessage::ServerAsksClientNicelyToRerequestChunkBatch() => { info!("Client asked for chunk batch."); world_regenerate_events.send(terrain_events::WorldRegenerateEvent); diff --git a/src/client/player/systems/controller.rs b/src/client/player/systems/controller.rs index dfaecbfb..f3ac1356 100644 --- a/src/client/player/systems/controller.rs +++ b/src/client/player/systems/controller.rs @@ -7,10 +7,12 @@ pub fn setup_player_camera(mut commands: Commands) { commands.spawn(( Name::new("Player cam?"), Camera3d::default(), - // Projection::Perspective(PerspectiveProjection { - // fov: TAU / 5.0, - // ..default() - // }), + #[cfg(not(feature = "ortho_camera"))] + Projection::Perspective(PerspectiveProjection { + fov: TAU / 5.0, + ..default() + }), + #[cfg(feature = "ortho_camera")] Projection::Orthographic(OrthographicProjection { scale: 0.125, near: 0.0001, diff --git a/src/client/terrain/systems.rs b/src/client/terrain/systems.rs index 7b297262..0c94f998 100644 --- a/src/client/terrain/systems.rs +++ b/src/client/terrain/systems.rs @@ -163,7 +163,6 @@ fn spawn_chunk( )); } -// visualizer pub fn handle_terrain_regeneration_events( mut client: ResMut, mut world_regenerate_events: EventReader, diff --git a/src/server/main.rs b/src/server/main.rs index 64b68368..9f1c01fc 100644 --- a/src/server/main.rs +++ b/src/server/main.rs @@ -4,29 +4,35 @@ pub mod player; pub mod prelude; pub mod terrain; -#[cfg(feature = "renet_visualizer")] +#[cfg(feature = "egui_layer")] use bevy::DefaultPlugins; -#[cfg(not(feature = "renet_visualizer"))] +#[cfg(not(feature = "egui_layer"))] use bevy::log::LogPlugin; use crate::prelude::*; fn main() { let mut app = App::new(); - #[cfg(not(feature = "renet_visualizer"))] + #[cfg(not(feature = "egui_layer"))] { app.add_plugins(MinimalPlugins); app.add_plugins(LogPlugin::default()); } - #[cfg(feature = "renet_visualizer")] - app.add_plugins(DefaultPlugins); + #[cfg(feature = "egui_layer")] + { + use bevy_inspector_egui::bevy_egui::EguiPlugin; + app.add_plugins(DefaultPlugins); + app.add_plugins(EguiPlugin); + } app.add_plugins(player::PlayerPlugin); app.add_plugins(networking::NetworkingPlugin); app.add_plugins(terrain::TerrainPlugin); + #[cfg(feature = "chat")] app.add_plugins(chat::ChatPlugin); + app.run(); } diff --git a/src/server/networking/mod.rs b/src/server/networking/mod.rs index 0cd5df05..f97d39c0 100644 --- a/src/server/networking/mod.rs +++ b/src/server/networking/mod.rs @@ -14,10 +14,8 @@ impl Plugin for NetworkingPlugin { #[cfg(feature = "renet_visualizer")] { - use bevy_inspector_egui::bevy_egui::EguiPlugin; use renet_visualizer::RenetServerVisualizer; - app.add_plugins(EguiPlugin); app.insert_resource(RenetServerVisualizer::<200>::default()); app.add_systems( Update, diff --git a/src/server/terrain/events.rs b/src/server/terrain/events.rs index e9a8054c..cfe17ee9 100644 --- a/src/server/terrain/events.rs +++ b/src/server/terrain/events.rs @@ -1,4 +1,3 @@ -use terrain_resources::TextureType; use crate::prelude::*; @@ -8,9 +7,17 @@ pub struct BlockUpdateEvent { pub block: BlockId, } -// visualizer -#[derive(Event)] -pub struct RegenerateHeightMapEvent(pub TextureType); +#[cfg(feature = "generator_visualizer")] +pub use visualizer::*; +#[cfg(feature = "generator_visualizer")] +mod visualizer { + use super::*; + use terrain_resources::TextureType; + + #[derive(Event)] + pub struct RegenerateHeightMapEvent(pub TextureType); + + #[derive(Event)] + pub struct WorldRegenerateEvent; +} -#[derive(Event)] -pub struct WorldRegenerateEvent; diff --git a/src/server/terrain/mod.rs b/src/server/terrain/mod.rs index 2ed877f1..2983cf47 100644 --- a/src/server/terrain/mod.rs +++ b/src/server/terrain/mod.rs @@ -15,14 +15,16 @@ impl Plugin for TerrainPlugin { app.add_systems(Startup, terrain_systems::setup_world_system); app.insert_resource(resources::Generator::default()); - // visualizer - app.insert_resource(resources::NoiseTextureList::default()); - app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); - app.add_systems(Update, terrain_systems::render_visualizer_system); - app.add_systems(Update, terrain_systems::regenerate_heightmap_system); - app.add_systems(Update, terrain_systems::handle_regenerate_event_system); + #[cfg(feature = "generator_visualizer")] + { + app.insert_resource(resources::NoiseTextureList::default()); + app.add_systems(Startup, terrain_systems::prepare_visualizer_texture_system); + app.add_systems(Update, terrain_systems::render_visualizer_system); + app.add_systems(Update, terrain_systems::regenerate_heightmap_system); + app.add_systems(Update, terrain_systems::handle_regenerate_event_system); - app.add_event::(); - app.add_event::(); + app.add_event::(); + app.add_event::(); + } } } diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index f181fc02..34e533f1 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -1,7 +1,5 @@ use crate::prelude::*; -use bevy::utils::HashMap; -use bevy_inspector_egui::egui::TextureHandle; use terrain_events::BlockUpdateEvent; #[derive(Resource)] @@ -91,42 +89,50 @@ impl Default for TerrainGeneratorParams { } } -// visualizer +#[cfg(feature = "generator_visualizer")] +pub use visualizer::*; -#[derive(PartialEq, Hash, Eq, Clone, Debug)] -pub enum TextureType { - Height, - HeightAdjust, - Density, -} +#[cfg(feature = "generator_visualizer")] +mod visualizer { + use super::*; + use bevy::utils::HashMap; + use bevy_inspector_egui::egui::TextureHandle; -#[derive(Resource)] -pub struct NoiseTextureList { - pub noise_textures: HashMap, -} + #[derive(PartialEq, Hash, Eq, Clone, Debug)] + pub enum TextureType { + Height, + HeightAdjust, + Density, + } -impl Default for NoiseTextureList { - fn default() -> Self { - let mut noise_textures = HashMap::new(); + #[derive(Resource)] + pub struct NoiseTextureList { + pub noise_textures: HashMap, + } - noise_textures.insert(TextureType::Height, NoiseTexture::default()); - noise_textures.insert(TextureType::HeightAdjust, NoiseTexture::default()); - noise_textures.insert(TextureType::Density, NoiseTexture::default()); + impl Default for NoiseTextureList { + fn default() -> Self { + let mut noise_textures = HashMap::new(); - NoiseTextureList { noise_textures } + noise_textures.insert(TextureType::Height, NoiseTexture::default()); + noise_textures.insert(TextureType::HeightAdjust, NoiseTexture::default()); + noise_textures.insert(TextureType::Density, NoiseTexture::default()); + + NoiseTextureList { noise_textures } + } } -} -pub struct NoiseTexture { - pub texture: Option, - pub size: Vec2, -} + pub struct NoiseTexture { + pub texture: Option, + pub size: Vec2, + } -impl Default for NoiseTexture { - fn default() -> Self { - NoiseTexture { - texture: None, - size: Vec2::ZERO, + impl Default for NoiseTexture { + fn default() -> Self { + NoiseTexture { + texture: None, + size: Vec2::ZERO, + } } } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 42622a31..5db20d66 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -18,8 +18,10 @@ pub fn setup_world_system( chunk_manager.insert_chunks(chunks); } +#[cfg(feature = "generator_visualizer")] pub use visualizer::*; +#[cfg(feature = "generator_visualizer")] mod visualizer { use bevy::{ log::{info, warn}, @@ -40,6 +42,7 @@ mod visualizer { use super::{ terrain_events, terrain_resources::{self, NoiseFunctionParams, TextureType}, + prelude::*, }; fn map_range(value: f64, min: f64, max: f64, new_min: f64, new_max: f64) -> f64 { diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index c69b3c03..eaadc013 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -16,17 +16,19 @@ impl Generator { } pub fn generate_chunk(&self, chunk: &mut Chunk) { - let chunk_origin = chunk.position * CHUNK_SIZE as f32; - if chunk_origin.y < 0.0 { + if chunk.position.y < 0.0 { return; } - // for x in 0..CHUNK_SIZE + 2 { - // for y in 0..CHUNK_SIZE + 2 { - // for z in 0..CHUNK_SIZE + 2 { - for x in 1..CHUNK_SIZE + 1 { - for y in 1..CHUNK_SIZE + 1 { - for z in 1..CHUNK_SIZE + 1 { + for x in 0..CHUNK_SIZE + 2 { + for y in 0..CHUNK_SIZE + 2 { + for z in 0..CHUNK_SIZE + 2 { + #[cfg(feature = "skip_chunk_padding")] + if x == 0 || x == CHUNK_SIZE + 1 || y == 0 || y == CHUNK_SIZE + 1 || z == 0 || z == CHUNK_SIZE + 1 { + continue; + } + + let chunk_origin = chunk.position * CHUNK_SIZE as f32; let local_position = Vec3::new(x as f32, y as f32, z as f32); let block_position = chunk_origin + local_position; let block = self.generate_block(block_position); @@ -181,7 +183,7 @@ impl Generator { sample - // sample.abs() * 2.0 - 1.0 + // sample.abs() * 2.0 - 1.0 } } diff --git a/src/shared/networking.rs b/src/shared/networking.rs index 11a16c31..e5b68349 100644 --- a/src/shared/networking.rs +++ b/src/shared/networking.rs @@ -50,7 +50,6 @@ pub enum NetworkingMessage { SingleChatMessageSync(ChatMessage), ChatMessageSync(Vec), BlockUpdate { position: Vec3, block: BlockId }, - // visualizer ServerAsksClientNicelyToRerequestChunkBatch(), } From a3c31ac2481cf8154b940939d61facddb9070469 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 21:34:04 +0100 Subject: [PATCH 37/68] Fix linter --- src/server/terrain/events.rs | 2 -- src/server/terrain/systems.rs | 2 +- src/server/terrain/util/generator.rs | 10 ++++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/server/terrain/events.rs b/src/server/terrain/events.rs index cfe17ee9..987f4b98 100644 --- a/src/server/terrain/events.rs +++ b/src/server/terrain/events.rs @@ -1,4 +1,3 @@ - use crate::prelude::*; #[derive(Event)] @@ -20,4 +19,3 @@ mod visualizer { #[derive(Event)] pub struct WorldRegenerateEvent; } - diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 5db20d66..be18873a 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -40,9 +40,9 @@ mod visualizer { use rsmc::{Chunk, ChunkManager, NetworkingMessage, CHUNK_SIZE}; use super::{ + prelude::*, terrain_events, terrain_resources::{self, NoiseFunctionParams, TextureType}, - prelude::*, }; fn map_range(value: f64, min: f64, max: f64, new_min: f64, new_max: f64) -> f64 { diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index eaadc013..2ede0dc6 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -24,7 +24,13 @@ impl Generator { for y in 0..CHUNK_SIZE + 2 { for z in 0..CHUNK_SIZE + 2 { #[cfg(feature = "skip_chunk_padding")] - if x == 0 || x == CHUNK_SIZE + 1 || y == 0 || y == CHUNK_SIZE + 1 || z == 0 || z == CHUNK_SIZE + 1 { + if x == 0 + || x == CHUNK_SIZE + 1 + || y == 0 + || y == CHUNK_SIZE + 1 + || z == 0 + || z == CHUNK_SIZE + 1 + { continue; } @@ -183,7 +189,7 @@ impl Generator { sample - // sample.abs() * 2.0 - 1.0 + // sample.abs() * 2.0 - 1.0 } } From 7fd42e99d14046300aa7449905e4d62976d7610d Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 21:39:11 +0100 Subject: [PATCH 38/68] Cleanup feature flags --- Cargo.toml | 4 ++-- src/client/player/systems/controller.rs | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 60e45aa1..c2a4528a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ name = "server" path = "src/server/main.rs" [features] -default = ["chat", "player_controller"] +default = ["chat"] dynamic_linking = ["bevy/dynamic_linking"] # both @@ -58,7 +58,7 @@ skip_chunk_padding = [] wireframe = [] debug_ui = [] ortho_camera = [] -player_controller = [] +lock_player = [] physics_debug = [] raycast_debug = [] visual_debug = ["wireframe", "physics_debug", "raycast_debug"] diff --git a/src/client/player/systems/controller.rs b/src/client/player/systems/controller.rs index f3ac1356..b7b1d610 100644 --- a/src/client/player/systems/controller.rs +++ b/src/client/player/systems/controller.rs @@ -1,6 +1,8 @@ use crate::prelude::*; -// const SPAWN_POINT: Vec3 = Vec3::new(0.0, 32.0, 0.0); +#[cfg(not(feature = "lock_player"))] +const SPAWN_POINT: Vec3 = Vec3::new(0.0, 32.0, 0.0); +#[cfg(feature = "lock_player")] const SPAWN_POINT: Vec3 = Vec3::new(128.0, 96.0, -128.0); pub fn setup_player_camera(mut commands: Commands) { @@ -48,7 +50,10 @@ pub fn setup_controller_on_area_ready_system( }, ActiveEvents::COLLISION_EVENTS, Velocity::zero(), + #[cfg(feature = "lock_player")] RigidBody::Fixed, + #[cfg(not(feature = "lock_player"))] + RigidBody::Dynamic, Sleeping::disabled(), LockedAxes::ROTATION_LOCKED, AdditionalMassProperties::Mass(1.0), @@ -56,9 +61,14 @@ pub fn setup_controller_on_area_ready_system( Ccd { enabled: true }, // Prevent clipping when going fast Transform::from_translation(SPAWN_POINT), LogicalPlayer, + #[cfg(not(feature = "lock_player"))] + FpsControllerInput { + pitch: -TAU / 20.0, + yaw: TAU * 5.0 / 12.0, + ..default() + }, + #[cfg(feature = "lock_player")] FpsControllerInput { - // pitch: -TAU / 20.0, - // yaw: TAU * 5.0 / 12.0, pitch: 0.0, yaw: 0.0, ..default() From 39f698bc75eff9e3e82535b77cc6046ccab190db Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:08:25 +0100 Subject: [PATCH 39/68] Refactor generator? --- src/server/terrain/util/generator.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 2ede0dc6..fe1e31f4 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -166,18 +166,22 @@ impl Generator { max } - pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { + fn sample(&self, position: Vec, params: &NoiseFunctionParams) -> f64 { let mut sample = 0.0; - let mut frequency = params.frequency; let mut weight = 1.0; - let mut weight_sum = 0.0; for _ in 0..params.octaves { - let new_sample = self - .perlin - .get([position.x as f64 * frequency, position.y as f64 * frequency]); + let pos: Vec = position.clone().into_iter().map(|v| v * frequency).collect(); + + let new_sample = match pos.len() { + 1 => self.perlin.get([pos[0]]), + 2 => self.perlin.get([pos[0], pos[1]]), + 3 => self.perlin.get([pos[0], pos[1], pos[2]]), + 4 => self.perlin.get([pos[0], pos[1], pos[2], pos[3]]), + _ => panic!("Incorrect dimension for noise sample, must be either 2, 3 or 4") + }; frequency *= params.lacuranity; sample += new_sample * weight; @@ -185,11 +189,15 @@ impl Generator { weight *= params.persistence; } - sample /= weight_sum; + sample / weight_sum + } - sample + pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { + self.sample(position.to_array().map(|v| v as f64).to_vec(), params) + } - // sample.abs() * 2.0 - 1.0 + pub fn sample_3d(&self, position: Vec3, params: &NoiseFunctionParams) -> f64 { + self.sample(position.to_array().map(|v| v as f64).to_vec(), params) } } From 6e199b70c35be95392b8a911eeaa19c25b9b7d4b Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:17:05 +0100 Subject: [PATCH 40/68] Drastically improve performance by duplicating code Martin would be sad --- src/server/terrain/util/generator.rs | 46 +++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index fe1e31f4..3049fed7 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -173,14 +173,18 @@ impl Generator { let mut weight_sum = 0.0; for _ in 0..params.octaves { - let pos: Vec = position.clone().into_iter().map(|v| v * frequency).collect(); + let pos: Vec = position + .clone() + .into_iter() + .map(|v| v * frequency) + .collect(); let new_sample = match pos.len() { 1 => self.perlin.get([pos[0]]), 2 => self.perlin.get([pos[0], pos[1]]), 3 => self.perlin.get([pos[0], pos[1], pos[2]]), 4 => self.perlin.get([pos[0], pos[1], pos[2], pos[3]]), - _ => panic!("Incorrect dimension for noise sample, must be either 2, 3 or 4") + _ => panic!("Incorrect dimension for noise sample, must be either 2, 3 or 4"), }; frequency *= params.lacuranity; @@ -193,11 +197,45 @@ impl Generator { } pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { - self.sample(position.to_array().map(|v| v as f64).to_vec(), params) + let mut sample = 0.0; + let mut frequency = params.frequency; + let mut weight = 1.0; + let mut weight_sum = 0.0; + + for _ in 0..params.octaves { + let new_sample = self + .perlin + .get([position.x as f64 * frequency, position.y as f64 * frequency]); + + frequency *= params.lacuranity; + sample += new_sample * weight; + weight_sum += weight; + weight *= params.persistence; + } + + sample / weight_sum } pub fn sample_3d(&self, position: Vec3, params: &NoiseFunctionParams) -> f64 { - self.sample(position.to_array().map(|v| v as f64).to_vec(), params) + let mut sample = 0.0; + let mut frequency = params.frequency; + let mut weight = 1.0; + let mut weight_sum = 0.0; + + for _ in 0..params.octaves { + let new_sample = self.perlin.get([ + position.x as f64 * frequency, + position.y as f64 * frequency, + position.z as f64 * frequency, + ]); + + frequency *= params.lacuranity; + sample += new_sample * weight; + weight_sum += weight; + weight *= params.persistence; + } + + sample / weight_sum } } From df5f40ca420691be1118c029bd64e01afe040775 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:17:37 +0100 Subject: [PATCH 41/68] Remove unused code --- src/server/terrain/util/generator.rs | 30 ---------------------------- 1 file changed, 30 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 3049fed7..79f075b5 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -166,36 +166,6 @@ impl Generator { max } - fn sample(&self, position: Vec, params: &NoiseFunctionParams) -> f64 { - let mut sample = 0.0; - let mut frequency = params.frequency; - let mut weight = 1.0; - let mut weight_sum = 0.0; - - for _ in 0..params.octaves { - let pos: Vec = position - .clone() - .into_iter() - .map(|v| v * frequency) - .collect(); - - let new_sample = match pos.len() { - 1 => self.perlin.get([pos[0]]), - 2 => self.perlin.get([pos[0], pos[1]]), - 3 => self.perlin.get([pos[0], pos[1], pos[2]]), - 4 => self.perlin.get([pos[0], pos[1], pos[2], pos[3]]), - _ => panic!("Incorrect dimension for noise sample, must be either 2, 3 or 4"), - }; - - frequency *= params.lacuranity; - sample += new_sample * weight; - weight_sum += weight; - weight *= params.persistence; - } - - sample / weight_sum - } - pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { let mut sample = 0.0; let mut frequency = params.frequency; From 93545c441df5fe5942d6d70dc51b2dc2cfbdc944 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:23:32 +0100 Subject: [PATCH 42/68] Update generator --- src/server/terrain/util/generator.rs | 31 +++++++--------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 79f075b5..49639254 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -45,32 +45,16 @@ impl Generator { } fn generate_block(&self, position: Vec3) -> BlockId { - let default_params = &self.params.height_params; - let terrain_height = self.determine_terrain_height(position); + let terrain_density = self.determine_terrain_density(position); if (position.y as f64) < terrain_height { return BlockId::Stone; } - // let terrain_height = self.sample_2d( - // Vec2 { - // x: position.x, - // y: position.z, - // }, - // default_params, - // ); - - // if (position.y as f64) < terrain_height + 20.0 { - // let max_slope = self.calculate_max_slope(position, default_params); - // if max_slope > 4.0 { - // return BlockId::Stone; - // } else if max_slope > 1.0 { - // return BlockId::Dirt; - // } else { - // return BlockId::Grass; - // } - // } + if terrain_density > 0.0 { + return BlockId::Stone; + } BlockId::Air } @@ -89,6 +73,10 @@ impl Generator { self.spline_lerp(noise_value) } + fn determine_terrain_density(&self, position: Vec3) -> f64 { + self.sample_3d(position, &self.params.density_params) + } + pub fn normalized_spline_terrain_sample(&self, position: Vec2) -> f64 { let noise_value = self.sample_2d(position, &self.params.height_params); @@ -101,9 +89,6 @@ impl Generator { } fn spline_lerp(&self, x: f64) -> f64 { - // x is the noise function value - // y is the mapped terrain height - let x: f32 = x as f32; assert!(self.params.splines.len() >= 2); From 91534814a268e4ad28d4c34fc5f42a1cef0f04b4 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:29:51 +0100 Subject: [PATCH 43/68] Refactor chunk generation --- src/server/terrain/util/generator.rs | 52 +++++++++++++++++----------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 49639254..904dbbe9 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -2,24 +2,8 @@ use terrain_resources::{Generator, NoiseFunctionParams, TerrainGeneratorParams}; use crate::prelude::*; -impl Generator { - pub fn new(seed: u32) -> Generator { - Self::new_with_params(seed, TerrainGeneratorParams::default()) - } - - pub fn new_with_params(seed: u32, params: TerrainGeneratorParams) -> Generator { - Generator { - seed, - perlin: Perlin::new(seed), - params, - } - } - - pub fn generate_chunk(&self, chunk: &mut Chunk) { - if chunk.position.y < 0.0 { - return; - } - +macro_rules! for_each_chunk_coordinate { + ($chunk:expr, $body:expr) => { for x in 0..CHUNK_SIZE + 2 { for y in 0..CHUNK_SIZE + 2 { for z in 0..CHUNK_SIZE + 2 { @@ -34,14 +18,40 @@ impl Generator { continue; } - let chunk_origin = chunk.position * CHUNK_SIZE as f32; + let chunk_origin = $chunk.position * CHUNK_SIZE as f32; let local_position = Vec3::new(x as f32, y as f32, z as f32); let block_position = chunk_origin + local_position; - let block = self.generate_block(block_position); - chunk.set_unpadded(x, y, z, block); + + $body(x, y, z, block_position); } } } + }; +} + + +impl Generator { + pub fn new(seed: u32) -> Generator { + Self::new_with_params(seed, TerrainGeneratorParams::default()) + } + + pub fn new_with_params(seed: u32, params: TerrainGeneratorParams) -> Generator { + Generator { + seed, + perlin: Perlin::new(seed), + params, + } + } + + pub fn generate_chunk(&self, chunk: &mut Chunk) { + if chunk.position.y < 0.0 { + return; + } + + for_each_chunk_coordinate!(chunk, |x, y, z, block_position| { + let block = self.generate_block(block_position); + chunk.set_unpadded(x, y, z, block); + }); } fn generate_block(&self, position: Vec3) -> BlockId { From 0deb8aa250e7b84b8a2a2ea45948e63d2cdc2d0b Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:43:48 +0100 Subject: [PATCH 44/68] Add grass layer --- src/server/terrain/util/generator.rs | 26 ++++++++++++++++++++++---- src/shared/terrain.rs | 12 ++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 904dbbe9..2b897f5b 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -10,10 +10,10 @@ macro_rules! for_each_chunk_coordinate { #[cfg(feature = "skip_chunk_padding")] if x == 0 || x == CHUNK_SIZE + 1 - || y == 0 - || y == CHUNK_SIZE + 1 - || z == 0 - || z == CHUNK_SIZE + 1 + || y == 0 + || y == CHUNK_SIZE + 1 + || z == 0 + || z == CHUNK_SIZE + 1 { continue; } @@ -52,6 +52,24 @@ impl Generator { let block = self.generate_block(block_position); chunk.set_unpadded(x, y, z, block); }); + + for_each_chunk_coordinate!(chunk, |x, y, z, _| { + let block = chunk.get_unpadded(x, y, z); + + if block == BlockId::Stone { + + let x = x as usize; + let y = y as usize; + let z = z as usize; + + if Chunk::valid_unpadded(x,y + 1,z) { + let top_block = chunk.get_unpadded(x, y + 1, z); + if top_block == BlockId::Air { + chunk.set_unpadded(x, y, z, BlockId::Grass); + } + } + } + }); } fn generate_block(&self, position: Vec3) -> BlockId { diff --git a/src/shared/terrain.rs b/src/shared/terrain.rs index 4e41fef5..e7134ffd 100644 --- a/src/shared/terrain.rs +++ b/src/shared/terrain.rs @@ -24,6 +24,18 @@ impl Chunk { } } + pub fn valid_padded(x: usize, y: usize, z: usize) -> bool { + (x >= 1 && x < CHUNK_SIZE) && + (y >= 1 && y < CHUNK_SIZE) && + (z >= 1 && z < CHUNK_SIZE) + } + + pub fn valid_unpadded(x: usize, y: usize, z: usize) -> bool { + x < PADDED_CHUNK_SIZE && + y < PADDED_CHUNK_SIZE && + z < PADDED_CHUNK_SIZE + } + pub fn get(&self, x: usize, y: usize, z: usize) -> BlockId { self.get_unpadded(x + 1, y + 1, z + 1) } From ea68b1d12183df46c4cf573ffad93b2ac6a25024 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:47:45 +0100 Subject: [PATCH 45/68] Refactor code --- src/server/terrain/util/generator.rs | 52 +++------------------------- src/shared/terrain.rs | 8 ++--- 2 files changed, 7 insertions(+), 53 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 2b897f5b..1550162b 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -10,10 +10,10 @@ macro_rules! for_each_chunk_coordinate { #[cfg(feature = "skip_chunk_padding")] if x == 0 || x == CHUNK_SIZE + 1 - || y == 0 - || y == CHUNK_SIZE + 1 - || z == 0 - || z == CHUNK_SIZE + 1 + || y == 0 + || y == CHUNK_SIZE + 1 + || z == 0 + || z == CHUNK_SIZE + 1 { continue; } @@ -29,7 +29,6 @@ macro_rules! for_each_chunk_coordinate { }; } - impl Generator { pub fn new(seed: u32) -> Generator { Self::new_with_params(seed, TerrainGeneratorParams::default()) @@ -57,12 +56,7 @@ impl Generator { let block = chunk.get_unpadded(x, y, z); if block == BlockId::Stone { - - let x = x as usize; - let y = y as usize; - let z = z as usize; - - if Chunk::valid_unpadded(x,y + 1,z) { + if Chunk::valid_unpadded(x, y + 1, z) { let top_block = chunk.get_unpadded(x, y + 1, z); if top_block == BlockId::Air { chunk.set_unpadded(x, y, z, BlockId::Grass); @@ -143,42 +137,6 @@ impl Generator { ((point0.y * (point1.x - x) + point1.y * (x - point0.x)) / (point1.x - point0.x)) as f64 } - fn get_sample_positions(&self, position: Vec3, epsilon: f32) -> [Vec2; 5] { - let mut positions = [Vec2::ZERO; 5]; - - let Vec3 { x, y: _, z: y } = position; - - positions[0] = Vec2 { x, y }; - positions[1] = Vec2 { x: x + epsilon, y }; - positions[2] = Vec2 { x: x - epsilon, y }; - positions[3] = Vec2 { x, y: y + epsilon }; - positions[4] = Vec2 { x, y: y - epsilon }; - - positions - } - - fn get_terrain_samples(&self, position: Vec3, params: &NoiseFunctionParams) -> [f64; 5] { - let sample_positions = self.get_sample_positions(position, 0.001); - - sample_positions.map(|sample_position| self.sample_2d(sample_position, params).abs()) - } - - fn calculate_max_slope(&self, position: Vec3, params: &NoiseFunctionParams) -> f64 { - let samples = self.get_terrain_samples(position, params); - - let mut max = 0.0; - - let main_sample = samples[0]; - - for sample in samples.iter().skip(1) { - if main_sample - sample > max { - max = main_sample - sample; - } - } - - max - } - pub fn sample_2d(&self, position: Vec2, params: &NoiseFunctionParams) -> f64 { let mut sample = 0.0; let mut frequency = params.frequency; diff --git a/src/shared/terrain.rs b/src/shared/terrain.rs index e7134ffd..5f532c56 100644 --- a/src/shared/terrain.rs +++ b/src/shared/terrain.rs @@ -25,15 +25,11 @@ impl Chunk { } pub fn valid_padded(x: usize, y: usize, z: usize) -> bool { - (x >= 1 && x < CHUNK_SIZE) && - (y >= 1 && y < CHUNK_SIZE) && - (z >= 1 && z < CHUNK_SIZE) + (1..CHUNK_SIZE).contains(&x) && (1..CHUNK_SIZE).contains(&y) && (1..CHUNK_SIZE).contains(&z) } pub fn valid_unpadded(x: usize, y: usize, z: usize) -> bool { - x < PADDED_CHUNK_SIZE && - y < PADDED_CHUNK_SIZE && - z < PADDED_CHUNK_SIZE + x < PADDED_CHUNK_SIZE && y < PADDED_CHUNK_SIZE && z < PADDED_CHUNK_SIZE } pub fn get(&self, x: usize, y: usize, z: usize) -> BlockId { From 45f87c437461a0fe822238206b9676f8bc779bbf Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 22:47:59 +0100 Subject: [PATCH 46/68] Fix linter --- src/server/terrain/util/generator.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 1550162b..782a19fe 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -55,12 +55,10 @@ impl Generator { for_each_chunk_coordinate!(chunk, |x, y, z, _| { let block = chunk.get_unpadded(x, y, z); - if block == BlockId::Stone { - if Chunk::valid_unpadded(x, y + 1, z) { - let top_block = chunk.get_unpadded(x, y + 1, z); - if top_block == BlockId::Air { - chunk.set_unpadded(x, y, z, BlockId::Grass); - } + if block == BlockId::Stone && Chunk::valid_unpadded(x, y + 1, z) { + let top_block = chunk.get_unpadded(x, y + 1, z); + if top_block == BlockId::Air { + chunk.set_unpadded(x, y, z, BlockId::Grass); } } }); From d33eb7e0b9a4520afe908103eb98ae0a981b2386 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:11:41 +0100 Subject: [PATCH 47/68] Uopdate generatror grass placement --- src/server/terrain/util/generator.rs | 65 +++++++++++++++++++++------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 782a19fe..bde287e3 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -10,19 +10,19 @@ macro_rules! for_each_chunk_coordinate { #[cfg(feature = "skip_chunk_padding")] if x == 0 || x == CHUNK_SIZE + 1 - || y == 0 - || y == CHUNK_SIZE + 1 - || z == 0 - || z == CHUNK_SIZE + 1 + || y == 0 + || y == CHUNK_SIZE + 1 + || z == 0 + || z == CHUNK_SIZE + 1 { continue; } let chunk_origin = $chunk.position * CHUNK_SIZE as f32; let local_position = Vec3::new(x as f32, y as f32, z as f32); - let block_position = chunk_origin + local_position; + let world_position = chunk_origin + local_position; - $body(x, y, z, block_position); + $body(x, y, z, world_position); } } } @@ -47,23 +47,58 @@ impl Generator { return; } - for_each_chunk_coordinate!(chunk, |x, y, z, block_position| { - let block = self.generate_block(block_position); + for_each_chunk_coordinate!(chunk, |x, y, z, world_position| { + let block = self.generate_block(world_position); chunk.set_unpadded(x, y, z, block); }); for_each_chunk_coordinate!(chunk, |x, y, z, _| { - let block = chunk.get_unpadded(x, y, z); + let pos = Vec3 { + x: x as f32, + y: y as f32, + z: z as f32, + }; - if block == BlockId::Stone && Chunk::valid_unpadded(x, y + 1, z) { - let top_block = chunk.get_unpadded(x, y + 1, z); - if top_block == BlockId::Air { - chunk.set_unpadded(x, y, z, BlockId::Grass); - } - } + let block = self.decorate_block(chunk, pos); + chunk.set_unpadded(x, y, z, block); }); } + fn decorate_block(&self, chunk: &Chunk, position: Vec3) -> BlockId { + let x = position.x as usize; + let y = position.y as usize; + let z = position.z as usize; + + let block = chunk.get_unpadded(x,y,z); + if block == BlockId::Air { + return block; + } + + + let mut depth_below_nearest_air = 0; + let depth_check = 5; + + for delta_height in 0..depth_check { + if !Chunk::valid_unpadded(x, y + delta_height, z) { + break + } + + let block = chunk.get_unpadded(x,y + delta_height,z); + + if block == BlockId::Air { + break + } + + depth_below_nearest_air += 1; + } + + match depth_below_nearest_air { + 0_i32..=1_i32 => BlockId::Grass, + 2..5 => BlockId::Dirt, + _ => BlockId::Stone + } + } + fn generate_block(&self, position: Vec3) -> BlockId { let terrain_height = self.determine_terrain_height(position); let terrain_density = self.determine_terrain_density(position); From 55f34a73b50c76430f2ff4b2359068817859cb1a Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:25:11 +0100 Subject: [PATCH 48/68] Impl density falloff --- src/server/terrain/util/generator.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index bde287e3..d039a84c 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -129,7 +129,10 @@ impl Generator { } fn determine_terrain_density(&self, position: Vec3) -> f64 { - self.sample_3d(position, &self.params.density_params) + let density = self.sample_3d(position, &self.params.density_params); + let density_falloff = (position.y as f64) / 200.0; + + density - density_falloff } pub fn normalized_spline_terrain_sample(&self, position: Vec2) -> f64 { From 7905866d31e312e3b7f7ad976777a00e9a32319c Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:25:25 +0100 Subject: [PATCH 49/68] Fix linter --- src/server/terrain/util/generator.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index d039a84c..2abdc698 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -10,10 +10,10 @@ macro_rules! for_each_chunk_coordinate { #[cfg(feature = "skip_chunk_padding")] if x == 0 || x == CHUNK_SIZE + 1 - || y == 0 - || y == CHUNK_SIZE + 1 - || z == 0 - || z == CHUNK_SIZE + 1 + || y == 0 + || y == CHUNK_SIZE + 1 + || z == 0 + || z == CHUNK_SIZE + 1 { continue; } @@ -69,24 +69,23 @@ impl Generator { let y = position.y as usize; let z = position.z as usize; - let block = chunk.get_unpadded(x,y,z); - if block == BlockId::Air { - return block; + let block = chunk.get_unpadded(x, y, z); + if block == BlockId::Air { + return block; } - let mut depth_below_nearest_air = 0; let depth_check = 5; for delta_height in 0..depth_check { if !Chunk::valid_unpadded(x, y + delta_height, z) { - break + break; } - let block = chunk.get_unpadded(x,y + delta_height,z); + let block = chunk.get_unpadded(x, y + delta_height, z); if block == BlockId::Air { - break + break; } depth_below_nearest_air += 1; @@ -95,7 +94,7 @@ impl Generator { match depth_below_nearest_air { 0_i32..=1_i32 => BlockId::Grass, 2..5 => BlockId::Dirt, - _ => BlockId::Stone + _ => BlockId::Stone, } } From c492a0de554592cad715584f8496cd61a7ec6304 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:32:45 +0100 Subject: [PATCH 50/68] Refactor heihgt params --- src/server/terrain/resources.rs | 38 ++++++++++++++++------------ src/server/terrain/util/generator.rs | 20 +++++++-------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 34e533f1..53bbab7d 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -28,6 +28,11 @@ pub struct Generator { pub params: TerrainGeneratorParams, } +pub struct HeightParams { + pub noise: NoiseFunctionParams, + pub splines: Vec, +} + #[derive(Debug)] pub struct NoiseFunctionParams { pub octaves: i32, @@ -45,8 +50,7 @@ impl Default for Generator { } pub struct TerrainGeneratorParams { - pub splines: Vec, - pub height_params: NoiseFunctionParams, + pub height_params: HeightParams, pub height_adjust_params: NoiseFunctionParams, pub density_params: NoiseFunctionParams, } @@ -54,20 +58,22 @@ pub struct TerrainGeneratorParams { impl Default for TerrainGeneratorParams { fn default() -> Self { Self { - splines: vec![ - Vec2::new(-1.0, -20.0), - Vec2::new(-0.5, 0.0), - Vec2::new(0.0, 20.0), - Vec2::new(0.5, 40.0), - Vec2::new(1.0, 60.0), - ], - height_params: NoiseFunctionParams { - octaves: 4, - height: 0.0, - lacuranity: 2.0, - frequency: 1.0 / 120.0, - amplitude: 30.0, - persistence: 0.5, + height_params: HeightParams { + splines: vec![ + Vec2::new(-1.0, -20.0), + Vec2::new(-0.5, 0.0), + Vec2::new(0.0, 20.0), + Vec2::new(0.5, 40.0), + Vec2::new(1.0, 60.0), + ], + noise: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 120.0, + amplitude: 30.0, + persistence: 0.5, + } }, height_adjust_params: NoiseFunctionParams { octaves: 4, diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 2abdc698..7a31a1ab 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -120,7 +120,7 @@ impl Generator { x: position.x, y: position.z, }, - &self.params.height_params, + &self.params.height_params.noise, ) .abs(); @@ -135,10 +135,10 @@ impl Generator { } pub fn normalized_spline_terrain_sample(&self, position: Vec2) -> f64 { - let noise_value = self.sample_2d(position, &self.params.height_params); + let noise_value = self.sample_2d(position, &self.params.height_params.noise); - let min_height = self.params.splines[0].y as f64; - let max_height = self.params.splines[self.params.splines.len() - 1].y as f64; + let min_height = self.params.height_params.splines[0].y as f64; + let max_height = self.params.height_params.splines[self.params.height_params.splines.len() - 1].y as f64; let splined_value = self.spline_lerp(noise_value); @@ -148,17 +148,17 @@ impl Generator { fn spline_lerp(&self, x: f64) -> f64 { let x: f32 = x as f32; - assert!(self.params.splines.len() >= 2); + assert!(self.params.height_params.splines.len() >= 2); - let min_x = self.params.splines[0].x; - let max_x = self.params.splines[self.params.splines.len() - 1].x; + let min_x = self.params.height_params.splines[0].x; + let max_x = self.params.height_params.splines[self.params.height_params.splines.len() - 1].x; assert!(min_x == -1.0); assert!(max_x == 1.0); - for i in 0..self.params.splines.len() - 1 { - let current = self.params.splines[i]; - let next = self.params.splines[i + 1]; + for i in 0..self.params.height_params.splines.len() - 1 { + let current = self.params.height_params.splines[i]; + let next = self.params.height_params.splines[i + 1]; if x >= current.x && x <= next.x { return self.lerp(current, x, next); From 36b0aeaa290cf0077181279a101adff263d0e79b Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:35:20 +0100 Subject: [PATCH 51/68] Refactor density params --- src/server/terrain/resources.rs | 28 ++++++++++++++++++---------- src/server/terrain/util/generator.rs | 4 ++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 53bbab7d..b26cf96c 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -33,9 +33,14 @@ pub struct HeightParams { pub splines: Vec, } +pub struct DensityParams { + pub noise: NoiseFunctionParams, + pub squash_factor: f64 +} + #[derive(Debug)] pub struct NoiseFunctionParams { - pub octaves: i32, + pub octaves: u32, pub height: f64, pub lacuranity: f64, pub frequency: f64, @@ -52,7 +57,7 @@ impl Default for Generator { pub struct TerrainGeneratorParams { pub height_params: HeightParams, pub height_adjust_params: NoiseFunctionParams, - pub density_params: NoiseFunctionParams, + pub density_params: DensityParams , } impl Default for TerrainGeneratorParams { @@ -83,14 +88,17 @@ impl Default for TerrainGeneratorParams { amplitude: 30.0, persistence: 0.5, }, - density_params: NoiseFunctionParams { - octaves: 4, - height: 0.0, - lacuranity: 2.0, - frequency: 1.0 / 60.0, - amplitude: 10.0, - persistence: 0.5, - }, + density_params: DensityParams { + squash_factor: 1.0 / 200.0, + noise: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 60.0, + amplitude: 10.0, + persistence: 0.5, + }, + } } } } diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 7a31a1ab..f5b8efa9 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -128,8 +128,8 @@ impl Generator { } fn determine_terrain_density(&self, position: Vec3) -> f64 { - let density = self.sample_3d(position, &self.params.density_params); - let density_falloff = (position.y as f64) / 200.0; + let density = self.sample_3d(position, &self.params.density_params.noise); + let density_falloff = (position.y as f64) * &self.params.density_params.squash_factor; density - density_falloff } From 6d8498f7f6687608740069797d6a94da1400bae7 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:36:34 +0100 Subject: [PATCH 52/68] Refactor rename params to be less verbose --- src/server/terrain/resources.rs | 12 ++++++------ src/server/terrain/util/generator.rs | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index b26cf96c..0f00558f 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -55,15 +55,15 @@ impl Default for Generator { } pub struct TerrainGeneratorParams { - pub height_params: HeightParams, - pub height_adjust_params: NoiseFunctionParams, - pub density_params: DensityParams , + pub height: HeightParams, + pub height_adjust: NoiseFunctionParams, + pub density: DensityParams , } impl Default for TerrainGeneratorParams { fn default() -> Self { Self { - height_params: HeightParams { + height: HeightParams { splines: vec![ Vec2::new(-1.0, -20.0), Vec2::new(-0.5, 0.0), @@ -80,7 +80,7 @@ impl Default for TerrainGeneratorParams { persistence: 0.5, } }, - height_adjust_params: NoiseFunctionParams { + height_adjust: NoiseFunctionParams { octaves: 4, height: 0.0, lacuranity: 2.0, @@ -88,7 +88,7 @@ impl Default for TerrainGeneratorParams { amplitude: 30.0, persistence: 0.5, }, - density_params: DensityParams { + density: DensityParams { squash_factor: 1.0 / 200.0, noise: NoiseFunctionParams { octaves: 4, diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index f5b8efa9..03728b00 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -120,7 +120,7 @@ impl Generator { x: position.x, y: position.z, }, - &self.params.height_params.noise, + &self.params.height.noise, ) .abs(); @@ -128,17 +128,17 @@ impl Generator { } fn determine_terrain_density(&self, position: Vec3) -> f64 { - let density = self.sample_3d(position, &self.params.density_params.noise); - let density_falloff = (position.y as f64) * &self.params.density_params.squash_factor; + let density = self.sample_3d(position, &self.params.density.noise); + let density_falloff = (position.y as f64) * &self.params.density.squash_factor; density - density_falloff } pub fn normalized_spline_terrain_sample(&self, position: Vec2) -> f64 { - let noise_value = self.sample_2d(position, &self.params.height_params.noise); + let noise_value = self.sample_2d(position, &self.params.height.noise); - let min_height = self.params.height_params.splines[0].y as f64; - let max_height = self.params.height_params.splines[self.params.height_params.splines.len() - 1].y as f64; + let min_height = self.params.height.splines[0].y as f64; + let max_height = self.params.height.splines[self.params.height.splines.len() - 1].y as f64; let splined_value = self.spline_lerp(noise_value); @@ -148,17 +148,17 @@ impl Generator { fn spline_lerp(&self, x: f64) -> f64 { let x: f32 = x as f32; - assert!(self.params.height_params.splines.len() >= 2); + assert!(self.params.height.splines.len() >= 2); - let min_x = self.params.height_params.splines[0].x; - let max_x = self.params.height_params.splines[self.params.height_params.splines.len() - 1].x; + let min_x = self.params.height.splines[0].x; + let max_x = self.params.height.splines[self.params.height.splines.len() - 1].x; assert!(min_x == -1.0); assert!(max_x == 1.0); - for i in 0..self.params.height_params.splines.len() - 1 { - let current = self.params.height_params.splines[i]; - let next = self.params.height_params.splines[i + 1]; + for i in 0..self.params.height.splines.len() - 1 { + let current = self.params.height.splines[i]; + let next = self.params.height.splines[i + 1]; if x >= current.x && x <= next.x { return self.lerp(current, x, next); From 13946e2af26be602db1d6f83284acbc639bd195f Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:40:19 +0100 Subject: [PATCH 53/68] Refacotr height adjust, fix server visualizer system --- src/server/terrain/resources.rs | 44 +++++++++++++++++++-------------- src/server/terrain/systems.rs | 19 +++++++------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 0f00558f..033e056e 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -38,6 +38,10 @@ pub struct DensityParams { pub squash_factor: f64 } +pub struct HeightAdjustParams { + pub noise: NoiseFunctionParams, +} + #[derive(Debug)] pub struct NoiseFunctionParams { pub octaves: u32, @@ -56,8 +60,8 @@ impl Default for Generator { pub struct TerrainGeneratorParams { pub height: HeightParams, - pub height_adjust: NoiseFunctionParams, - pub density: DensityParams , + pub height_adjust: HeightAdjustParams, + pub density: DensityParams, } impl Default for TerrainGeneratorParams { @@ -80,25 +84,27 @@ impl Default for TerrainGeneratorParams { persistence: 0.5, } }, - height_adjust: NoiseFunctionParams { - octaves: 4, - height: 0.0, - lacuranity: 2.0, - frequency: 1.0 / 120.0, - amplitude: 30.0, - persistence: 0.5, + height_adjust: HeightAdjustParams { + noise: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 120.0, + amplitude: 30.0, + persistence: 0.5, + } }, density: DensityParams { - squash_factor: 1.0 / 200.0, - noise: NoiseFunctionParams { - octaves: 4, - height: 0.0, - lacuranity: 2.0, - frequency: 1.0 / 60.0, - amplitude: 10.0, - persistence: 0.5, - }, - } + squash_factor: 1.0 / 200.0, + noise: NoiseFunctionParams { + octaves: 4, + height: 0.0, + lacuranity: 2.0, + frequency: 1.0 / 60.0, + amplitude: 10.0, + persistence: 0.5, + }, + } } } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index be18873a..9994a1c5 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -40,7 +40,6 @@ mod visualizer { use rsmc::{Chunk, ChunkManager, NetworkingMessage, CHUNK_SIZE}; use super::{ - prelude::*, terrain_events, terrain_resources::{self, NoiseFunctionParams, TextureType}, }; @@ -80,7 +79,7 @@ mod visualizer { TextureType::HeightAdjust => { let sample_position = Vec2::new(x as f32, z as f32); let value = generator - .sample_2d(sample_position, &generator.params.height_adjust_params); + .sample_2d(sample_position, &generator.params.height_adjust.noise); let value = map_range(value, -1.0, 1.0, 0.0, 255.0); data[index] = value as u8; @@ -88,7 +87,7 @@ mod visualizer { TextureType::Density => { // TODO: change to sample3D let pos = Vec2::new(x as f32, z as f32); - let value = generator.sample_2d(pos, &generator.params.density_params); + let value = generator.sample_2d(pos, &generator.params.density.noise); let value = map_range(value, -1.0, 1.0, 0.0, 255.0); data[index] = value as u8; @@ -258,14 +257,14 @@ mod visualizer { let mut changed = false; - let length = generator.params.splines.len(); + let length = generator.params.height.splines.len(); for index in 0..length { if index != 0 && index != length - 1 { // Ensure range from 0 to 1 by locking the first and last splines - add_slider!(ui, changed, &mut generator.params.splines[index].x, -1.0..=1.0, format!("x{}", index)); + add_slider!(ui, changed, &mut generator.params.height.splines[index].x, -1.0..=1.0, format!("x{}", index)); } - add_slider!(ui, changed, &mut generator.params.splines[index].y, -40.0..=80.0, format!("y{}", index)); + add_slider!(ui, changed, &mut generator.params.height.splines[index].y, -40.0..=80.0, format!("y{}", index)); } if changed { @@ -278,7 +277,7 @@ mod visualizer { egui_plot::Plot::new("splines") .show(ui, |plot_ui| { - let plot_points: Vec = generator.params.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let plot_points: Vec = generator.params.height.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); let line_chart = Line::new(PlotPoints::Owned(plot_points)); plot_ui.line(line_chart); }); @@ -301,9 +300,9 @@ mod visualizer { }; let params: &mut NoiseFunctionParams = match texture_type { - TextureType::Height => &mut generator.params.height_params, - TextureType::HeightAdjust => &mut generator.params.height_adjust_params, - TextureType::Density => &mut generator.params.density_params + TextureType::Height => &mut generator.params.height.noise, + TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, + TextureType::Density => &mut generator.params.density.noise }; egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { From 77466749ebbf4d87a6ed680f701d0a1531285c69 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sun, 9 Feb 2025 23:49:11 +0100 Subject: [PATCH 54/68] Fix linter --- src/server/terrain/resources.rs | 8 ++++---- src/server/terrain/util/generator.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 033e056e..7f1e45e8 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -35,7 +35,7 @@ pub struct HeightParams { pub struct DensityParams { pub noise: NoiseFunctionParams, - pub squash_factor: f64 + pub squash_factor: f64, } pub struct HeightAdjustParams { @@ -82,7 +82,7 @@ impl Default for TerrainGeneratorParams { frequency: 1.0 / 120.0, amplitude: 30.0, persistence: 0.5, - } + }, }, height_adjust: HeightAdjustParams { noise: NoiseFunctionParams { @@ -92,7 +92,7 @@ impl Default for TerrainGeneratorParams { frequency: 1.0 / 120.0, amplitude: 30.0, persistence: 0.5, - } + }, }, density: DensityParams { squash_factor: 1.0 / 200.0, @@ -104,7 +104,7 @@ impl Default for TerrainGeneratorParams { amplitude: 10.0, persistence: 0.5, }, - } + }, } } } diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 03728b00..0b745063 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -129,7 +129,7 @@ impl Generator { fn determine_terrain_density(&self, position: Vec3) -> f64 { let density = self.sample_3d(position, &self.params.density.noise); - let density_falloff = (position.y as f64) * &self.params.density.squash_factor; + let density_falloff = position.y as f64 * self.params.density.squash_factor; density - density_falloff } From b4c1703f17617c24ab3daefcb52ec4eb549504e1 Mon Sep 17 00:00:00 2001 From: Daniel Bengl <53896675+CuddlyBunion341@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:09:06 +0100 Subject: [PATCH 55/68] Update README.md --- README.md | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index fd1c6d50..05f66f87 100644 --- a/README.md +++ b/README.md @@ -60,20 +60,6 @@ nix-shell --run "cargo run --bin server" nix-shell --run "cargo run --bin client" ``` -## Implementation notes - -### Terrain generation - -1. Step (terrain shaping) -- 3D fractal perlin noise with low frequency, squash factor to determine terrain density at xyz. -- 2D fractal perlin noise with higher frequency serving as a base layer. Use splines for ridged height map. -- Subtract 3D fractal perlin noise to get cave generation. -- Use strongly flattened 3D noise perlin or worley noise for different rock layers. - -- Place stone (base) - -2. Step (Decorating) -- Place grass on blocks where there is air above -- Use white noise to place some ores, grow them randomly? - +## Notes +Checkout the [Wiki](https://github.com/CuddlyBunion341/rsmc/wiki) for additional project information. From 20333faa82247a47ae296cea54ffc480e9bdc4d4 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Mon, 10 Feb 2025 22:25:40 +0100 Subject: [PATCH 56/68] Refactor sliders, add cave params --- src/server/terrain/resources.rs | 21 ++++++++++ src/server/terrain/systems.rs | 72 +++++++++++++++------------------ 2 files changed, 54 insertions(+), 39 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 7f1e45e8..8313e4e1 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -38,6 +38,12 @@ pub struct DensityParams { pub squash_factor: f64, } +pub struct CaveParams { + pub noise: NoiseFunctionParams, + pub base_value: f64, + pub threshold: f64 +} + pub struct HeightAdjustParams { pub noise: NoiseFunctionParams, } @@ -62,6 +68,7 @@ pub struct TerrainGeneratorParams { pub height: HeightParams, pub height_adjust: HeightAdjustParams, pub density: DensityParams, + pub cave: CaveParams, } impl Default for TerrainGeneratorParams { @@ -105,6 +112,18 @@ impl Default for TerrainGeneratorParams { persistence: 0.5, }, }, + cave: CaveParams { + noise: NoiseFunctionParams { + octaves: 2, + height: 0.0, + lacuranity: 0.3, + frequency: 1.0 / 50.0, + amplitude: 30.0, + persistence: 0.5, + }, + base_value: 0.5, + threshold: 0.1, + } } } } @@ -123,6 +142,7 @@ mod visualizer { Height, HeightAdjust, Density, + Cave } #[derive(Resource)] @@ -137,6 +157,7 @@ mod visualizer { noise_textures.insert(TextureType::Height, NoiseTexture::default()); noise_textures.insert(TextureType::HeightAdjust, NoiseTexture::default()); noise_textures.insert(TextureType::Density, NoiseTexture::default()); + noise_textures.insert(TextureType::Cave, NoiseTexture::default()); NoiseTextureList { noise_textures } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 9994a1c5..4bc75bf3 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -90,6 +90,13 @@ mod visualizer { let value = generator.sample_2d(pos, &generator.params.density.noise); let value = map_range(value, -1.0, 1.0, 0.0, 255.0); + data[index] = value as u8; + } + TextureType::Cave => { + let pos = Vec3::new(x as f32, z as f32, 0.0); + let value = generator.sample_3d(pos, &generator.params.cave.noise); + let value = map_range(value, -1.0, 1.0, 0.0, 255.0); + data[index] = value as u8; } }; @@ -127,7 +134,7 @@ mod visualizer { generator.generate_chunk(&mut chunk); chunk }) - .collect(); + .collect(); new_chunks.into_iter().for_each(|chunk| { chunk_manager.insert_chunk(chunk); @@ -174,37 +181,43 @@ mod visualizer { .expect("Noise texture not loaded, please initialize the resource properly."); entry.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), + "terrain-texture", + image_data, + TextureOptions::default(), )); entry.size = Vec2::new(width as f32, height as f32); } } + #[rustfmt::skip] pub fn prepare_visualizer_texture_system( mut event_writer: EventWriter, ) { - event_writer.send(terrain_events::RegenerateHeightMapEvent( - TextureType::Height, - )); - event_writer.send(terrain_events::RegenerateHeightMapEvent( - TextureType::HeightAdjust, - )); - event_writer.send(terrain_events::RegenerateHeightMapEvent( - TextureType::Density, - )); + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::HeightAdjust)); + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Density)); + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Cave)); } macro_rules! add_slider { ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ $changed = $changed || $ui - .add(egui::widgets::Slider::new($value, $range).text($text)) - .changed(); - }}; + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; + } + + macro_rules! add_noise_sliders { + ($ui:expr, $changed:expr, $params:expr) => { + add_slider!($ui, $changed, &mut $params.octaves, 1..=8, "octaves"); + add_slider!($ui, $changed, &mut $params.lacuranity, 0.001..=4.0, "lacuranity"); + add_slider!($ui, $changed, &mut $params.frequency, 10.0..=800.0, "frequency"); + add_slider!($ui, $changed, &mut $params.persistence, 0.001..=1.0, "persistence"); + }; } + #[rustfmt::skip] fn add_sliders_for_noise_params( ui: &mut egui::Ui, changed: &mut bool, @@ -214,28 +227,7 @@ mod visualizer { let mut loc_changed = false; - add_slider!(ui, loc_changed, &mut params.octaves, 1..=8, "octaves"); - add_slider!( - ui, - loc_changed, - &mut params.lacuranity, - 0.001..=4.0, - "lacuranity" - ); - add_slider!( - ui, - loc_changed, - &mut params.frequency, - 10.0..=800.0, - "frequency" - ); - add_slider!( - ui, - loc_changed, - &mut params.persistence, - 0.001..=1.0, - "persistence" - ); + add_noise_sliders!(ui, loc_changed, params); params.frequency = 1.0 / params.frequency; @@ -297,12 +289,14 @@ mod visualizer { TextureType::Height => "Base Height", TextureType::HeightAdjust => "Height adjustment", TextureType::Density => "Density", + TextureType::Cave => "Cave", }; let params: &mut NoiseFunctionParams = match texture_type { TextureType::Height => &mut generator.params.height.noise, TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, - TextureType::Density => &mut generator.params.density.noise + TextureType::Density => &mut generator.params.density.noise, + TextureType::Cave => &mut generator.params.cave.noise, }; egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { From 972dac9c7e12f00eb2f856935b37cd1f6283f088 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Mon, 10 Feb 2025 22:26:45 +0100 Subject: [PATCH 57/68] Refactor --- src/server/terrain/systems.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 4bc75bf3..22c13b88 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -224,14 +224,8 @@ mod visualizer { params: &mut NoiseFunctionParams, ) { params.frequency = 1.0 / params.frequency; - - let mut loc_changed = false; - - add_noise_sliders!(ui, loc_changed, params); - + add_noise_sliders!(ui, *changed, params); params.frequency = 1.0 / params.frequency; - - *changed = *changed || loc_changed; } #[rustfmt::skip] From 6a96741a6ff83af0d4ae1c660b9742720f62fc2b Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Mon, 10 Feb 2025 22:38:25 +0100 Subject: [PATCH 58/68] Break stuff --- src/server/terrain/systems.rs | 46 ++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 22c13b88..95a5c365 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -207,7 +207,7 @@ mod visualizer { .changed(); }}; } - + macro_rules! add_noise_sliders { ($ui:expr, $changed:expr, $params:expr) => { add_slider!($ui, $changed, &mut $params.octaves, 1..=8, "octaves"); @@ -217,17 +217,25 @@ mod visualizer { }; } - #[rustfmt::skip] - fn add_sliders_for_noise_params( - ui: &mut egui::Ui, - changed: &mut bool, - params: &mut NoiseFunctionParams, - ) { - params.frequency = 1.0 / params.frequency; - add_noise_sliders!(ui, *changed, params); - params.frequency = 1.0 / params.frequency; + macro_rules! add_sliders_for_noise_params { + ($ui:expr, $changed:expr, $params:expr) => { + $params.frequency = 1.0 / $params.frequency; + add_noise_sliders!($ui, *$changed, $params); + $params.frequency = 1.0 / $params.frequency; + }; } + // #[rustfmt::skip] + // fn add_sliders_for_noise_params( + // ui: &mut egui::Ui, + // changed: &mut bool, + // params: &mut NoiseFunctionParams, + // ) { + // params.frequency = 1.0 / params.frequency; + // add_noise_sliders!(ui, *changed, params); + // params.frequency = 1.0 / params.frequency; + // } + #[rustfmt::skip] pub fn render_visualizer_system( mut contexts: EguiContexts, @@ -286,26 +294,26 @@ mod visualizer { TextureType::Cave => "Cave", }; - let params: &mut NoiseFunctionParams = match texture_type { - TextureType::Height => &mut generator.params.height.noise, - TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, - TextureType::Density => &mut generator.params.density.noise, - TextureType::Cave => &mut generator.params.cave.noise, - }; egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { ui.label(window_name); let mut changed = false; - add_sliders_for_noise_params(ui, &mut changed, params); + let params: &mut NoiseFunctionParams = match texture_type { + TextureType::Height => &mut generator.params.height.noise, + TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, + TextureType::Density => &mut generator.params.density.noise, + TextureType::Cave => &mut generator.params.cave.noise, + }; + + add_slider!(ui, changed, &mut generator.params.cave.base_value, -1.0..=1.0, "base value"); + add_sliders_for_noise_params!(ui, &mut changed, params); if changed { event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); }; - ui.label(format!("{:?}", params)); - ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( texture_handle.id(), texture_handle.size_vec2(), From db610b08e11c04b88a52c0599a8e982473f22d09 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 21:48:31 +0100 Subject: [PATCH 59/68] Update terrain generator --- src/server/terrain/resources.rs | 8 +++---- src/server/terrain/systems.rs | 31 +++++++++++++++++++++------- src/server/terrain/util/generator.rs | 18 ++++++++++++---- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 8313e4e1..b2d9fba1 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -102,7 +102,7 @@ impl Default for TerrainGeneratorParams { }, }, density: DensityParams { - squash_factor: 1.0 / 200.0, + squash_factor: 1.0 / 300.0, noise: NoiseFunctionParams { octaves: 4, height: 0.0, @@ -116,12 +116,12 @@ impl Default for TerrainGeneratorParams { noise: NoiseFunctionParams { octaves: 2, height: 0.0, - lacuranity: 0.3, - frequency: 1.0 / 50.0, + lacuranity: 0.03, + frequency: 1.0 / 20.0, amplitude: 30.0, persistence: 0.5, }, - base_value: 0.5, + base_value: 0.0, threshold: 0.1, } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 95a5c365..cfa55e23 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -32,6 +32,7 @@ mod visualizer { bevy_egui::EguiContexts, egui::{self, Color32, ColorImage, ImageData, TextureOptions}, }; + use bevy_renet::netcode::generate_random_bytes; use egui_plot::{Line, PlotPoint, PlotPoints}; use rayon::iter::IntoParallelIterator; @@ -85,16 +86,24 @@ mod visualizer { data[index] = value as u8; } TextureType::Density => { - // TODO: change to sample3D - let pos = Vec2::new(x as f32, z as f32); - let value = generator.sample_2d(pos, &generator.params.density.noise); + let pos = Vec3::new(x as f32, z as f32, 0.0); + let value = generator.sample_3d(pos, &generator.params.density.noise); let value = map_range(value, -1.0, 1.0, 0.0, 255.0); data[index] = value as u8; } TextureType::Cave => { let pos = Vec3::new(x as f32, z as f32, 0.0); - let value = generator.sample_3d(pos, &generator.params.cave.noise); + let mut value = generator.sample_3d(pos, &generator.params.cave.noise); + + let base = generator.params.cave.base_value; + let upper_bound = base + generator.params.cave.threshold; + let lower_bound = base - generator.params.cave.threshold; + + if lower_bound <= value && value >= upper_bound { + value = -1.0; + } + let value = map_range(value, -1.0, 1.0, 0.0, 255.0); data[index] = value as u8; @@ -303,11 +312,19 @@ mod visualizer { let params: &mut NoiseFunctionParams = match texture_type { TextureType::Height => &mut generator.params.height.noise, TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, - TextureType::Density => &mut generator.params.density.noise, - TextureType::Cave => &mut generator.params.cave.noise, + TextureType::Density => { + generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; + add_slider!(ui, changed, &mut generator.params.density.squash_factor, 10.0..=500.0, "squash factor"); + generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; + &mut generator.params.density.noise + } + TextureType::Cave => { + add_slider!(ui, changed, &mut generator.params.cave.base_value, -1.0..=1.0, "base value"); + add_slider!(ui, changed, &mut generator.params.cave.threshold, -1.0..=1.0, "treshold"); + &mut generator.params.cave.noise + }, }; - add_slider!(ui, changed, &mut generator.params.cave.base_value, -1.0..=1.0, "base value"); add_sliders_for_noise_params!(ui, &mut changed, params); if changed { diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 0b745063..10e07754 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -99,20 +99,30 @@ impl Generator { } fn generate_block(&self, position: Vec3) -> BlockId { - let terrain_height = self.determine_terrain_height(position); - let terrain_density = self.determine_terrain_density(position); + if self.is_inside_cave(position) { + return BlockId::Air; + } - if (position.y as f64) < terrain_height { + if (position.y as f64) < self.determine_terrain_height(position) { return BlockId::Stone; } - if terrain_density > 0.0 { + if self.determine_terrain_density(position) > 0.0 { return BlockId::Stone; } BlockId::Air } + fn is_inside_cave(&self, position: Vec3) -> bool { + let density = self.sample_3d(position, &self.params.cave.noise); + + let upper_bound = self.params.cave.base_value - self.params.cave.threshold; + let lower_bound = self.params.cave.base_value + self.params.cave.threshold; + + return lower_bound <= density && density >= upper_bound + } + fn determine_terrain_height(&self, position: Vec3) -> f64 { let noise_value = self .sample_2d( From 490777dc250d1c460b52d2cc7b72487c0ad6e866 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 21:48:47 +0100 Subject: [PATCH 60/68] Fix linter --- src/server/terrain/resources.rs | 6 ++--- src/server/terrain/systems.rs | 38 ++++++++++++++++++++-------- src/server/terrain/util/generator.rs | 2 +- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index b2d9fba1..de99e90d 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -41,7 +41,7 @@ pub struct DensityParams { pub struct CaveParams { pub noise: NoiseFunctionParams, pub base_value: f64, - pub threshold: f64 + pub threshold: f64, } pub struct HeightAdjustParams { @@ -123,7 +123,7 @@ impl Default for TerrainGeneratorParams { }, base_value: 0.0, threshold: 0.1, - } + }, } } } @@ -142,7 +142,7 @@ mod visualizer { Height, HeightAdjust, Density, - Cave + Cave, } #[derive(Resource)] diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index cfa55e23..98910221 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -143,7 +143,7 @@ mod visualizer { generator.generate_chunk(&mut chunk); chunk }) - .collect(); + .collect(); new_chunks.into_iter().for_each(|chunk| { chunk_manager.insert_chunk(chunk); @@ -190,9 +190,9 @@ mod visualizer { .expect("Noise texture not loaded, please initialize the resource properly."); entry.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), + "terrain-texture", + image_data, + TextureOptions::default(), )); entry.size = Vec2::new(width as f32, height as f32); } @@ -212,17 +212,35 @@ mod visualizer { ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ $changed = $changed || $ui - .add(egui::widgets::Slider::new($value, $range).text($text)) - .changed(); - }}; + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; } macro_rules! add_noise_sliders { ($ui:expr, $changed:expr, $params:expr) => { add_slider!($ui, $changed, &mut $params.octaves, 1..=8, "octaves"); - add_slider!($ui, $changed, &mut $params.lacuranity, 0.001..=4.0, "lacuranity"); - add_slider!($ui, $changed, &mut $params.frequency, 10.0..=800.0, "frequency"); - add_slider!($ui, $changed, &mut $params.persistence, 0.001..=1.0, "persistence"); + add_slider!( + $ui, + $changed, + &mut $params.lacuranity, + 0.001..=4.0, + "lacuranity" + ); + add_slider!( + $ui, + $changed, + &mut $params.frequency, + 10.0..=800.0, + "frequency" + ); + add_slider!( + $ui, + $changed, + &mut $params.persistence, + 0.001..=1.0, + "persistence" + ); }; } diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 10e07754..cc820a99 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -120,7 +120,7 @@ impl Generator { let upper_bound = self.params.cave.base_value - self.params.cave.threshold; let lower_bound = self.params.cave.base_value + self.params.cave.threshold; - return lower_bound <= density && density >= upper_bound + lower_bound <= density && density >= upper_bound } fn determine_terrain_height(&self, position: Vec3) -> f64 { From 4fe90fdbb97214a81a86b509f1936cb8f028c95e Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 22:00:55 +0100 Subject: [PATCH 61/68] Refactor UI --- src/server/terrain/systems.rs | 176 +++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 77 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 98910221..5e15bb51 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -143,7 +143,7 @@ mod visualizer { generator.generate_chunk(&mut chunk); chunk }) - .collect(); + .collect(); new_chunks.into_iter().for_each(|chunk| { chunk_manager.insert_chunk(chunk); @@ -190,9 +190,9 @@ mod visualizer { .expect("Noise texture not loaded, please initialize the resource properly."); entry.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), + "terrain-texture", + image_data, + TextureOptions::default(), )); entry.size = Vec2::new(width as f32, height as f32); } @@ -212,9 +212,9 @@ mod visualizer { ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ $changed = $changed || $ui - .add(egui::widgets::Slider::new($value, $range).text($text)) - .changed(); - }}; + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; } macro_rules! add_noise_sliders { @@ -271,92 +271,114 @@ mod visualizer { mut event_writer: EventWriter, mut world_regenerate_event_writer: EventWriter, ) { - egui::Window::new("Splines").show(contexts.ctx_mut(), |ui| { - if ui.button("Organize windows").clicked() { - ui.ctx().memory_mut(|mem| mem.reset_areas()); - } + let noise_textures = &noise_texture_list.noise_textures; - let mut changed = false; + egui::Window::new("Terrain Generator").show(contexts.ctx_mut(), |ui| { - let length = generator.params.height.splines.len(); + ui.horizontal(|ui| { - for index in 0..length { - if index != 0 && index != length - 1 { - // Ensure range from 0 to 1 by locking the first and last splines - add_slider!(ui, changed, &mut generator.params.height.splines[index].x, -1.0..=1.0, format!("x{}", index)); - } - add_slider!(ui, changed, &mut generator.params.height.splines[index].y, -40.0..=80.0, format!("y{}", index)); - } + ui.group(|ui| { + ui.vertical(|ui| { + ui.label("Splines"); - if changed { - event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); - } + if ui.button("Organize windows").clicked() { + ui.ctx().memory_mut(|mem| mem.reset_areas()); + } - if ui.button("Regenerate world").clicked() { - world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); - } + let mut changed = false; - egui_plot::Plot::new("splines") - .show(ui, |plot_ui| { - let plot_points: Vec = generator.params.height.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); - let line_chart = Line::new(PlotPoints::Owned(plot_points)); - plot_ui.line(line_chart); - }); - }); + let length = generator.params.height.splines.len(); - let noise_textures = &noise_texture_list.noise_textures; + for index in 0..length { + if index != 0 && index != length - 1 { + // Ensure range from 0 to 1 by locking the first and last splines + add_slider!(ui, changed, &mut generator.params.height.splines[index].x, -1.0..=1.0, format!("x{}", index)); + } + add_slider!(ui, changed, &mut generator.params.height.splines[index].y, -40.0..=80.0, format!("y{}", index)); + } - for (texture_type, noise_texture) in noise_textures { - let texture_handle = noise_texture.texture.as_ref(); + if changed { + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); + } - match texture_handle { - None => { - warn!("Noise texture handle could not be borrowed") - }, - Some(texture_handle) => { - let window_name = match texture_type { - TextureType::Height => "Base Height", - TextureType::HeightAdjust => "Height adjustment", - TextureType::Density => "Density", - TextureType::Cave => "Cave", - }; + if ui.button("Regenerate world").clicked() { + world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); + } + egui_plot::Plot::new("splines") + .show(ui, |plot_ui| { + let plot_points: Vec = generator.params.height.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let line_chart = Line::new(PlotPoints::Owned(plot_points)); + plot_ui.line(line_chart); + }); + }) - egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { - ui.label(window_name); - let mut changed = false; - let params: &mut NoiseFunctionParams = match texture_type { - TextureType::Height => &mut generator.params.height.noise, - TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, - TextureType::Density => { - generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; - add_slider!(ui, changed, &mut generator.params.density.squash_factor, 10.0..=500.0, "squash factor"); - generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; - &mut generator.params.density.noise - } - TextureType::Cave => { - add_slider!(ui, changed, &mut generator.params.cave.base_value, -1.0..=1.0, "base value"); - add_slider!(ui, changed, &mut generator.params.cave.threshold, -1.0..=1.0, "treshold"); - &mut generator.params.cave.noise - }, - }; + }); - add_sliders_for_noise_params!(ui, &mut changed, params); + for (texture_type, noise_texture) in noise_textures { + let texture_handle = noise_texture.texture.as_ref(); + + match texture_handle { + None => { + warn!("Noise texture handle could not be borrowed") + }, + Some(texture_handle) => { + let window_name = match texture_type { + TextureType::Height => "Base Height", + TextureType::HeightAdjust => "Height adjustment", + TextureType::Density => "Density", + TextureType::Cave => "Cave", + }; + + ui.group(|ui| { + ui.vertical(|ui| { + ui.label(window_name); + + let mut changed = false; + + let params: &mut NoiseFunctionParams = match texture_type { + TextureType::Height => &mut generator.params.height.noise, + TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, + TextureType::Density => { + generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; + add_slider!(ui, changed, &mut generator.params.density.squash_factor, 10.0..=500.0, "squash factor"); + generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; + &mut generator.params.density.noise + } + TextureType::Cave => { + add_slider!(ui, changed, &mut generator.params.cave.base_value, -1.0..=1.0, "base value"); + add_slider!(ui, changed, &mut generator.params.cave.threshold, -1.0..=1.0, "treshold"); + &mut generator.params.cave.noise + }, + }; + + add_sliders_for_noise_params!(ui, &mut changed, params); + + if changed { + event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); + }; + + ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( + texture_handle.id(), + texture_handle.size_vec2(), + ))); + + }) + }); + + // egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { + // ui.label(window_name); + // + // }); + } + } - if changed { - event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); - }; - - ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( - texture_handle.id(), - texture_handle.size_vec2(), - ))); - }); } - } - }; + }) + + }); } } From 0bec27caa1c2a2d80e731e3dfc2367c4ac2e2376 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 22:06:42 +0100 Subject: [PATCH 62/68] Make UI nice again! (using grid) --- src/server/terrain/systems.rs | 179 +++++++++++++++++----------------- 1 file changed, 90 insertions(+), 89 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 5e15bb51..4ee16275 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -277,106 +277,107 @@ mod visualizer { ui.horizontal(|ui| { - ui.group(|ui| { - ui.vertical(|ui| { - ui.label("Splines"); + egui::Grid::new("Terrain gen").show(ui, |ui| { + ui.group(|ui| { + ui.vertical(|ui| { + ui.label("Splines"); - if ui.button("Organize windows").clicked() { - ui.ctx().memory_mut(|mem| mem.reset_areas()); - } - - let mut changed = false; - - let length = generator.params.height.splines.len(); - - for index in 0..length { - if index != 0 && index != length - 1 { - // Ensure range from 0 to 1 by locking the first and last splines - add_slider!(ui, changed, &mut generator.params.height.splines[index].x, -1.0..=1.0, format!("x{}", index)); + if ui.button("Organize windows").clicked() { + ui.ctx().memory_mut(|mem| mem.reset_areas()); } - add_slider!(ui, changed, &mut generator.params.height.splines[index].y, -40.0..=80.0, format!("y{}", index)); - } - if changed { - event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); - } - - if ui.button("Regenerate world").clicked() { - world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); - } + let mut changed = false; - egui_plot::Plot::new("splines") - .show(ui, |plot_ui| { - let plot_points: Vec = generator.params.height.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); - let line_chart = Line::new(PlotPoints::Owned(plot_points)); - plot_ui.line(line_chart); - }); - }) + let length = generator.params.height.splines.len(); + for index in 0..length { + if index != 0 && index != length - 1 { + // Ensure range from 0 to 1 by locking the first and last splines + add_slider!(ui, changed, &mut generator.params.height.splines[index].x, -1.0..=1.0, format!("x{}", index)); + } + add_slider!(ui, changed, &mut generator.params.height.splines[index].y, -40.0..=80.0, format!("y{}", index)); + } + if changed { + event_writer.send(terrain_events::RegenerateHeightMapEvent(TextureType::Height)); + } - }); + if ui.button("Regenerate world").clicked() { + world_regenerate_event_writer.send(terrain_events::WorldRegenerateEvent); + } - for (texture_type, noise_texture) in noise_textures { - let texture_handle = noise_texture.texture.as_ref(); - - match texture_handle { - None => { - warn!("Noise texture handle could not be borrowed") - }, - Some(texture_handle) => { - let window_name = match texture_type { - TextureType::Height => "Base Height", - TextureType::HeightAdjust => "Height adjustment", - TextureType::Density => "Density", - TextureType::Cave => "Cave", - }; - - ui.group(|ui| { - ui.vertical(|ui| { - ui.label(window_name); - - let mut changed = false; - - let params: &mut NoiseFunctionParams = match texture_type { - TextureType::Height => &mut generator.params.height.noise, - TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, - TextureType::Density => { - generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; - add_slider!(ui, changed, &mut generator.params.density.squash_factor, 10.0..=500.0, "squash factor"); - generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; - &mut generator.params.density.noise - } - TextureType::Cave => { - add_slider!(ui, changed, &mut generator.params.cave.base_value, -1.0..=1.0, "base value"); - add_slider!(ui, changed, &mut generator.params.cave.threshold, -1.0..=1.0, "treshold"); - &mut generator.params.cave.noise - }, - }; - - add_sliders_for_noise_params!(ui, &mut changed, params); - - if changed { - event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); - }; - - ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( - texture_handle.id(), - texture_handle.size_vec2(), - ))); - - }) - }); - - // egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { - // ui.label(window_name); - // - // }); + egui_plot::Plot::new("splines") + .show(ui, |plot_ui| { + let plot_points: Vec = generator.params.height.splines.iter().map(|spline| PlotPoint {x: spline.x as f64, y: spline.y as f64}).collect(); + let line_chart = Line::new(PlotPoints::Owned(plot_points)); + plot_ui.line(line_chart); + }); + }) + + + + }); + for (texture_type, noise_texture) in noise_textures { + let texture_handle = noise_texture.texture.as_ref(); + + match texture_handle { + None => { + warn!("Noise texture handle could not be borrowed") + }, + Some(texture_handle) => { + let window_name = match texture_type { + TextureType::Height => "Base Height", + TextureType::HeightAdjust => "Height adjustment", + TextureType::Density => "Density", + TextureType::Cave => "Cave", + }; + + ui.group(|ui| { + ui.vertical(|ui| { + ui.label(window_name); + + let mut changed = false; + + let params: &mut NoiseFunctionParams = match texture_type { + TextureType::Height => &mut generator.params.height.noise, + TextureType::HeightAdjust => &mut generator.params.height_adjust.noise, + TextureType::Density => { + generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; + add_slider!(ui, changed, &mut generator.params.density.squash_factor, 10.0..=500.0, "squash factor"); + generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; + &mut generator.params.density.noise + } + TextureType::Cave => { + add_slider!(ui, changed, &mut generator.params.cave.base_value, -1.0..=1.0, "base value"); + add_slider!(ui, changed, &mut generator.params.cave.threshold, -1.0..=1.0, "treshold"); + &mut generator.params.cave.noise + }, + }; + + add_sliders_for_noise_params!(ui, &mut changed, params); + + if changed { + event_writer.send(terrain_events::RegenerateHeightMapEvent(texture_type.clone())); + }; + + ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( + texture_handle.id(), + texture_handle.size_vec2(), + ))); + + }) + }); + + // egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { + // ui.label(window_name); + // + // }); + } } - } - } + } + }); }) }); From 32c90b4ddda3c097e10274f2db5ae2eacb6e8f11 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 22:06:50 +0100 Subject: [PATCH 63/68] Fix linter --- src/server/terrain/systems.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 4ee16275..8cf78047 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -143,7 +143,7 @@ mod visualizer { generator.generate_chunk(&mut chunk); chunk }) - .collect(); + .collect(); new_chunks.into_iter().for_each(|chunk| { chunk_manager.insert_chunk(chunk); @@ -190,9 +190,9 @@ mod visualizer { .expect("Noise texture not loaded, please initialize the resource properly."); entry.texture = Some(contexts.ctx_mut().load_texture( - "terrain-texture", - image_data, - TextureOptions::default(), + "terrain-texture", + image_data, + TextureOptions::default(), )); entry.size = Vec2::new(width as f32, height as f32); } @@ -212,9 +212,9 @@ mod visualizer { ($ui:expr, $changed:expr, $value:expr, $range:expr, $text:expr) => {{ $changed = $changed || $ui - .add(egui::widgets::Slider::new($value, $range).text($text)) - .changed(); - }}; + .add(egui::widgets::Slider::new($value, $range).text($text)) + .changed(); + }}; } macro_rules! add_noise_sliders { From 9dfbc088efd927549f4ad14c2be8fc737fa5fafd Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 22:43:57 +0100 Subject: [PATCH 64/68] Update terrain params --- src/server/terrain/resources.rs | 18 +++++++++--------- src/server/terrain/systems.rs | 21 +-------------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index de99e90d..9367bf1c 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -76,17 +76,17 @@ impl Default for TerrainGeneratorParams { Self { height: HeightParams { splines: vec![ - Vec2::new(-1.0, -20.0), - Vec2::new(-0.5, 0.0), - Vec2::new(0.0, 20.0), - Vec2::new(0.5, 40.0), - Vec2::new(1.0, 60.0), + Vec2::new(-1.0, -16.0), + Vec2::new(0.0, 0.0), + Vec2::new(0.0, 0.0), + Vec2::new(0.05, 2.0), + Vec2::new(1.0, 15.0), ], noise: NoiseFunctionParams { octaves: 4, height: 0.0, lacuranity: 2.0, - frequency: 1.0 / 120.0, + frequency: 1.0 / 300.0, amplitude: 30.0, persistence: 0.5, }, @@ -102,7 +102,7 @@ impl Default for TerrainGeneratorParams { }, }, density: DensityParams { - squash_factor: 1.0 / 300.0, + squash_factor: 1.0 / 100.0, noise: NoiseFunctionParams { octaves: 4, height: 0.0, @@ -119,10 +119,10 @@ impl Default for TerrainGeneratorParams { lacuranity: 0.03, frequency: 1.0 / 20.0, amplitude: 30.0, - persistence: 0.5, + persistence: 0.59, }, base_value: 0.0, - threshold: 0.1, + threshold: 0.25, }, } } diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 8cf78047..1782f959 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -4,7 +4,7 @@ pub fn setup_world_system( mut chunk_manager: ResMut, generator: Res, ) { - let render_distance = Vec3::new(6.0, 2.0, 6.0); + let render_distance = Vec3::new(8.0, 3.0, 8.0); info!("Generating chunks"); @@ -32,7 +32,6 @@ mod visualizer { bevy_egui::EguiContexts, egui::{self, Color32, ColorImage, ImageData, TextureOptions}, }; - use bevy_renet::netcode::generate_random_bytes; use egui_plot::{Line, PlotPoint, PlotPoints}; use rayon::iter::IntoParallelIterator; @@ -252,17 +251,6 @@ mod visualizer { }; } - // #[rustfmt::skip] - // fn add_sliders_for_noise_params( - // ui: &mut egui::Ui, - // changed: &mut bool, - // params: &mut NoiseFunctionParams, - // ) { - // params.frequency = 1.0 / params.frequency; - // add_noise_sliders!(ui, *changed, params); - // params.frequency = 1.0 / params.frequency; - // } - #[rustfmt::skip] pub fn render_visualizer_system( mut contexts: EguiContexts, @@ -367,16 +355,9 @@ mod visualizer { }) }); - - // egui::Window::new(window_name).show(contexts.ctx_mut(), |ui| { - // ui.label(window_name); - // - // }); } } - } - }); }) From 0072b8d3c2fadfe256014b21a85adc7936d445ee Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 22:49:02 +0100 Subject: [PATCH 65/68] Update parametrers, refactor --- src/server/terrain/resources.rs | 8 +++++--- src/server/terrain/systems.rs | 5 +---- src/server/terrain/util/generator.rs | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 9367bf1c..8073a297 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -36,6 +36,7 @@ pub struct HeightParams { pub struct DensityParams { pub noise: NoiseFunctionParams, pub squash_factor: f64, + pub height_offset: f64, } pub struct CaveParams { @@ -76,11 +77,11 @@ impl Default for TerrainGeneratorParams { Self { height: HeightParams { splines: vec![ - Vec2::new(-1.0, -16.0), + Vec2::new(-1.0, 4.0), Vec2::new(0.0, 0.0), Vec2::new(0.0, 0.0), - Vec2::new(0.05, 2.0), - Vec2::new(1.0, 15.0), + Vec2::new(0.05, 20.0), + Vec2::new(1.0, 35.0), ], noise: NoiseFunctionParams { octaves: 4, @@ -103,6 +104,7 @@ impl Default for TerrainGeneratorParams { }, density: DensityParams { squash_factor: 1.0 / 100.0, + height_offset: -20.0, noise: NoiseFunctionParams { octaves: 4, height: 0.0, diff --git a/src/server/terrain/systems.rs b/src/server/terrain/systems.rs index 1782f959..f6af669d 100644 --- a/src/server/terrain/systems.rs +++ b/src/server/terrain/systems.rs @@ -270,10 +270,6 @@ mod visualizer { ui.vertical(|ui| { ui.label("Splines"); - if ui.button("Organize windows").clicked() { - ui.ctx().memory_mut(|mem| mem.reset_areas()); - } - let mut changed = false; let length = generator.params.height.splines.len(); @@ -332,6 +328,7 @@ mod visualizer { TextureType::Density => { generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; add_slider!(ui, changed, &mut generator.params.density.squash_factor, 10.0..=500.0, "squash factor"); + add_slider!(ui, changed, &mut generator.params.density.height_offset, -50.0..=50.0, "height offset"); generator.params.density.squash_factor = 1.0 / generator.params.density.squash_factor; &mut generator.params.density.noise } diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index cc820a99..b709d954 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -139,7 +139,7 @@ impl Generator { fn determine_terrain_density(&self, position: Vec3) -> f64 { let density = self.sample_3d(position, &self.params.density.noise); - let density_falloff = position.y as f64 * self.params.density.squash_factor; + let density_falloff = (position.y as f64 + self.params.density.height_offset)* self.params.density.squash_factor; density - density_falloff } From c454f6faf873fc8466311148ce04e580ff29be41 Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 22:49:08 +0100 Subject: [PATCH 66/68] Fix linter --- src/server/terrain/util/generator.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index b709d954..3cb66e0f 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -139,7 +139,8 @@ impl Generator { fn determine_terrain_density(&self, position: Vec3) -> f64 { let density = self.sample_3d(position, &self.params.density.noise); - let density_falloff = (position.y as f64 + self.params.density.height_offset)* self.params.density.squash_factor; + let density_falloff = (position.y as f64 + self.params.density.height_offset) + * self.params.density.squash_factor; density - density_falloff } From 8fe21e2f74545848ce7f47905d2e7fd014289bbe Mon Sep 17 00:00:00 2001 From: CuddlyBunion341 Date: Sat, 1 Mar 2025 22:51:10 +0100 Subject: [PATCH 67/68] Update gradd decoration --- src/server/terrain/util/generator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/terrain/util/generator.rs b/src/server/terrain/util/generator.rs index 3cb66e0f..c7156d0c 100644 --- a/src/server/terrain/util/generator.rs +++ b/src/server/terrain/util/generator.rs @@ -75,7 +75,7 @@ impl Generator { } let mut depth_below_nearest_air = 0; - let depth_check = 5; + let depth_check = 3; for delta_height in 0..depth_check { if !Chunk::valid_unpadded(x, y + delta_height, z) { @@ -93,7 +93,7 @@ impl Generator { match depth_below_nearest_air { 0_i32..=1_i32 => BlockId::Grass, - 2..5 => BlockId::Dirt, + 2..3 => BlockId::Dirt, _ => BlockId::Stone, } } From ffb3f8504e04d9021f0c6cf9f6e039db39e7d4a2 Mon Sep 17 00:00:00 2001 From: Daniel Bengl <53896675+CuddlyBunion341@users.noreply.github.com> Date: Sat, 1 Mar 2025 22:54:52 +0100 Subject: [PATCH 68/68] Apply suggestions from code review --- src/client/player/systems/controller.rs | 2 +- src/server/terrain/resources.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/player/systems/controller.rs b/src/client/player/systems/controller.rs index b7b1d610..e0a34bf4 100644 --- a/src/client/player/systems/controller.rs +++ b/src/client/player/systems/controller.rs @@ -1,7 +1,7 @@ use crate::prelude::*; #[cfg(not(feature = "lock_player"))] -const SPAWN_POINT: Vec3 = Vec3::new(0.0, 32.0, 0.0); +const SPAWN_POINT: Vec3 = Vec3::new(0.0, 64.0, 0.0); #[cfg(feature = "lock_player")] const SPAWN_POINT: Vec3 = Vec3::new(128.0, 96.0, -128.0); diff --git a/src/server/terrain/resources.rs b/src/server/terrain/resources.rs index 8073a297..0bd1ad9e 100644 --- a/src/server/terrain/resources.rs +++ b/src/server/terrain/resources.rs @@ -24,7 +24,7 @@ impl PastBlockUpdates { #[derive(Resource)] pub struct Generator { pub seed: u32, - pub perlin: Perlin, // TODO: reduce visibility of attributes on this struct decl + pub perlin: Perlin, pub params: TerrainGeneratorParams, }