From 523db9f05451295940b15403dba160bb2cc52387 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 2 Jan 2019 19:22:01 +0000 Subject: [PATCH] Started work on adding terrain --- client/src/lib.rs | 6 +-- common/Cargo.toml | 1 + common/src/comp/mod.rs | 6 ++- common/src/comp/phys.rs | 30 ++++++++++++ common/src/lib.rs | 35 +++----------- common/src/state.rs | 39 +++++++++++++++ common/src/terrain/biome.rs | 9 ++++ common/src/terrain/block.rs | 4 ++ common/src/terrain/mod.rs | 35 ++++++++++++++ common/src/vol.rs | 27 +++++++++++ common/src/volumes/chunk.rs | 91 +++++++++++++++++++++++++++++++++++ common/src/volumes/mod.rs | 2 + common/src/volumes/vol_map.rs | 79 ++++++++++++++++++++++++++++++ server/src/lib.rs | 6 +-- 14 files changed, 334 insertions(+), 36 deletions(-) create mode 100644 common/src/comp/phys.rs create mode 100644 common/src/state.rs create mode 100644 common/src/terrain/biome.rs create mode 100644 common/src/terrain/block.rs create mode 100644 common/src/terrain/mod.rs create mode 100644 common/src/vol.rs create mode 100644 common/src/volumes/chunk.rs create mode 100644 common/src/volumes/mod.rs create mode 100644 common/src/volumes/vol_map.rs diff --git a/client/src/lib.rs b/client/src/lib.rs index a6fd9f1afd..627d7cc1ac 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -2,7 +2,7 @@ use std::time::Duration; // Internal -use common::LocalState; +use common::state::State; pub enum ClientErr { ServerShutdown, @@ -14,7 +14,7 @@ pub struct Input { } pub struct Client { - state: LocalState, + state: State, // TODO: Add "meta" state here } @@ -22,7 +22,7 @@ pub struct Client { impl Client { pub fn new() -> Self { Self { - state: LocalState::new(), + state: State::new(), } } diff --git a/common/Cargo.toml b/common/Cargo.toml index c2909ab685..65a6d13a8d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -6,3 +6,4 @@ edition = "2018" [dependencies] specs = "0.14" +vek = "0.9" diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index a3eea3dddd..cc7bec16b9 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -1,6 +1,10 @@ +pub mod phys; + // External use specs::{World as EcsWorld, Builder}; pub fn register_local_components(ecs_world: &mut EcsWorld) { - // TODO: Register local components here + ecs_world.register::(); + ecs_world.register::(); + ecs_world.register::(); } diff --git a/common/src/comp/phys.rs b/common/src/comp/phys.rs new file mode 100644 index 0000000000..50809815ba --- /dev/null +++ b/common/src/comp/phys.rs @@ -0,0 +1,30 @@ +// Library +use specs::{Component, VecStorage}; +use vek::*; + +// Pos + +#[derive(Copy, Clone, Debug)] +pub struct Pos(pub Vec3); + +impl Component for Pos { + type Storage = VecStorage; +} + +// Vel + +#[derive(Copy, Clone, Debug)] +pub struct Vel(pub Vec3); + +impl Component for Vel { + type Storage = VecStorage; +} + +// Dir + +#[derive(Copy, Clone, Debug)] +pub struct Dir(pub Vec3); + +impl Component for Dir { + type Storage = VecStorage; +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 86e2b8ce10..e1ec001dc1 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,30 +1,7 @@ +#![feature(euclidean_division)] + pub mod comp; - -// Standard -use std::time::Duration; - -// External -use specs::{World as EcsWorld, Builder}; - -// A type used to represent game state stored on both the client and the server. This includes -// things like entity components, terrain data, and global state like weather, time of day, etc. -pub struct LocalState { - ecs_world: EcsWorld -} - -impl LocalState { - pub fn new() -> Self { - let mut ecs_world = EcsWorld::new(); - - comp::register_local_components(&mut ecs_world); - - Self { - ecs_world, - } - } - - // Execute a single tick, simulating the game state by the given duration - pub fn tick(&mut self, dt: Duration) { - println!("Ticked!"); - } -} +pub mod state; +pub mod terrain; +pub mod volumes; +pub mod vol; diff --git a/common/src/state.rs b/common/src/state.rs new file mode 100644 index 0000000000..5842498ec3 --- /dev/null +++ b/common/src/state.rs @@ -0,0 +1,39 @@ +// Standard +use std::time::Duration; + +// External +use specs::World as EcsWorld; + +// Crate +use crate::{ + comp, + terrain::TerrainMap, + vol::VolSize, +}; + +// A type used to represent game state stored on both the client and the server. This includes +// things like entity components, terrain data, and global state like weather, time of day, etc. +pub struct State { + ecs_world: EcsWorld, + terrain_map: TerrainMap, + time: f64, +} + +impl State { + pub fn new() -> Self { + let mut ecs_world = EcsWorld::new(); + + comp::register_local_components(&mut ecs_world); + + Self { + ecs_world, + terrain_map: TerrainMap::new(), + time: 0.0, + } + } + + // Execute a single tick, simulating the game state by the given duration + pub fn tick(&mut self, dt: Duration) { + println!("Ticked!"); + } +} diff --git a/common/src/terrain/biome.rs b/common/src/terrain/biome.rs new file mode 100644 index 0000000000..53632d139c --- /dev/null +++ b/common/src/terrain/biome.rs @@ -0,0 +1,9 @@ +pub enum BiomeKind { + Grassland, + Ocean, + Mountain, + Snowlands, + Desert, + Swamp, + Forest, +} diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs new file mode 100644 index 0000000000..776c2f7a48 --- /dev/null +++ b/common/src/terrain/block.rs @@ -0,0 +1,4 @@ +pub struct Block { + kind: u8, + color: [u8; 3], +} diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs new file mode 100644 index 0000000000..e54f6d508f --- /dev/null +++ b/common/src/terrain/mod.rs @@ -0,0 +1,35 @@ +pub mod block; +pub mod biome; + +// Library +use vek::*; + +// Crate +use crate::{ + vol::VolSize, + volumes::vol_map::VolMap, +}; + +// Local +use self::{ + block::Block, + biome::BiomeKind, +}; + +// ChunkSize + +pub struct ChunkSize; + +impl VolSize for ChunkSize { + const SIZE: Vec3 = Vec3 { x: 32, y: 32, z: 32 }; +} + +// ChunkMeta + +pub struct ChunkMeta { + biome: BiomeKind, +} + +// TerrainMap + +pub type TerrainMap = VolMap; diff --git a/common/src/vol.rs b/common/src/vol.rs new file mode 100644 index 0000000000..025a3adbf5 --- /dev/null +++ b/common/src/vol.rs @@ -0,0 +1,27 @@ +// Library +use vek::*; + +pub trait BaseVol { + type Vox; + type Err; +} + +pub trait SizedVol: BaseVol { + const SIZE: Vec3; +} + +pub trait ReadVol: BaseVol { + #[inline(always)] + fn get(&self, pos: Vec3) -> Result<&Self::Vox, Self::Err>; +} + +pub trait WriteVol: BaseVol { + #[inline(always)] + fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), Self::Err>; +} + +// Utility traits + +pub trait VolSize { + const SIZE: Vec3; +} diff --git a/common/src/volumes/chunk.rs b/common/src/volumes/chunk.rs new file mode 100644 index 0000000000..1acec192e8 --- /dev/null +++ b/common/src/volumes/chunk.rs @@ -0,0 +1,91 @@ +// Standard +use std::marker::PhantomData; + +// Library +use vek::*; + +// Local +use crate::vol::{ + BaseVol, + SizedVol, + ReadVol, + WriteVol, + VolSize, +}; + +pub enum ChunkErr { + OutOfBounds, +} + +// V = Voxel +// S = Size (replace when const generics are a thing) +// M = Metadata +pub struct Chunk { + vox: Vec, + meta: M, + phantom: PhantomData, +} + +impl Chunk { + #[inline(always)] + fn idx_for(pos: Vec3) -> Option { + if + pos.map(|e| e >= 0).reduce_and() && + pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and() + { + Some(( + pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + + pos.y * S::SIZE.z as i32 + + pos.z + ) as usize) + } else { + None + } + } +} + +impl BaseVol for Chunk { + type Vox = V; + type Err = ChunkErr; +} + +impl SizedVol for Chunk { + const SIZE: Vec3 = Vec3 { x: 32, y: 32, z: 32 }; +} + +impl ReadVol for Chunk { + #[inline(always)] + fn get(&self, pos: Vec3) -> Result<&V, ChunkErr> { + Self::idx_for(pos) + .and_then(|idx| self.vox.get(idx)) + .ok_or(ChunkErr::OutOfBounds) + } +} + +impl WriteVol for Chunk { + #[inline(always)] + fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), ChunkErr> { + Self::idx_for(pos) + .and_then(|idx| self.vox.get_mut(idx)) + .map(|old_vox| *old_vox = vox) + .ok_or(ChunkErr::OutOfBounds) + } +} + +impl Chunk { + pub fn filled(vox: V, meta: M) -> Self { + Self { + vox: vec![vox; S::SIZE.product() as usize], + meta, + phantom: PhantomData, + } + } + + pub fn metadata(&self) -> &M { + &self.meta + } + + pub fn metadata_mut(&mut self) -> &mut M { + &mut self.meta + } +} diff --git a/common/src/volumes/mod.rs b/common/src/volumes/mod.rs new file mode 100644 index 0000000000..d1f4568502 --- /dev/null +++ b/common/src/volumes/mod.rs @@ -0,0 +1,2 @@ +pub mod chunk; +pub mod vol_map; diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs new file mode 100644 index 0000000000..c3c2ff0834 --- /dev/null +++ b/common/src/volumes/vol_map.rs @@ -0,0 +1,79 @@ +// Standard +use std::collections::HashMap; + +// Library +use vek::*; + +// Crate +use crate::{ + vol::{ + BaseVol, + ReadVol, + WriteVol, + VolSize, + }, + volumes::chunk::{Chunk, ChunkErr}, +}; + +pub enum VolMapErr { + NoSuchChunk, + ChunkErr(ChunkErr), +} + +// V = Voxel +// S = Size (replace with a const when const generics is a thing) +// M = Chunk metadata +pub struct VolMap { + chunks: HashMap, Chunk>, +} + +impl VolMap { + #[inline(always)] + fn chunk_key(pos: Vec3) -> Vec3 { + pos.map2(S::SIZE, |e, sz| e.div_euclid(sz as i32)) + } + + #[inline(always)] + fn chunk_offs(pos: Vec3) -> Vec3 { + pos.map2(S::SIZE, |e, sz| e.rem_euclid(sz as i32)) + } +} + +impl BaseVol for VolMap { + type Vox = V; + type Err = VolMapErr; +} + +impl ReadVol for VolMap { + #[inline(always)] + fn get(&self, pos: Vec3) -> Result<&V, VolMapErr> { + let ck = Self::chunk_key(pos); + self.chunks.get(&ck) + .ok_or(VolMapErr::NoSuchChunk) + .and_then(|chunk| { + let co = Self::chunk_offs(pos); + chunk.get(co).map_err(|err| VolMapErr::ChunkErr(err)) + }) + } +} + +impl WriteVol for VolMap { + #[inline(always)] + fn set(&mut self, pos: Vec3, vox: V) -> Result<(), VolMapErr> { + let ck = Self::chunk_key(pos); + self.chunks.get_mut(&ck) + .ok_or(VolMapErr::NoSuchChunk) + .and_then(|chunk| { + let co = Self::chunk_offs(pos); + chunk.set(co, vox).map_err(|err| VolMapErr::ChunkErr(err)) + }) + } +} + +impl VolMap { + pub fn new() -> Self { + Self { + chunks: HashMap::new(), + } + } +} diff --git a/server/src/lib.rs b/server/src/lib.rs index 4e44b9f7d6..b03b3b61c3 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -2,7 +2,7 @@ use std::time::Duration; // Internal -use common::LocalState; +use common::state::State; pub enum ClientErr { ServerShutdown, @@ -14,7 +14,7 @@ pub struct Input { } pub struct Server { - state: LocalState, + state: State, // TODO: Add "meta" state here } @@ -22,7 +22,7 @@ pub struct Server { impl Server { pub fn new() -> Self { Self { - state: LocalState::new(), + state: State::new(), } }