veloren/world/src/lib.rs

179 lines
4.9 KiB
Rust
Raw Normal View History

2019-08-19 12:39:23 +00:00
#![deny(unsafe_code)]
2019-08-22 21:25:17 +00:00
#![feature(
const_generics,
euclidean_division,
bind_by_move_pattern_guards,
2019-08-24 22:57:55 +00:00
option_flattening,
label_break_value
2019-08-21 18:41:32 +00:00
)]
2019-06-11 18:39:25 +00:00
mod all;
2019-06-09 10:24:18 +00:00
mod block;
mod column;
2019-06-15 12:34:28 +00:00
pub mod config;
pub mod generator;
2019-06-18 21:22:31 +00:00
pub mod sim;
2019-06-15 12:34:28 +00:00
pub mod util;
2019-06-09 10:24:18 +00:00
// Reexports
pub use crate::config::CONFIG;
2019-06-15 10:36:26 +00:00
use crate::{
block::BlockGen,
2019-06-15 12:34:28 +00:00
column::{ColumnGen, ColumnSample},
2019-09-04 23:03:49 +00:00
util::Sampler,
2019-06-15 10:36:26 +00:00
};
2019-01-15 15:13:11 +00:00
use common::{
terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
common: Rework volume API See the doc comments in `common/src/vol.rs` for more information on the API itself. The changes include: * Consistent `Err`/`Error` naming. * Types are named `...Error`. * `enum` variants are named `...Err`. * Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation to an upcoming change where a “map” in the game related sense will be added. * Add volume iterators. There are two types of them: * _Position_ iterators obtained from the trait `IntoPosIterator` using the method `fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `Vec3<i32>`. * _Volume_ iterators obtained from the trait `IntoVolIterator` using the method `fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `(Vec3<i32>, &Self::Vox)`. Those traits will usually be implemented by references to volume types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some type which usually implements several volume traits, such as `Chunk`). * _Position_ iterators iterate over the positions valid for that volume. * _Volume_ iterators do the same but return not only the position but also the voxel at that position, in each iteration. * Introduce trait `RectSizedVol` for the use case which we have with `Chonk`: A `Chonk` is sized only in x and y direction. * Introduce traits `RasterableVol`, `RectRasterableVol` * `RasterableVol` represents a volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen because such a volume can be used with `VolGrid3d`. * `RectRasterableVol` represents a volume that is compile-time sized at least in x and y direction and has its lower bound at `(0, 0, z)`. There's no requirement on he lower bound or size in z direction. The name `RectRasterableVol` was chosen because such a volume can be used with `VolGrid2d`.
2019-09-03 22:23:29 +00:00
vol::{ReadVol, RectVolSize, Vox, WriteVol},
2019-01-15 15:13:11 +00:00
};
2019-08-02 14:37:26 +00:00
use rand::Rng;
2019-09-16 13:11:47 +00:00
use std::time::Duration;
use vek::*;
2019-01-15 15:13:11 +00:00
#[derive(Debug)]
pub enum Error {
Other(String),
}
pub struct World {
sim: sim::WorldSim,
}
2019-01-15 15:13:11 +00:00
impl World {
pub fn generate(seed: u32) -> Self {
Self {
sim: sim::WorldSim::generate(seed),
}
}
pub fn sim(&self) -> &sim::WorldSim {
&self.sim
}
2019-07-01 18:40:41 +00:00
pub fn tick(&self, _dt: Duration) {
// TODO
2019-01-15 15:13:11 +00:00
}
2019-06-15 12:34:28 +00:00
pub fn sample_columns(
&self,
) -> impl Sampler<Index = Vec2<i32>, Sample = Option<ColumnSample>> + '_ {
2019-08-24 22:57:55 +00:00
ColumnGen::new(&self.sim)
2019-06-15 12:34:28 +00:00
}
2019-07-04 23:14:55 +00:00
pub fn sample_blocks(&self) -> BlockGen {
2019-08-24 22:57:55 +00:00
BlockGen::new(self, ColumnGen::new(&self.sim))
2019-06-09 10:24:18 +00:00
}
2019-09-16 02:01:05 +00:00
pub fn generate_chunk(
&self,
chunk_pos: Vec2<i32>,
2019-09-16 13:11:47 +00:00
mut should_continue: impl FnMut() -> bool,
2019-09-16 02:05:36 +00:00
) -> Result<(TerrainChunk, ChunkSupplement), ()> {
2019-01-23 20:01:58 +00:00
let air = Block::empty();
let stone = Block::new(BlockKind::Dense, Rgb::new(200, 220, 255));
2019-08-16 14:58:14 +00:00
let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190));
2019-01-23 20:01:58 +00:00
common: Rework volume API See the doc comments in `common/src/vol.rs` for more information on the API itself. The changes include: * Consistent `Err`/`Error` naming. * Types are named `...Error`. * `enum` variants are named `...Err`. * Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation to an upcoming change where a “map” in the game related sense will be added. * Add volume iterators. There are two types of them: * _Position_ iterators obtained from the trait `IntoPosIterator` using the method `fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `Vec3<i32>`. * _Volume_ iterators obtained from the trait `IntoVolIterator` using the method `fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `(Vec3<i32>, &Self::Vox)`. Those traits will usually be implemented by references to volume types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some type which usually implements several volume traits, such as `Chunk`). * _Position_ iterators iterate over the positions valid for that volume. * _Volume_ iterators do the same but return not only the position but also the voxel at that position, in each iteration. * Introduce trait `RectSizedVol` for the use case which we have with `Chonk`: A `Chonk` is sized only in x and y direction. * Introduce traits `RasterableVol`, `RectRasterableVol` * `RasterableVol` represents a volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen because such a volume can be used with `VolGrid3d`. * `RectRasterableVol` represents a volume that is compile-time sized at least in x and y direction and has its lower bound at `(0, 0, z)`. There's no requirement on he lower bound or size in z direction. The name `RectRasterableVol` was chosen because such a volume can be used with `VolGrid2d`.
2019-09-03 22:23:29 +00:00
let chunk_size2d = TerrainChunkSize::RECT_SIZE;
2019-06-19 14:55:26 +00:00
let (base_z, sim_chunk) = match self
.sim
.get_interpolated(
chunk_pos.map2(chunk_size2d, |e, sz: u32| e * sz as i32 + sz as i32 / 2),
|chunk| chunk.get_base_z(),
)
.and_then(|base_z| self.sim.get(chunk_pos).map(|sim_chunk| (base_z, sim_chunk)))
{
2019-06-18 21:22:31 +00:00
Some((base_z, sim_chunk)) => (base_z as i32, sim_chunk),
2019-07-09 20:42:27 +00:00
None => {
2019-09-16 01:51:08 +00:00
return Ok((
2019-08-02 14:37:26 +00:00
TerrainChunk::new(
CONFIG.sea_level as i32,
water,
air,
TerrainChunkMeta::void(),
),
ChunkSupplement::default(),
2019-09-16 01:51:08 +00:00
))
2019-07-09 20:42:27 +00:00
}
};
2019-06-25 15:59:09 +00:00
let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome());
2019-06-15 12:34:28 +00:00
let mut sampler = self.sample_blocks();
common: Rework volume API See the doc comments in `common/src/vol.rs` for more information on the API itself. The changes include: * Consistent `Err`/`Error` naming. * Types are named `...Error`. * `enum` variants are named `...Err`. * Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation to an upcoming change where a “map” in the game related sense will be added. * Add volume iterators. There are two types of them: * _Position_ iterators obtained from the trait `IntoPosIterator` using the method `fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `Vec3<i32>`. * _Volume_ iterators obtained from the trait `IntoVolIterator` using the method `fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `(Vec3<i32>, &Self::Vox)`. Those traits will usually be implemented by references to volume types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some type which usually implements several volume traits, such as `Chunk`). * _Position_ iterators iterate over the positions valid for that volume. * _Volume_ iterators do the same but return not only the position but also the voxel at that position, in each iteration. * Introduce trait `RectSizedVol` for the use case which we have with `Chonk`: A `Chonk` is sized only in x and y direction. * Introduce traits `RasterableVol`, `RectRasterableVol` * `RasterableVol` represents a volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen because such a volume can be used with `VolGrid3d`. * `RectRasterableVol` represents a volume that is compile-time sized at least in x and y direction and has its lower bound at `(0, 0, z)`. There's no requirement on he lower bound or size in z direction. The name `RectRasterableVol` was chosen because such a volume can be used with `VolGrid2d`.
2019-09-03 22:23:29 +00:00
let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
2019-08-02 14:37:26 +00:00
let mut chunk = TerrainChunk::new(base_z, stone, air, meta);
common: Rework volume API See the doc comments in `common/src/vol.rs` for more information on the API itself. The changes include: * Consistent `Err`/`Error` naming. * Types are named `...Error`. * `enum` variants are named `...Err`. * Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation to an upcoming change where a “map” in the game related sense will be added. * Add volume iterators. There are two types of them: * _Position_ iterators obtained from the trait `IntoPosIterator` using the method `fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `Vec3<i32>`. * _Volume_ iterators obtained from the trait `IntoVolIterator` using the method `fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `(Vec3<i32>, &Self::Vox)`. Those traits will usually be implemented by references to volume types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some type which usually implements several volume traits, such as `Chunk`). * _Position_ iterators iterate over the positions valid for that volume. * _Volume_ iterators do the same but return not only the position but also the voxel at that position, in each iteration. * Introduce trait `RectSizedVol` for the use case which we have with `Chonk`: A `Chonk` is sized only in x and y direction. * Introduce traits `RasterableVol`, `RectRasterableVol` * `RasterableVol` represents a volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen because such a volume can be used with `VolGrid3d`. * `RectRasterableVol` represents a volume that is compile-time sized at least in x and y direction and has its lower bound at `(0, 0, z)`. There's no requirement on he lower bound or size in z direction. The name `RectRasterableVol` was chosen because such a volume can be used with `VolGrid2d`.
2019-09-03 22:23:29 +00:00
for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 {
for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 {
2019-09-16 13:11:47 +00:00
if should_continue() {
2019-09-16 02:05:36 +00:00
return Err(());
2019-09-16 02:01:05 +00:00
};
let wpos2d = Vec2::new(x, y)
common: Rework volume API See the doc comments in `common/src/vol.rs` for more information on the API itself. The changes include: * Consistent `Err`/`Error` naming. * Types are named `...Error`. * `enum` variants are named `...Err`. * Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation to an upcoming change where a “map” in the game related sense will be added. * Add volume iterators. There are two types of them: * _Position_ iterators obtained from the trait `IntoPosIterator` using the method `fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `Vec3<i32>`. * _Volume_ iterators obtained from the trait `IntoVolIterator` using the method `fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `(Vec3<i32>, &Self::Vox)`. Those traits will usually be implemented by references to volume types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some type which usually implements several volume traits, such as `Chunk`). * _Position_ iterators iterate over the positions valid for that volume. * _Volume_ iterators do the same but return not only the position but also the voxel at that position, in each iteration. * Introduce trait `RectSizedVol` for the use case which we have with `Chonk`: A `Chonk` is sized only in x and y direction. * Introduce traits `RasterableVol`, `RectRasterableVol` * `RasterableVol` represents a volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen because such a volume can be used with `VolGrid3d`. * `RectRasterableVol` represents a volume that is compile-time sized at least in x and y direction and has its lower bound at `(0, 0, z)`. There's no requirement on he lower bound or size in z direction. The name `RectRasterableVol` was chosen because such a volume can be used with `VolGrid2d`.
2019-09-03 22:23:29 +00:00
+ Vec2::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
let z_cache = match sampler.get_z_cache(wpos2d) {
Some(z_cache) => z_cache,
None => continue,
};
2019-07-04 23:14:55 +00:00
let (min_z, max_z) = z_cache.get_z_limits();
for z in base_z..min_z as i32 {
let _ = chunk.set(Vec3::new(x, y, z), stone);
}
for z in min_z as i32..max_z as i32 {
let lpos = Vec3::new(x, y, z);
2019-08-02 14:37:26 +00:00
let wpos = chunk_block_pos + lpos;
if let Some(block) = sampler.get_with_z_cache(wpos, Some(&z_cache)) {
2019-06-09 10:24:18 +00:00
let _ = chunk.set(lpos, block);
}
}
}
2019-01-23 20:01:58 +00:00
}
2019-08-02 14:37:26 +00:00
let gen_entity_pos = || {
common: Rework volume API See the doc comments in `common/src/vol.rs` for more information on the API itself. The changes include: * Consistent `Err`/`Error` naming. * Types are named `...Error`. * `enum` variants are named `...Err`. * Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation to an upcoming change where a “map” in the game related sense will be added. * Add volume iterators. There are two types of them: * _Position_ iterators obtained from the trait `IntoPosIterator` using the method `fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `Vec3<i32>`. * _Volume_ iterators obtained from the trait `IntoVolIterator` using the method `fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `(Vec3<i32>, &Self::Vox)`. Those traits will usually be implemented by references to volume types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some type which usually implements several volume traits, such as `Chunk`). * _Position_ iterators iterate over the positions valid for that volume. * _Volume_ iterators do the same but return not only the position but also the voxel at that position, in each iteration. * Introduce trait `RectSizedVol` for the use case which we have with `Chonk`: A `Chonk` is sized only in x and y direction. * Introduce traits `RasterableVol`, `RectRasterableVol` * `RasterableVol` represents a volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen because such a volume can be used with `VolGrid3d`. * `RectRasterableVol` represents a volume that is compile-time sized at least in x and y direction and has its lower bound at `(0, 0, z)`. There's no requirement on he lower bound or size in z direction. The name `RectRasterableVol` was chosen because such a volume can be used with `VolGrid2d`.
2019-09-03 22:23:29 +00:00
let lpos2d = TerrainChunkSize::RECT_SIZE
2019-08-02 14:37:26 +00:00
.map(|sz| rand::thread_rng().gen::<u32>().rem_euclid(sz));
let mut lpos = Vec3::new(lpos2d.x as i32, lpos2d.y as i32, 0);
while chunk.get(lpos).map(|vox| !vox.is_empty()).unwrap_or(false) {
lpos.z += 1;
}
(chunk_block_pos + lpos).map(|e| e as f32) + 0.5
};
const SPAWN_RATE: f32 = 0.1;
2019-08-04 09:27:08 +00:00
const BOSS_RATE: f32 = 0.03;
2019-08-02 14:37:26 +00:00
let supplement = ChunkSupplement {
2019-08-02 17:48:14 +00:00
npcs: if rand::thread_rng().gen::<f32>() < SPAWN_RATE && sim_chunk.chaos < 0.5 {
2019-08-02 14:37:26 +00:00
vec![NpcInfo {
pos: gen_entity_pos(),
boss: rand::thread_rng().gen::<f32>() < BOSS_RATE,
2019-08-02 14:37:26 +00:00
}]
} else {
Vec::new()
},
};
2019-09-16 01:51:08 +00:00
Ok((chunk, supplement))
2019-08-02 14:37:26 +00:00
}
}
pub struct NpcInfo {
pub pos: Vec3<f32>,
pub boss: bool,
2019-08-02 14:37:26 +00:00
}
pub struct ChunkSupplement {
pub npcs: Vec<NpcInfo>,
}
impl Default for ChunkSupplement {
fn default() -> Self {
Self { npcs: Vec::new() }
}
}