aboutsummaryrefslogtreecommitdiff
path: root/azalea-world/src/lib.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2022-06-25 05:09:26 +0000
committerGitHub <noreply@github.com>2022-06-25 05:09:26 +0000
commit7d3e57763e32ac9cf94180b1c714704cfbc3034d (patch)
tree2dcfe72bf09a42f6614f9dc988dc0254162ea0bf /azalea-world/src/lib.rs
parent69c47eda4c496b13dadd80976bffd2fab7ea5894 (diff)
parentca7067e173129f3044ebc8c77634f06da29a086e (diff)
downloadazalea-drasl-7d3e57763e32ac9cf94180b1c714704cfbc3034d.tar.xz
Merge pull request #10 from mat-1/azalea-entity
azalea-entity
Diffstat (limited to 'azalea-world/src/lib.rs')
-rw-r--r--azalea-world/src/lib.rs276
1 files changed, 86 insertions, 190 deletions
diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs
index e651e455..3afa4fee 100644
--- a/azalea-world/src/lib.rs
+++ b/azalea-world/src/lib.rs
@@ -1,19 +1,22 @@
#![feature(int_roundings)]
mod bit_storage;
+mod chunk;
+mod entity;
mod palette;
-use crate::palette::PalettedContainerType;
use azalea_block::BlockState;
-use azalea_core::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos};
-use azalea_protocol::mc_buf::{McBufReadable, McBufWritable};
+use azalea_core::{BlockPos, ChunkPos, EntityPos, PositionDelta8};
+use azalea_entity::Entity;
pub use bit_storage::BitStorage;
-use palette::PalettedContainer;
+pub use chunk::{Chunk, ChunkStorage};
+pub use entity::EntityStorage;
use std::{
- io::{Read, Write},
+ io::Read,
ops::{Index, IndexMut},
sync::{Arc, Mutex},
};
+use uuid::Uuid;
#[cfg(test)]
mod tests {
@@ -24,230 +27,123 @@ mod tests {
}
}
-const SECTION_HEIGHT: u32 = 16;
-
+#[derive(Debug)]
pub struct World {
- pub storage: ChunkStorage,
- pub height: u32,
- pub min_y: i32,
+ chunk_storage: ChunkStorage,
+ entity_storage: EntityStorage,
}
impl World {
+ pub fn new(chunk_radius: u32, height: u32, min_y: i32) -> Self {
+ World {
+ chunk_storage: ChunkStorage::new(chunk_radius, height, min_y),
+ entity_storage: EntityStorage::new(),
+ }
+ }
+
pub fn replace_with_packet_data(
&mut self,
pos: &ChunkPos,
data: &mut impl Read,
) -> Result<(), String> {
- if !self.storage.in_range(pos) {
- println!(
- "Ignoring chunk since it's not in the view range: {}, {}",
- pos.x, pos.z
- );
- return Ok(());
- }
- // let existing_chunk = &self.storage[pos];
-
- let chunk = Arc::new(Mutex::new(Chunk::read_with_world(data, self)?));
- println!("Loaded chunk {:?}", pos);
- self.storage[pos] = Some(chunk);
-
- Ok(())
+ self.chunk_storage.replace_with_packet_data(pos, data)
}
pub fn update_view_center(&mut self, pos: &ChunkPos) {
- self.storage.view_center = *pos;
+ self.chunk_storage.view_center = *pos;
}
pub fn get_block_state(&self, pos: &BlockPos) -> Option<BlockState> {
- self.storage.get_block_state(pos, self.min_y)
- }
-}
-impl Index<&ChunkPos> for World {
- type Output = Option<Arc<Mutex<Chunk>>>;
-
- fn index(&self, pos: &ChunkPos) -> &Self::Output {
- &self.storage[pos]
- }
-}
-impl IndexMut<&ChunkPos> for World {
- fn index_mut<'a>(&'a mut self, pos: &ChunkPos) -> &'a mut Self::Output {
- &mut self.storage[pos]
- }
-}
-// impl Index<&BlockPos> for World {
-// type Output = Option<Arc<Mutex<Chunk>>>;
-
-// fn index(&self, pos: &BlockPos) -> &Self::Output {
-// let chunk = &self[ChunkPos::from(pos)];
-// // chunk.
-
-// }
-// }
-
-pub struct ChunkStorage {
- view_center: ChunkPos,
- chunk_radius: u32,
- view_range: u32,
- // chunks is a list of size chunk_radius * chunk_radius
- chunks: Vec<Option<Arc<Mutex<Chunk>>>>,
-}
-
-// java moment
-// it might be possible to replace this with just a modulo, but i copied java's floorMod just in case
-fn floor_mod(x: i32, y: u32) -> u32 {
- if x < 0 {
- y - ((-x) as u32 % y)
- } else {
- x as u32 % y
- }
-}
-
-impl ChunkStorage {
- pub fn new(chunk_radius: u32) -> Self {
- let view_range = chunk_radius * 2 + 1;
- ChunkStorage {
- view_center: ChunkPos::new(0, 0),
- chunk_radius,
- view_range,
- chunks: vec![None; (view_range * view_range) as usize],
+ self.chunk_storage.get_block_state(pos, self.min_y())
+ }
+
+ pub fn move_entity(&mut self, entity_id: u32, new_pos: EntityPos) -> Result<(), String> {
+ let entity = self
+ .entity_storage
+ .get_mut_by_id(entity_id)
+ .ok_or_else(|| "Moving entity that doesn't exist".to_string())?;
+
+ let old_chunk = ChunkPos::from(entity.pos());
+ let new_chunk = ChunkPos::from(&new_pos);
+ // this is fine because we update the chunk below
+ entity.unsafe_move(new_pos);
+ if old_chunk != new_chunk {
+ self.entity_storage
+ .update_entity_chunk(entity_id, &old_chunk, &new_chunk);
}
+ Ok(())
}
- fn get_index(&self, chunk_pos: &ChunkPos) -> usize {
- (floor_mod(chunk_pos.x, self.view_range) * self.view_range
- + floor_mod(chunk_pos.z, self.view_range)) as usize
+ pub fn move_entity_with_delta(
+ &mut self,
+ entity_id: u32,
+ delta: &PositionDelta8,
+ ) -> Result<(), String> {
+ let entity = self
+ .entity_storage
+ .get_mut_by_id(entity_id)
+ .ok_or_else(|| "Moving entity that doesn't exist".to_string())?;
+ let new_pos = entity.pos().with_delta(delta);
+
+ let old_chunk = ChunkPos::from(entity.pos());
+ let new_chunk = ChunkPos::from(&new_pos);
+ // this is fine because we update the chunk below
+
+ entity.unsafe_move(new_pos);
+ if old_chunk != new_chunk {
+ self.entity_storage
+ .update_entity_chunk(entity_id, &old_chunk, &new_chunk);
+ }
+ Ok(())
}
- pub fn in_range(&self, chunk_pos: &ChunkPos) -> bool {
- (chunk_pos.x - self.view_center.x).unsigned_abs() <= self.chunk_radius
- && (chunk_pos.z - self.view_center.z).unsigned_abs() <= self.chunk_radius
+ pub fn add_entity(&mut self, entity: Entity) {
+ self.entity_storage.insert(entity);
}
- pub fn get_block_state(&self, pos: &BlockPos, min_y: i32) -> Option<BlockState> {
- let chunk_pos = ChunkPos::from(pos);
- println!("chunk_pos {:?} block_pos {:?}", chunk_pos, pos);
- let chunk = &self[&chunk_pos];
- match chunk {
- Some(chunk) => Some(chunk.lock().unwrap().get(&ChunkBlockPos::from(pos), min_y)),
- None => None,
- }
+ pub fn height(&self) -> u32 {
+ self.chunk_storage.height
}
-}
-
-impl Index<&ChunkPos> for ChunkStorage {
- type Output = Option<Arc<Mutex<Chunk>>>;
- fn index(&self, pos: &ChunkPos) -> &Self::Output {
- &self.chunks[self.get_index(pos)]
+ pub fn min_y(&self) -> i32 {
+ self.chunk_storage.min_y
}
-}
-impl IndexMut<&ChunkPos> for ChunkStorage {
- fn index_mut<'a>(&'a mut self, pos: &ChunkPos) -> &'a mut Self::Output {
- let index = self.get_index(pos);
- &mut self.chunks[index]
- }
-}
-#[derive(Debug)]
-pub struct Chunk {
- pub sections: Vec<Section>,
-}
-
-impl Chunk {
- pub fn read_with_world(buf: &mut impl Read, data: &World) -> Result<Self, String> {
- Self::read_with_world_height(buf, data.height)
+ pub fn entity_by_id(&self, id: u32) -> Option<&Entity> {
+ self.entity_storage.get_by_id(id)
}
- pub fn read_with_world_height(buf: &mut impl Read, world_height: u32) -> Result<Self, String> {
- let section_count = world_height / SECTION_HEIGHT;
- let mut sections = Vec::with_capacity(section_count as usize);
- for _ in 0..section_count {
- let section = Section::read_into(buf)?;
- sections.push(section);
- }
- Ok(Chunk { sections })
+ pub fn mut_entity_by_id(&mut self, id: u32) -> Option<&mut Entity> {
+ self.entity_storage.get_mut_by_id(id)
}
- pub fn section_index(&self, y: i32, min_y: i32) -> u32 {
- // TODO: check the build height and stuff, this code will be broken if the min build height is 0
- // (LevelHeightAccessor.getMinSection in vanilla code)
- assert!(y >= 0);
- let min_section_index = min_y.div_floor(16);
- (y.div_floor(16) - min_section_index) as u32
+ pub fn entity_by_uuid(&self, uuid: &Uuid) -> Option<&Entity> {
+ self.entity_storage.get_by_uuid(uuid)
}
- pub fn get(&self, pos: &ChunkBlockPos, min_y: i32) -> BlockState {
- let section_index = self.section_index(pos.y, min_y);
- // TODO: make sure the section exists
- let section = &self.sections[section_index as usize];
- let chunk_section_pos = ChunkSectionBlockPos::from(pos);
- let block_state = section.get(chunk_section_pos);
- block_state
+ /// Get an iterator over all entities.
+ #[inline]
+ pub fn entities(&self) -> std::collections::hash_map::Values<'_, u32, Entity> {
+ self.entity_storage.entities()
}
-}
-impl McBufWritable for Chunk {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- for section in &self.sections {
- section.write_into(buf)?;
- }
- Ok(())
+ pub fn find_one_entity<F>(&self, mut f: F) -> Option<&Entity>
+ where
+ F: FnMut(&Entity) -> bool,
+ {
+ self.entity_storage.find_one_entity(|entity| f(entity))
}
}
-#[derive(Clone, Debug)]
-pub struct Section {
- pub block_count: u16,
- pub states: PalettedContainer,
- pub biomes: PalettedContainer,
-}
-
-impl McBufReadable for Section {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let block_count = u16::read_into(buf)?;
-
- // this is commented out because the vanilla server is wrong
- // assert!(
- // block_count <= 16 * 16 * 16,
- // "A section has more blocks than what should be possible. This is a bug!"
- // );
-
- let states = PalettedContainer::read_with_type(buf, &PalettedContainerType::BlockStates)?;
-
- for i in 0..states.storage.size() {
- if !BlockState::is_valid_state(states.storage.get(i) as u32) {
- return Err(format!(
- "Invalid block state {} (index {}) found in section.",
- states.storage.get(i),
- i
- ));
- }
- }
-
- let biomes = PalettedContainer::read_with_type(buf, &PalettedContainerType::Biomes)?;
- Ok(Section {
- block_count,
- states,
- biomes,
- })
- }
-}
+impl Index<&ChunkPos> for World {
+ type Output = Option<Arc<Mutex<Chunk>>>;
-impl McBufWritable for Section {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- self.block_count.write_into(buf)?;
- self.states.write_into(buf)?;
- self.biomes.write_into(buf)?;
- Ok(())
+ fn index(&self, pos: &ChunkPos) -> &Self::Output {
+ &self.chunk_storage[pos]
}
}
-
-impl Section {
- fn get(&self, pos: ChunkSectionBlockPos) -> BlockState {
- // TODO: use the unsafe method and do the check earlier
- self.states
- .get(pos.x as usize, pos.y as usize, pos.z as usize)
- .try_into()
- .expect("Invalid block state.")
+impl IndexMut<&ChunkPos> for World {
+ fn index_mut<'a>(&'a mut self, pos: &ChunkPos) -> &'a mut Self::Output {
+ &mut self.chunk_storage[pos]
}
}