aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-client/src')
-rw-r--r--azalea-client/src/client.rs72
-rw-r--r--azalea-client/src/movement.rs54
2 files changed, 69 insertions, 57 deletions
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs
index 2b721206..d5071787 100644
--- a/azalea-client/src/client.rs
+++ b/azalea-client/src/client.rs
@@ -25,14 +25,13 @@ use azalea_protocol::{
read::ReadPacketError,
resolver, ServerAddress,
};
-use azalea_world::entity::EntityData;
-use azalea_world::Dimension;
-use log::{debug, error, warn};
-use std::{
- fmt::Debug,
- io,
- sync::{Arc, Mutex},
+use azalea_world::{
+ entity::{EntityData, EntityMut, EntityRef},
+ Dimension,
};
+use log::{debug, error, warn};
+use parking_lot::Mutex;
+use std::{fmt::Debug, io, sync::Arc};
use thiserror::Error;
use tokio::{
io::AsyncWriteExt,
@@ -41,12 +40,14 @@ use tokio::{
time::{self},
};
+/// Events are sent before they're processed, so for example game ticks happen
+/// at the beginning of a tick before anything has happened.
#[derive(Debug, Clone)]
pub enum Event {
Login,
Chat(ChatPacket),
/// A game tick, happens 20 times per second.
- GameTick,
+ Tick,
Packet(Box<ClientboundGamePacket>),
}
@@ -219,7 +220,7 @@ impl Client {
// read the error to see where the issue is
// you might be able to just drop the lock or put it in its own scope to fix
{
- let mut tasks = client.tasks.lock().unwrap();
+ let mut tasks = client.tasks.lock();
tasks.push(tokio::spawn(Self::protocol_loop(
client.clone(),
tx.clone(),
@@ -238,7 +239,7 @@ impl Client {
/// Disconnect from the server, ending all tasks.
pub async fn shutdown(self) -> Result<(), std::io::Error> {
self.write_conn.lock().await.write_stream.shutdown().await?;
- let tasks = self.tasks.lock().unwrap();
+ let tasks = self.tasks.lock();
for task in tasks.iter() {
task.abort();
}
@@ -346,7 +347,7 @@ impl Client {
.as_int()
.expect("min_y tag is not an int");
- let mut dimension_lock = client.dimension.lock().unwrap();
+ let mut dimension_lock = client.dimension.lock();
// the 16 here is our render distance
// i'll make this an actual setting later
*dimension_lock = Dimension::new(16, height, min_y);
@@ -354,7 +355,7 @@ impl Client {
let entity = EntityData::new(client.game_profile.uuid, Vec3::default());
dimension_lock.add_entity(p.player_id, entity);
- let mut player_lock = client.player.lock().unwrap();
+ let mut player_lock = client.player.lock();
player_lock.set_entity_id(p.player_id);
}
@@ -411,11 +412,11 @@ impl Client {
let (new_pos, y_rot, x_rot) = {
let player_entity_id = {
- let player_lock = client.player.lock().unwrap();
+ let player_lock = client.player.lock();
player_lock.entity_id
};
- let mut dimension_lock = client.dimension.lock().unwrap();
+ let mut dimension_lock = client.dimension.lock();
let mut player_entity = dimension_lock
.entity_mut(player_entity_id)
@@ -503,7 +504,7 @@ impl Client {
debug!("Got chunk cache center packet {:?}", p);
client
.dimension
- .lock()?
+ .lock()
.update_view_center(&ChunkPos::new(p.x, p.z));
}
ClientboundGamePacket::LevelChunkWithLight(p) => {
@@ -513,7 +514,7 @@ impl Client {
// debug("chunk {:?}")
client
.dimension
- .lock()?
+ .lock()
.replace_with_packet_data(&pos, &mut p.chunk_data.data.as_slice())
.unwrap();
}
@@ -523,7 +524,7 @@ 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.lock().add_entity(p.id, entity);
}
ClientboundGamePacket::SetEntityData(_p) => {
// debug!("Got set entity data packet {:?}", p);
@@ -540,7 +541,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.lock().add_entity(p.id, entity);
}
ClientboundGamePacket::InitializeBorder(p) => {
debug!("Got initialize border packet {:?}", p);
@@ -561,7 +562,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.lock();
dimension_lock
.set_entity_pos(
@@ -581,14 +582,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.lock();
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.lock();
dimension_lock
.move_entity_with_delta(p.entity_id, &p.delta)
@@ -623,7 +624,7 @@ impl Client {
}
ClientboundGamePacket::BlockUpdate(p) => {
debug!("Got block update packet {:?}", p);
- let mut dimension = client.dimension.lock()?;
+ let mut dimension = client.dimension.lock();
dimension.set_block_state(&p.pos, p.block_state);
}
ClientboundGamePacket::Animate(p) => {
@@ -725,10 +726,12 @@ impl Client {
/// Runs every 50 milliseconds.
async fn game_tick(client: &mut Client, tx: &UnboundedSender<Event>) {
+ tx.send(Event::Tick).unwrap();
+
// return if there's no chunk at the player's position
{
- let dimension_lock = client.dimension.lock().unwrap();
- let player_lock = client.player.lock().unwrap();
+ let dimension_lock = client.dimension.lock();
+ let player_lock = client.player.lock();
let player_entity = player_lock.entity(&dimension_lock);
let player_entity = if let Some(player_entity) = player_entity {
player_entity
@@ -749,8 +752,27 @@ impl Client {
client.ai_step();
// TODO: minecraft does ambient sounds here
+ }
- tx.send(Event::GameTick).unwrap();
+ /// Returns the entity associated to the player.
+ pub fn entity_mut<'d>(&self, dimension: &'d mut Dimension) -> EntityMut<'d> {
+ let entity_id = {
+ let player_lock = self.player.lock();
+ player_lock.entity_id
+ };
+ dimension
+ .entity_mut(entity_id)
+ .expect("Player entity should be in the given dimension")
+ }
+ /// Returns the entity associated to the player.
+ pub fn entity<'d>(&self, dimension: &'d Dimension) -> EntityRef<'d> {
+ let entity_id = {
+ let player_lock = self.player.lock();
+ player_lock.entity_id
+ };
+ dimension
+ .entity(entity_id)
+ .expect("Player entity should be in the given dimension")
}
}
diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs
index ab324370..fb4a5968 100644
--- a/azalea-client/src/movement.rs
+++ b/azalea-client/src/movement.rs
@@ -31,9 +31,9 @@ impl Client {
/// This gets called every tick.
pub async fn send_position(&mut self) -> Result<(), MovePlayerError> {
let packet = {
- let player_lock = self.player.lock().unwrap();
- let mut physics_state = self.physics_state.lock().unwrap();
- let mut dimension_lock = self.dimension.lock().unwrap();
+ let player_lock = self.player.lock();
+ let mut physics_state = self.physics_state.lock();
+ let mut dimension_lock = self.dimension.lock();
let mut player_entity = player_lock
.entity_mut(&mut dimension_lock)
@@ -129,8 +129,8 @@ impl Client {
// Set our current position to the provided Vec3, potentially clipping through blocks.
pub async fn set_pos(&mut self, new_pos: Vec3) -> Result<(), MovePlayerError> {
- let player_lock = self.player.lock().unwrap();
- let mut dimension_lock = self.dimension.lock().unwrap();
+ let player_lock = self.player.lock();
+ let mut dimension_lock = self.dimension.lock();
dimension_lock.set_entity_pos(player_lock.entity_id, new_pos)?;
@@ -138,8 +138,8 @@ impl Client {
}
pub async fn move_entity(&mut self, movement: &Vec3) -> Result<(), MovePlayerError> {
- let mut dimension_lock = self.dimension.lock().unwrap();
- let player = self.player.lock().unwrap();
+ let mut dimension_lock = self.dimension.lock();
+ let player = self.player.lock();
let mut entity = player
.entity_mut(&mut dimension_lock)
@@ -157,25 +157,17 @@ impl Client {
pub fn ai_step(&mut self) {
self.tick_controls(None);
- let player_lock = self.player.lock().unwrap();
- let mut dimension_lock = self.dimension.lock().unwrap();
-
+ let player_lock = self.player.lock();
+ let mut dimension_lock = self.dimension.lock();
let mut player_entity = player_lock
.entity_mut(&mut dimension_lock)
.expect("Player must exist");
// server ai step
{
- let mut physics_state = self.physics_state.lock().unwrap();
+ let physics_state = self.physics_state.lock();
player_entity.xxa = physics_state.left_impulse;
player_entity.zza = physics_state.forward_impulse;
-
- // handle jumping_once
- if physics_state.jumping_once {
- player_entity.jumping = true;
- } else if player_entity.jumping {
- physics_state.jumping_once = false;
- }
}
player_entity.ai_step();
@@ -183,7 +175,7 @@ impl Client {
/// Update the impulse from self.move_direction. The multipler is used for sneaking.
pub(crate) fn tick_controls(&mut self, multiplier: Option<f32>) {
- let mut physics_state = self.physics_state.lock().unwrap();
+ let mut physics_state = self.physics_state.lock();
let mut forward_impulse: f32 = 0.;
let mut left_impulse: f32 = 0.;
@@ -219,31 +211,29 @@ impl Client {
/// Start walking in the given direction.
pub fn walk(&mut self, direction: MoveDirection) {
- let mut physics_state = self.physics_state.lock().unwrap();
+ let mut physics_state = self.physics_state.lock();
physics_state.move_direction = direction;
}
- /// Jump once next tick. This acts as if you pressed space for one tick in
- /// vanilla. If you want to jump continuously, use `set_jumping`.
- pub fn jump(&mut self) {
- let mut physics_state = self.physics_state.lock().unwrap();
- physics_state.jumping_once = true;
- }
-
/// Toggle whether we're jumping. This acts as if you held space in
/// vanilla. If you want to jump once, use the `jump` function.
///
/// If you're making a realistic client, calling this function every tick is
/// recommended.
pub fn set_jumping(&mut self, jumping: bool) {
- let player_lock = self.player.lock().unwrap();
- let mut dimension_lock = self.dimension.lock().unwrap();
- let mut player_entity = player_lock
- .entity_mut(&mut dimension_lock)
- .expect("Player must exist");
+ let mut dimension = self.dimension.lock();
+ let mut player_entity = self.entity_mut(&mut dimension);
player_entity.jumping = jumping;
}
+
+ /// Returns whether the player will try to jump next tick.
+ pub fn jumping(&self) -> bool {
+ let dimension = self.dimension.lock();
+ let player_entity = self.entity(&dimension);
+
+ player_entity.jumping
+ }
}
#[derive(Clone, Copy, Debug, Default)]