From 0098086b8f2f791e31c8fb34dfaa51dadd1c7972 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sat, 26 Dec 2020 15:53:06 +0000 Subject: [PATCH] Began work on new sites --- common/src/store.rs | 156 +++++++++++++++++++++++++++++++++------- world/examples/site.rs | 3 + world/src/lib.rs | 1 + world/src/sim2/mod.rs | 3 +- world/src/site2/mod.rs | 15 ++++ world/src/site2/plot.rs | 12 ++++ world/src/site2/tile.rs | 49 +++++++++++++ 7 files changed, 213 insertions(+), 26 deletions(-) create mode 100644 world/examples/site.rs create mode 100644 world/src/site2/mod.rs create mode 100644 world/src/site2/plot.rs create mode 100644 world/src/site2/tile.rs diff --git a/common/src/store.rs b/common/src/store.rs index e3ededbd25..49ed00e8c4 100644 --- a/common/src/store.rs +++ b/common/src/store.rs @@ -5,69 +5,175 @@ use std::{ ops::{Index, IndexMut}, }; -// NOTE: We use u64 to make sure we are consistent across all machines. We -// assume that usize fits into 8 bytes. -pub struct Id(u64, PhantomData); +pub struct Id { + idx: u32, + gen: u32, + phantom: PhantomData, +} impl Id { - pub fn id(&self) -> u64 { self.0 } + pub fn id(&self) -> u64 { self.idx as u64 | ((self.gen as u64) << 32) } } impl Copy for Id {} impl Clone for Id { - fn clone(&self) -> Self { Self(self.0, PhantomData) } + fn clone(&self) -> Self { + Self { + idx: self.idx, + gen: self.gen, + phantom: PhantomData, + } + } } impl Eq for Id {} impl PartialEq for Id { - fn eq(&self, other: &Self) -> bool { self.0 == other.0 } + fn eq(&self, other: &Self) -> bool { self.idx == other.idx && self.gen == other.gen } } impl fmt::Debug for Id { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Id<{}>({})", std::any::type_name::(), self.0) + write!(f, "Id<{}>({}, {})", std::any::type_name::(), self.idx, self.gen) } } impl hash::Hash for Id { - fn hash(&self, h: &mut H) { self.0.hash(h); } + fn hash(&self, h: &mut H) { + self.idx.hash(h); + self.gen.hash(h); + } +} + +struct Entry { + gen: u32, + item: Option, } pub struct Store { - items: Vec, + entries: Vec>, + len: usize, } impl Default for Store { - fn default() -> Self { Self { items: Vec::new() } } + fn default() -> Self { + Self { + entries: Vec::new(), + len: 0, + } + } } impl Store { + pub fn contains(&self, id: Id) -> bool { + self.entries + .get(id.idx as usize) + .map(|e| e.gen == id.gen) + .unwrap_or(false) + } + pub fn get(&self, id: Id) -> &T { - // NOTE: Safe conversion, because it came from usize. - self.items.get(id.0 as usize).unwrap() + let entry = self.entries + .get(id.idx as usize) + .unwrap(); + if entry.gen == id.gen { + entry.item.as_ref().unwrap() + } else { + panic!("Stale ID used to access store entry"); + } } pub fn get_mut(&mut self, id: Id) -> &mut T { - // NOTE: Safe conversion, because it came from usize. - self.items.get_mut(id.0 as usize).unwrap() + let entry = self.entries + .get_mut(id.idx as usize) + .unwrap(); + if entry.gen == id.gen { + entry.item.as_mut().unwrap() + } else { + panic!("Stale ID used to access store entry"); + } } - pub fn ids(&self) -> impl Iterator> { - (0..self.items.len()).map(|i| Id(i as u64, PhantomData)) + pub fn ids(&self) -> impl Iterator> + '_ { + self.iter().map(|(id, _)| id) } - pub fn values(&self) -> impl Iterator { self.items.iter() } + pub fn values(&self) -> impl Iterator + '_ { + self.iter().map(|(_, item)| item) + } - pub fn values_mut(&mut self) -> impl Iterator { self.items.iter_mut() } + pub fn values_mut(&mut self) -> impl Iterator + '_ { + self.iter_mut().map(|(_, item)| item) + } - pub fn iter(&self) -> impl Iterator, &T)> { self.ids().zip(self.values()) } + pub fn iter(&self) -> impl Iterator, &T)> + '_ { + self.entries + .iter() + .enumerate() + .filter_map(move |(idx, entry)| { + Some(Id { + idx: idx as u32, + gen: entry.gen, + phantom: PhantomData, + }).zip(entry.item.as_ref()) + }) + } - pub fn iter_mut(&mut self) -> impl Iterator, &mut T)> { - self.ids().zip(self.values_mut()) + pub fn iter_mut(&mut self) -> impl Iterator, &mut T)> + '_ { + self.entries + .iter_mut() + .enumerate() + .filter_map(move |(idx, entry)| { + Some(Id { + idx: idx as u32, + gen: entry.gen, + phantom: PhantomData, + }).zip(entry.item.as_mut()) + }) } pub fn insert(&mut self, item: T) -> Id { - // NOTE: Assumes usize fits into 8 bytes. - let id = Id(self.items.len() as u64, PhantomData); - self.items.push(item); - id + if self.len < self.entries.len() { + // TODO: Make this more efficient with a lookahead system + let (idx, entry) = self.entries + .iter_mut() + .enumerate() + .find(|(_, e)| e.item.is_none()) + .unwrap(); + entry.item = Some(item); + assert!(entry.gen < u32::MAX); + entry.gen += 1; + Id { + idx: idx as u32, + gen: entry.gen, + phantom: PhantomData, + } + } else { + assert!(self.entries.len() < (u32::MAX - 1) as usize); + let id = Id { + idx: self.entries.len() as u32, + gen: 0, + phantom: PhantomData, + }; + self.entries.push(Entry { + gen: 0, + item: Some(item), + }); + self.len += 1; + id + } + } + + pub fn remove(&mut self, id: Id) -> Option { + if let Some(item) = self.entries + .get_mut(id.idx as usize) + .and_then(|e| if e.gen == id.gen { + e.item.take() + } else { + None + }) + { + self.len -= 1; + Some(item) + } else { + None + } } } diff --git a/world/examples/site.rs b/world/examples/site.rs new file mode 100644 index 0000000000..c89b901b25 --- /dev/null +++ b/world/examples/site.rs @@ -0,0 +1,3 @@ +fn main() { + todo!(); +} diff --git a/world/src/lib.rs b/world/src/lib.rs index 859f829d82..b5ca5fad03 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -24,6 +24,7 @@ pub mod pathfinding; pub mod sim; pub mod sim2; pub mod site; +pub mod site2; pub mod util; // Reexports diff --git a/world/src/sim2/mod.rs b/world/src/sim2/mod.rs index a89d327d0c..2216286ed2 100644 --- a/world/src/sim2/mod.rs +++ b/world/src/sim2/mod.rs @@ -88,7 +88,8 @@ pub fn simulate(index: &mut Index, world: &mut WorldSim) { } pub fn tick(index: &mut Index, _world: &mut WorldSim, dt: f32) { - for site in index.sites.ids() { + let site_ids = index.sites.ids().collect::>(); + for site in site_ids { tick_site_economy(index, site, dt); } diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs new file mode 100644 index 0000000000..9bf80a75b3 --- /dev/null +++ b/world/src/site2/mod.rs @@ -0,0 +1,15 @@ +mod tile; +mod plot; + +use vek::*; +use common::store::{Store, Id}; +use crate::util::Grid; +use self::{ + tile::TileGrid, + plot::Plot, +}; + +pub struct Site { + grid: TileGrid, + plot: Store, +} diff --git a/world/src/site2/plot.rs b/world/src/site2/plot.rs new file mode 100644 index 0000000000..9c2b8c658e --- /dev/null +++ b/world/src/site2/plot.rs @@ -0,0 +1,12 @@ +use vek::*; + +pub struct Plot { + kind: PlotKind, + center_tpos: Vec2, + units: Vec2>, +} + +pub enum PlotKind { + Path, + House { height: i32 }, +} diff --git a/world/src/site2/tile.rs b/world/src/site2/tile.rs new file mode 100644 index 0000000000..b4006c436b --- /dev/null +++ b/world/src/site2/tile.rs @@ -0,0 +1,49 @@ +use super::*; + +const TILE_SIZE: u32 = 7; +const ZONE_SIZE: u32 = 16; +const ZONE_RADIUS: u32 = 16; +const TILE_RADIUS: u32 = ZONE_SIZE * ZONE_RADIUS; +const MAX_BLOCK_RADIUS: u32 = TILE_SIZE * TILE_RADIUS; + +pub struct TileGrid { + zones: Grid>>>, +} + +impl TileGrid { + pub fn new() -> Self { + Self { + zones: Grid::populate_from(Vec2::broadcast(ZONE_RADIUS as i32 * 2 + 1), |_| None), + } + } + + pub fn get(&self, tpos: Vec2) -> Option<&Tile> { + let tpos = tpos + TILE_RADIUS as i32; + self.zones + .get(tpos) + .and_then(|zone| zone.as_ref()?.get(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32)))) + .and_then(|tile| tile.as_ref()) + } + + pub fn get_mut(&mut self, tpos: Vec2) -> Option<&mut Tile> { + let tpos = tpos + TILE_RADIUS as i32; + self.zones + .get_mut(tpos) + .and_then(|zone| zone + .get_or_insert_with(|| Grid::populate_from(Vec2::broadcast(ZONE_RADIUS as i32 * 2 + 1), |_| None)) + .get_mut(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32))) + .map(|tile| tile.get_or_insert_with(|| Tile::empty()))) + } +} + +pub struct Tile { + plot: Option>, +} + +impl Tile { + pub fn empty() -> Self { + Self { + plot: None, + } + } +}