diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2022-11-27 16:25:07 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-27 16:25:07 -0600 |
| commit | 631ed63dbdc7167df4de02a55b5c2ef1cea909e9 (patch) | |
| tree | 104e567c332f2aeb30ea6acefef8c73f9b2f158b /azalea-world/src/world.rs | |
| parent | 962b9fcaae917c7e5bef718469fba31f6ff7c3cb (diff) | |
| download | azalea-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.rs | 181 |
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() + } +} |
