make world generation configurable

This commit is contained in:
Zoey 2024-04-19 12:49:35 -07:00
parent c78303cf44
commit 38164a6cc5
No known key found for this signature in database
GPG key ID: 8611B896D1AAFAF2
4 changed files with 101 additions and 9 deletions

View file

@ -1,3 +1,5 @@
pub mod generation;
/// a classic level
#[derive(Debug, Clone)]
pub struct Level {

93
src/level/generation.rs Normal file
View file

@ -0,0 +1,93 @@
use rand::Rng;
use serde::{Deserialize, Serialize};
use super::Level;
/// enum for different kinds of level generation
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum LevelGeneration {
/// an empty level
Empty,
/// a level where every block up to the given height is randomized
FullRandom { height: usize },
/// a flat level with the given preset
Flat(FlatPreset),
}
/// enum for level presents
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "flat_type")]
pub enum FlatPreset {
/// the level is mostly stone, then dirt, then a layer of grass on the top
StoneAndGrass,
/// the level layers are custom as defined in server config
Custom { layers: Vec<FlatLayer> },
}
/// description of a flat world's layer
#[derive(Debug, Serialize, Deserialize)]
pub struct FlatLayer {
/// the block for the layer
pub block: u8,
/// the depth of the layer
pub depth: usize,
}
impl LevelGeneration {
/// generates the level
pub fn generate<R>(&self, level: &mut Level, rng: &mut R)
where
R: Rng,
{
match self {
Self::Empty => {}
Self::FullRandom { height } => {
let height = *height.min(&level.y_size);
for x in 0..level.x_size {
for y in 0..height {
for z in 0..level.z_size {
level.set_block(x, y, z, rng.gen_range(0..49));
}
}
}
}
Self::Flat(preset) => {
let custom_layers;
let layers_ref;
match preset {
FlatPreset::StoneAndGrass => {
custom_layers = vec![
FlatLayer {
block: 1,
depth: level.y_size / 2 - 4,
},
FlatLayer { block: 3, depth: 3 },
FlatLayer { block: 2, depth: 1 },
];
layers_ref = &custom_layers;
}
FlatPreset::Custom { layers } => {
layers_ref = layers;
}
}
let mut y = 0;
for layer in layers_ref {
for _ in 0..layer.depth {
for x in 0..level.x_size {
for z in 0..level.z_size {
level.set_block(x, y, z, layer.block);
}
}
y += 1;
if y >= level.y_size {
return;
}
}
}
}
}
}
}

View file

@ -3,8 +3,6 @@ mod network;
use std::sync::Arc;
// use parking_lot::RwLock;
use rand::Rng;
use tokio::{net::TcpListener, sync::RwLock};
use crate::{level::Level, player::Player};
@ -50,13 +48,7 @@ impl Server {
)
};
let mut level = Level::new(level_x, level_y, level_z);
for x in 0..level.x_size {
for y in 0..(level.y_size / 2) {
for z in 0..level.z_size {
level.set_block(x, y, z, rng.gen_range(0..50));
}
}
}
config.generation.generate(&mut level, &mut rng);
println!("done!");
Self::new_with_level(config, level).await

View file

@ -1,5 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::level::generation::LevelGeneration;
/// configuration for the server
#[derive(Debug, Serialize, Deserialize)]
pub struct ServerConfig {
@ -13,6 +15,8 @@ pub struct ServerConfig {
pub level_size: Option<ConfigCoordinates>,
/// the level's spawn point
pub spawn: Option<ConfigCoordinates>,
/// the method to generate the server's level with
pub generation: LevelGeneration,
}
impl Default for ServerConfig {
@ -23,6 +27,7 @@ impl Default for ServerConfig {
password: None,
level_size: None,
spawn: None,
generation: LevelGeneration::Empty,
}
}
}