diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:18 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:18 +0100 |
commit | c8c5e880781343d72671c231be8e132af5e2f344 (patch) | |
tree | d4736c557f0dba0dd667d10c4ad22f22fb2495ad /stockton-types/src |
Initial Commit.
Diffstat (limited to 'stockton-types/src')
-rw-r--r-- | stockton-types/src/entity_store.rs | 97 | ||||
-rw-r--r-- | stockton-types/src/lib.rs | 27 |
2 files changed, 124 insertions, 0 deletions
diff --git a/stockton-types/src/entity_store.rs b/stockton-types/src/entity_store.rs new file mode 100644 index 0000000..99a9525 --- /dev/null +++ b/stockton-types/src/entity_store.rs @@ -0,0 +1,97 @@ +//! Stores entities in a world. + +use std::collections::HashMap; +use std::boxed::Box; +use std::ops::Index; +use crate::Vector3; + +/// An entity, capable of recieving events. +pub trait Entity { + + /// Should return the position of this entity in 3d space. + /// + /// This will likely just be `self.pos` + fn get_position(&self) -> Vector3; + +} + +/// Stores all the entities in a live world. The BSPFile only specifies the starting entities, +/// whereas this is mutable and thus is used to represent the current state of the world's entities. +/// +/// Internally, this uses a vector to store the entities, and a hashmap to map names to indicies in that vector. +/// +/// An entity's index may change, so if you want to target an entity throughout frames you should store its name. +pub struct EntityStore { + entities: Vec<Box<dyn Entity>>, + name_to_index: HashMap<String, usize> +} + +/// Returned when an entity's name conflicts with an existing entity. +pub struct NameConflict; + +impl EntityStore { + /// Try to add the given entity with the given name. + /// + /// # Returns + /// The name & index of the added entity if successful. + /// If an entity already exists with the given name, NameConflict is returned. + pub fn add(&mut self, entity: Box<Entity>, name: String) -> Result<usize, NameConflict> { + if self.name_to_index.contains_key(&name) { + return Err(NameConflict) + } + self.name_to_index.insert(name, self.entities.len()); + self.entities.push(entity); + + Ok(self.entities.len() - 1) + } + + /// Remove the entity with the given index, returning it. + /// + /// Takes O(2n - i) time. + pub fn remove_by_index(&mut self, index: usize) -> Option<Box<Entity>> { + if index >= self.entities.len() { + return None; + } + self.name_to_index.retain(|_,v| *v != index); + Some(self.entities.remove(index)) + } + + /// Removes the entity with the given name, returning it. + /// + /// Takes O(2n - i) time. + pub fn remove_by_name(&mut self, name: &str) -> Option<Box<Entity>> { + let mut index: usize = self.entities.len(); + + self.name_to_index.retain(|k,v| { + if k == name { + index = *v; + return false; + } + true + }); + + if index >= self.entities.len() { + return None; + } + + Some(self.entities.remove(index)) + } +} + +/// Indexes the EntityStore for a specific index. +/// If you want to target an entity for longer than one tick, store its name, not an index. +impl Index<usize> for EntityStore { + type Output = Entity; + fn index(&self, index: usize) -> &Self::Output { + self.entities[index].as_ref() + } +} + +/// Indexes the EntityStore for a specific name. +/// This is what you should use if you plan to target an entity for more than one tick. +impl Index<&str> for EntityStore { + type Output = Entity; + fn index(&self, index: &str) -> &Self::Output { + self.entities[self.name_to_index[index]].as_ref() + } +}
\ No newline at end of file diff --git a/stockton-types/src/lib.rs b/stockton-types/src/lib.rs new file mode 100644 index 0000000..259c40c --- /dev/null +++ b/stockton-types/src/lib.rs @@ -0,0 +1,27 @@ +//! Common types for all stockton crates. + +extern crate stockton_bsp; +extern crate nalgebra as na; + +use stockton_bsp::BSPFile; + +pub mod entity_store; +use entity_store::EntityStore; + +/// Alias for convenience +pub type Vector2 = na::base::Vector2<f32>; +/// Alias for convenience +pub type Vector3 = na::base::Vector3<f32>; + +/// Alias for convenience +pub type Vector2i = na::base::Vector2<i32>; + +/// Alias for convenience +pub type Vector3i = na::base::Vector3<i32>; + +/// A live and playable world. There are two parts: The map, which has walls and other static objects, +/// and entities, which can move around and do things and are physics simulated. +pub struct World<'a> { + pub map: BSPFile<'a>, + pub live_entities: EntityStore, +}
\ No newline at end of file |