diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2022-11-12 23:54:05 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-12 23:54:05 -0600 |
| commit | 6eee543a3367d38a6f0e9bffb457a2bd76a8f9cc (patch) | |
| tree | a5e493ccd7ec24293b8d866242c3836146517122 /azalea-client/src/client.rs | |
| parent | fa57d03627aa20b1df44caed7cb025b6db1d9b53 (diff) | |
| download | azalea-drasl-6eee543a3367d38a6f0e9bffb457a2bd76a8f9cc.tar.xz | |
Pathfinder (#25)
Pathfinding is very much not done, but it works enough and I want to get this merged.
TODO: fast replanning, goals that aren't a single node, falling moves (it should be able to play the dropper), parkour moves
Diffstat (limited to 'azalea-client/src/client.rs')
| -rw-r--r-- | azalea-client/src/client.rs | 97 |
1 files changed, 60 insertions, 37 deletions
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index 3d6c8e05..282de48f 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -1,4 +1,4 @@ -use crate::{movement::MoveDirection, Account, Player}; +use crate::{movement::WalkDirection, plugins::Plugins, Account, Player}; use azalea_auth::game_profile::GameProfile; use azalea_chat::Component; use azalea_core::{ChunkPos, ResourceLocation, Vec3}; @@ -28,11 +28,11 @@ use azalea_protocol::{ resolver, ServerAddress, }; use azalea_world::{ - entity::{metadata, EntityData, EntityMetadata, EntityMut, EntityRef}, + entity::{metadata, Entity, EntityData, EntityMetadata}, Dimension, }; use log::{debug, error, info, warn}; -use parking_lot::{Mutex, RwLock}; +use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::{ fmt::Debug, io::{self, Cursor}, @@ -86,10 +86,14 @@ pub struct Client { game_profile: GameProfile, pub read_conn: Arc<tokio::sync::Mutex<ReadConnection<ClientboundGamePacket>>>, pub write_conn: Arc<tokio::sync::Mutex<WriteConnection<ServerboundGamePacket>>>, - pub player: Arc<Mutex<Player>>, - pub dimension: Arc<Mutex<Dimension>>, + pub player: Arc<RwLock<Player>>, + pub dimension: Arc<RwLock<Dimension>>, pub physics_state: Arc<Mutex<PhysicsState>>, pub client_information: Arc<RwLock<ClientInformation>>, + /// Plugins are a way for other crates to add custom functionality to the + /// client and keep state. If you're not making a plugin and you're using + /// the `azalea` crate. you can ignore this field. + pub plugins: Arc<Plugins>, tasks: Arc<Mutex<Vec<JoinHandle<()>>>>, } @@ -97,8 +101,12 @@ pub struct Client { pub struct PhysicsState { /// Minecraft only sends a movement packet either after 20 ticks or if the player moved enough. This is that tick counter. pub position_remainder: u32, + pub was_sprinting: bool, + // Whether we're going to try to start sprinting this tick. Equivalent to + // holding down ctrl for a tick. + pub trying_to_sprint: bool, - pub move_direction: MoveDirection, + pub move_direction: WalkDirection, pub forward_impulse: f32, pub left_impulse: f32, } @@ -253,11 +261,14 @@ impl Client { game_profile, read_conn, write_conn, - player: Arc::new(Mutex::new(Player::default())), - dimension: Arc::new(Mutex::new(Dimension::default())), + player: Arc::new(RwLock::new(Player::default())), + dimension: Arc::new(RwLock::new(Dimension::default())), physics_state: Arc::new(Mutex::new(PhysicsState::default())), - tasks: Arc::new(Mutex::new(Vec::new())), client_information: Arc::new(RwLock::new(ClientInformation::default())), + // The plugins can be modified by the user by replacing the plugins + // field right after this. No Mutex so the user doesn't need to .lock(). + plugins: Arc::new(Plugins::new()), + tasks: Arc::new(Mutex::new(Vec::new())), }; tx.send(Event::Initialize).unwrap(); @@ -403,7 +414,7 @@ impl Client { .as_int() .expect("min_y tag is not an int"); - let mut dimension_lock = client.dimension.lock(); + let mut dimension_lock = client.dimension.write(); // the 16 here is our render distance // i'll make this an actual setting later *dimension_lock = Dimension::new(16, height, min_y); @@ -415,7 +426,7 @@ impl Client { ); dimension_lock.add_entity(p.player_id, entity); - let mut player_lock = client.player.lock(); + let mut player_lock = client.player.write(); player_lock.set_entity_id(p.player_id); } @@ -482,11 +493,11 @@ impl Client { let (new_pos, y_rot, x_rot) = { let player_entity_id = { - let player_lock = client.player.lock(); + let player_lock = client.player.write(); player_lock.entity_id }; - let mut dimension_lock = client.dimension.lock(); + let mut dimension_lock = client.dimension.write(); let mut player_entity = dimension_lock .entity_mut(player_entity_id) @@ -574,7 +585,7 @@ impl Client { debug!("Got chunk cache center packet {:?}", p); client .dimension - .lock() + .write() .update_view_center(&ChunkPos::new(p.x, p.z)); } ClientboundGamePacket::LevelChunkWithLight(p) => { @@ -584,7 +595,7 @@ impl Client { // debug("chunk {:?}") if let Err(e) = client .dimension - .lock() + .write() .replace_with_packet_data(&pos, &mut Cursor::new(&p.chunk_data.data)) { error!("Couldn't set chunk data: {}", e); @@ -596,11 +607,11 @@ impl Client { ClientboundGamePacket::AddEntity(p) => { debug!("Got add entity packet {:?}", p); let entity = EntityData::from(p); - client.dimension.lock().add_entity(p.id, entity); + client.dimension.write().add_entity(p.id, entity); } ClientboundGamePacket::SetEntityData(p) => { debug!("Got set entity data packet {:?}", p); - let mut dimension = client.dimension.lock(); + let mut dimension = client.dimension.write(); if let Some(mut entity) = dimension.entity_mut(p.id) { entity.apply_metadata(&p.packed_items.0); } else { @@ -619,7 +630,7 @@ impl Client { ClientboundGamePacket::AddPlayer(p) => { debug!("Got add player packet {:?}", p); let entity = EntityData::from(p); - client.dimension.lock().add_entity(p.id, entity); + client.dimension.write().add_entity(p.id, entity); } ClientboundGamePacket::InitializeBorder(p) => { debug!("Got initialize border packet {:?}", p); @@ -640,7 +651,7 @@ impl Client { debug!("Got set experience packet {:?}", p); } ClientboundGamePacket::TeleportEntity(p) => { - let mut dimension_lock = client.dimension.lock(); + let mut dimension_lock = client.dimension.write(); dimension_lock .set_entity_pos( @@ -660,14 +671,14 @@ impl Client { // debug!("Got rotate head packet {:?}", p); } ClientboundGamePacket::MoveEntityPos(p) => { - let mut dimension_lock = client.dimension.lock(); + let mut dimension_lock = client.dimension.write(); dimension_lock .move_entity_with_delta(p.entity_id, &p.delta) .map_err(|e| HandleError::Other(e.into()))?; } ClientboundGamePacket::MoveEntityPosRot(p) => { - let mut dimension_lock = client.dimension.lock(); + let mut dimension_lock = client.dimension.write(); dimension_lock .move_entity_with_delta(p.entity_id, &p.delta) @@ -702,7 +713,7 @@ impl Client { } ClientboundGamePacket::BlockUpdate(p) => { debug!("Got block update packet {:?}", p); - let mut dimension = client.dimension.lock(); + let mut dimension = client.dimension.write(); dimension.set_block_state(&p.pos, p.block_state); } ClientboundGamePacket::Animate(p) => { @@ -710,7 +721,7 @@ impl Client { } ClientboundGamePacket::SectionBlocksUpdate(p) => { debug!("Got section blocks update packet {:?}", p); - let mut dimension = client.dimension.lock(); + let mut dimension = client.dimension.write(); for state in &p.states { dimension.set_block_state(&(p.section_pos + state.pos.clone()), state.state); } @@ -808,8 +819,8 @@ impl Client { async fn game_tick(client: &mut Client, tx: &UnboundedSender<Event>) { // return if there's no chunk at the player's position { - let dimension_lock = client.dimension.lock(); - let player_lock = client.player.lock(); + let dimension_lock = client.dimension.write(); + let player_lock = client.player.write(); let player_entity = player_lock.entity(&dimension_lock); let player_entity = if let Some(player_entity) = player_entity { player_entity @@ -835,30 +846,42 @@ impl Client { } /// Returns the entity associated to the player. - pub fn entity_mut<'d>(&self, dimension: &'d mut Dimension) -> EntityMut<'d> { + pub fn entity_mut(&self) -> Entity<RwLockWriteGuard<Dimension>> { let entity_id = { - let player_lock = self.player.lock(); + let player_lock = self.player.write(); player_lock.entity_id }; - dimension - .entity_mut(entity_id) - .expect("Player entity should be in the given dimension") + + let mut dimension = self.dimension.write(); + + let entity_data = dimension + .entity_storage + .get_mut_by_id(entity_id) + .expect("Player entity should exist"); + let entity_ptr = unsafe { entity_data.as_ptr() }; + Entity::new(dimension, entity_id, entity_ptr) } /// Returns the entity associated to the player. - pub fn entity<'d>(&self, dimension: &'d Dimension) -> EntityRef<'d> { + pub fn entity(&self) -> Entity<RwLockReadGuard<Dimension>> { let entity_id = { - let player_lock = self.player.lock(); + let player_lock = self.player.read(); player_lock.entity_id }; - dimension - .entity(entity_id) - .expect("Player entity should be in the given dimension") + + let dimension = self.dimension.read(); + + let entity_data = dimension + .entity_storage + .get_by_id(entity_id) + .expect("Player entity should be in the given dimension"); + let entity_ptr = unsafe { entity_data.as_const_ptr() }; + Entity::new(dimension, entity_id, entity_ptr) } /// Returns whether we have a received the login packet yet. pub fn logged_in(&self) -> bool { - let dimension = self.dimension.lock(); - let player = self.player.lock(); + let dimension = self.dimension.read(); + let player = self.player.write(); player.entity(&dimension).is_some() } |
