aboutsummaryrefslogtreecommitdiff
path: root/azalea-world/src/world.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2022-11-27 16:25:07 -0600
committerGitHub <noreply@github.com>2022-11-27 16:25:07 -0600
commit631ed63dbdc7167df4de02a55b5c2ef1cea909e9 (patch)
tree104e567c332f2aeb30ea6acefef8c73f9b2f158b /azalea-world/src/world.rs
parent962b9fcaae917c7e5bef718469fba31f6ff7c3cb (diff)
downloadazalea-drasl-631ed63dbdc7167df4de02a55b5c2ef1cea909e9.tar.xz
Swarm (#36)
* make azalea-pathfinder dir * start writing d* lite impl * more work on d* lite * work more on implementing d* lite * full d* lite impl * updated edges * add next() function * add NoPathError * why does dstar lite not work * fix d* lite implementation * make the test actually check the coords * replace while loop with if statement * fix clippy complaints * make W only have to be PartialOrd * fix PartialOrd issues * implement mtd* lite * add a test to mtd* lite * remove normal d* lite * make heuristic only take in one arg * add `success` function * Update README.md * evil black magic to make .entity not need dimension * start adding moves * slightly improve the vec3/position situation new macro that implements all the useful functions * moves stuff * make it compile * update deps in az-pathfinder * make it compile again * more pathfinding stuff * add Bot::look_at * replace EntityMut and EntityRef with just Entity * block pos pathfinding stuff * rename movedirection to walkdirection * execute path every tick * advance path * change az-pf version * make azalea_client keep plugin state * fix Plugins::get * why does it think there is air * start debugging incorrect air * update some From methods to use rem_euclid * start adding swarm * fix deadlock i still don't understand why it was happening but the solution was to keep the Client::player lock for shorter so it didn't overlap with the Client::dimension lock * make lookat actually work probably * fix going too fast * Update main.rs * make a thing immutable * direction_looking_at * fix rotations * import swarm in an example * fix stuff from merge * remove azalea_pathfinder import * delete azalea-pathfinder crate already in azalea::pathfinder module * swarms * start working on shared dimensions * Shared worlds work * start adding Swarm::add_account * add_account works * change "client" to "bot" in some places * Fix issues from merge * Update world.rs * add SwarmEvent::Disconnect(Account) * almost add SwarmEvent::Chat and new plugin system it panics rn * make plugins have to provide the State associated type * improve comments * make fn build slightly cleaner * fix SwarmEvent::Chat * change a println in bot/main.rs * Client::shutdown -> disconnect * polish fix clippy warnings + improve some docs a bit * fix shared worlds* *there's a bug that entities and bots will have their positions exaggerated because the relative movement packet is applied for every entity once per bot * i am being trolled by rust for some reason some stuff is really slow for literally no reason and it makes no sense i am going insane * make world an RwLock again * remove debug messages * fix skipping event ticks unfortunately now sending events is `.send().await?` instead of just `.send()` * fix deadlock + warnings * turns out my floor_mod impl was wrong and i32::rem_euclid has the correct behavior LOL * still errors with lots of bots * make swarm iter & fix new chunks not loading * improve docs * start fixing tests * fix all the tests except the examples i don't know how to exclude them from the tests * improve docs some more
Diffstat (limited to 'azalea-world/src/world.rs')
-rw-r--r--azalea-world/src/world.rs181
1 files changed, 181 insertions, 0 deletions
diff --git a/azalea-world/src/world.rs b/azalea-world/src/world.rs
new file mode 100644
index 00000000..257d9eb6
--- /dev/null
+++ b/azalea-world/src/world.rs
@@ -0,0 +1,181 @@
+use crate::{
+ entity::{Entity, EntityData},
+ Chunk, MoveEntityError, PartialChunkStorage, PartialEntityStorage, WeakChunkStorage,
+ WeakEntityStorage,
+};
+use azalea_block::BlockState;
+use azalea_buf::BufReadError;
+use azalea_core::{BlockPos, ChunkPos, PositionDelta8, Vec3};
+use parking_lot::{Mutex, RwLock};
+use std::{backtrace::Backtrace, fmt::Debug};
+use std::{fmt::Formatter, io::Cursor, sync::Arc};
+use uuid::Uuid;
+
+/// A world is a collection of chunks and entities. They're called "levels" in Minecraft's source code.
+#[derive(Default)]
+pub struct World {
+ // we just need to keep a strong reference to `shared` so it doesn't get
+ // dropped, we don't need to do anything with it
+ _shared: Arc<WeakWorld>,
+
+ pub chunk_storage: PartialChunkStorage,
+ pub entity_storage: PartialEntityStorage,
+}
+
+/// A world where the chunks are stored as weak pointers. This is used for shared worlds.
+#[derive(Default)]
+pub struct WeakWorld {
+ pub chunk_storage: Arc<RwLock<WeakChunkStorage>>,
+ pub entity_storage: Arc<RwLock<WeakEntityStorage>>,
+}
+
+impl World {
+ pub fn new(chunk_radius: u32, shared: Arc<WeakWorld>, owner_entity_id: u32) -> Self {
+ World {
+ _shared: shared.clone(),
+ chunk_storage: PartialChunkStorage::new(chunk_radius, shared.chunk_storage.clone()),
+ entity_storage: PartialEntityStorage::new(
+ shared.entity_storage.clone(),
+ owner_entity_id,
+ ),
+ }
+ }
+
+ pub fn replace_with_packet_data(
+ &mut self,
+ pos: &ChunkPos,
+ data: &mut Cursor<&[u8]>,
+ ) -> Result<(), BufReadError> {
+ self.chunk_storage.replace_with_packet_data(pos, data)
+ }
+
+ pub fn get_chunk(&self, pos: &ChunkPos) -> Option<Arc<Mutex<Chunk>>> {
+ self.chunk_storage.get(pos)
+ }
+
+ pub fn set_chunk(&mut self, pos: &ChunkPos, chunk: Option<Chunk>) -> Result<(), BufReadError> {
+ self.chunk_storage
+ .set(pos, chunk.map(|c| Arc::new(Mutex::new(c))));
+ Ok(())
+ }
+
+ pub fn update_view_center(&mut self, pos: &ChunkPos) {
+ self.chunk_storage.view_center = *pos;
+ }
+
+ pub fn get_block_state(&self, pos: &BlockPos) -> Option<BlockState> {
+ self.chunk_storage.get_block_state(pos)
+ }
+
+ pub fn set_block_state(&mut self, pos: &BlockPos, state: BlockState) -> Option<BlockState> {
+ self.chunk_storage.set_block_state(pos, state)
+ }
+
+ pub fn set_entity_pos(&mut self, entity_id: u32, new_pos: Vec3) -> Result<(), MoveEntityError> {
+ let mut entity = self
+ .entity_mut(entity_id)
+ .ok_or_else(|| MoveEntityError::EntityDoesNotExist(Backtrace::capture()))?;
+ let old_chunk = ChunkPos::from(entity.pos());
+ let new_chunk = ChunkPos::from(&new_pos);
+ // this is fine because we update the chunk below
+ unsafe { entity.move_unchecked(new_pos) };
+ if old_chunk != new_chunk {
+ self.entity_storage
+ .update_entity_chunk(entity_id, &old_chunk, &new_chunk);
+ }
+ Ok(())
+ }
+
+ pub fn move_entity_with_delta(
+ &mut self,
+ entity_id: u32,
+ delta: &PositionDelta8,
+ ) -> Result<(), MoveEntityError> {
+ let mut entity = self
+ .entity_mut(entity_id)
+ .ok_or_else(|| MoveEntityError::EntityDoesNotExist(Backtrace::capture()))?;
+ 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
+
+ unsafe { entity.move_unchecked(new_pos) };
+ if old_chunk != new_chunk {
+ self.entity_storage
+ .update_entity_chunk(entity_id, &old_chunk, &new_chunk);
+ }
+ Ok(())
+ }
+
+ pub fn add_entity(&mut self, id: u32, entity: EntityData) {
+ self.entity_storage.insert(id, entity);
+ }
+
+ pub fn height(&self) -> u32 {
+ self.chunk_storage.height()
+ }
+
+ pub fn min_y(&self) -> i32 {
+ self.chunk_storage.min_y()
+ }
+
+ pub fn entity_data_by_id(&self, id: u32) -> Option<Arc<EntityData>> {
+ self.entity_storage.get_by_id(id)
+ }
+
+ pub fn entity(&self, id: u32) -> Option<Entity<&World>> {
+ let entity_data = self.entity_storage.get_by_id(id)?;
+ let entity_ptr = unsafe { entity_data.as_ptr() };
+ Some(Entity::new(self, id, entity_ptr))
+ }
+
+ /// Returns a mutable reference to the entity with the given ID.
+ pub fn entity_mut(&mut self, id: u32) -> Option<Entity<'_, &mut World>> {
+ // no entity for you (we're processing this entity somewhere else)
+ if id != self.entity_storage.owner_entity_id && !self.entity_storage.maybe_update(id) {
+ return None;
+ }
+
+ let entity_data = self.entity_storage.get_by_id(id)?;
+ let entity_ptr = unsafe { entity_data.as_ptr() };
+ Some(Entity::new(self, id, entity_ptr))
+ }
+
+ pub fn entity_by_uuid(&self, uuid: &Uuid) -> Option<Arc<EntityData>> {
+ self.entity_storage.get_by_uuid(uuid)
+ }
+
+ pub fn find_one_entity<F>(&self, mut f: F) -> Option<Arc<EntityData>>
+ where
+ F: FnMut(&EntityData) -> bool,
+ {
+ self.entity_storage.find_one_entity(|entity| f(entity))
+ }
+}
+
+impl WeakWorld {
+ pub fn new(height: u32, min_y: i32) -> Self {
+ WeakWorld {
+ chunk_storage: Arc::new(RwLock::new(WeakChunkStorage::new(height, min_y))),
+ entity_storage: Arc::new(RwLock::new(WeakEntityStorage::new())),
+ }
+ }
+
+ pub fn height(&self) -> u32 {
+ self.chunk_storage.read().height
+ }
+
+ pub fn min_y(&self) -> i32 {
+ self.chunk_storage.read().min_y
+ }
+}
+
+impl Debug for World {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("World")
+ .field("chunk_storage", &self.chunk_storage)
+ .field("entity_storage", &self.entity_storage)
+ .finish()
+ }
+}