aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-10-02 14:52:48 -0500
committermat <github@matdoes.dev>2022-10-02 14:52:48 -0500
commit37f9f1c6feda676be30bef31291eaed2a5fc82ce (patch)
tree9e61a94766d0477eeb861165fa721f8b42bb9a85
parentc9b4dccd7eaeed68ce96cf5167916417d0baa6a7 (diff)
downloadazalea-drasl-37f9f1c6feda676be30bef31291eaed2a5fc82ce.tar.xz
add jumping
-rw-r--r--azalea-block/src/behavior.rs18
-rw-r--r--azalea-client/src/client.rs6
-rw-r--r--azalea-client/src/movement.rs32
-rw-r--r--azalea-physics/src/collision/mod.rs2
-rw-r--r--azalea-physics/src/lib.rs79
-rw-r--r--azalea-world/src/entity/mod.rs6
-rw-r--r--bot/src/main.rs6
7 files changed, 145 insertions, 4 deletions
diff --git a/azalea-block/src/behavior.rs b/azalea-block/src/behavior.rs
index db357632..18854fff 100644
--- a/azalea-block/src/behavior.rs
+++ b/azalea-block/src/behavior.rs
@@ -1,7 +1,17 @@
-#[derive(Default)]
pub struct BlockBehavior {
pub has_collision: bool,
pub friction: f32,
+ pub jump_factor: f32,
+}
+
+impl Default for BlockBehavior {
+ fn default() -> Self {
+ Self {
+ has_collision: true,
+ friction: 0.6,
+ jump_factor: 1.0,
+ }
+ }
}
impl BlockBehavior {
@@ -16,4 +26,10 @@ impl BlockBehavior {
self.friction = friction;
self
}
+
+ #[inline]
+ pub fn jump_factor(mut self, jump_factor: f32) -> Self {
+ self.jump_factor = jump_factor;
+ self
+ }
}
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs
index cca932c0..2b721206 100644
--- a/azalea-client/src/client.rs
+++ b/azalea-client/src/client.rs
@@ -85,6 +85,12 @@ pub struct PhysicsState {
pub move_direction: MoveDirection,
pub forward_impulse: f32,
pub left_impulse: f32,
+
+ /// Whether we will jump next tick. This is purely to help with bots,
+ /// realistic clients should change the `jumping` field in the player entity.
+ ///
+ /// TODO: have a convenient way to change the `jumping` field in the player entity.
+ pub jumping_once: bool,
}
/// Whether we should ignore errors when decoding packets.
diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs
index 193f2017..ab324370 100644
--- a/azalea-client/src/movement.rs
+++ b/azalea-client/src/movement.rs
@@ -166,9 +166,16 @@ impl Client {
// server ai step
{
- let physics_state = self.physics_state.lock().unwrap();
+ let mut physics_state = self.physics_state.lock().unwrap();
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();
@@ -210,10 +217,33 @@ impl Client {
}
}
+ /// Start walking in the given direction.
pub fn walk(&mut self, direction: MoveDirection) {
let mut physics_state = self.physics_state.lock().unwrap();
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");
+
+ player_entity.jumping = jumping;
+ }
}
#[derive(Clone, Copy, Debug, Default)]
diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs
index a18440b7..f08e48e3 100644
--- a/azalea-physics/src/collision/mod.rs
+++ b/azalea-physics/src/collision/mod.rs
@@ -133,7 +133,7 @@ impl MovableEntity for EntityMut<'_> {
let horizontal_collision = x_collision || z_collision;
let vertical_collision = movement.y != collide_result.y;
let on_ground = vertical_collision && movement.y < 0.;
- // self.on_ground = on_ground;
+ self.on_ground = on_ground;
// TODO: minecraft checks for a "minor" horizontal collision here
diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs
index 56923577..fe75c71e 100644
--- a/azalea-physics/src/lib.rs
+++ b/azalea-physics/src/lib.rs
@@ -11,6 +11,8 @@ use collision::{MovableEntity, MoverType};
pub trait HasPhysics {
fn travel(&mut self, acceleration: &Vec3);
fn ai_step(&mut self);
+
+ fn jump_from_ground(&mut self);
}
impl HasPhysics for EntityMut<'_> {
@@ -85,6 +87,14 @@ impl HasPhysics for EntityMut<'_> {
self.delta.z = 0.;
}
+ if self.jumping {
+ // TODO: jumping in liquids and jump delay
+
+ if self.on_ground {
+ self.jump_from_ground();
+ }
+ }
+
self.xxa *= 0.98;
self.zza *= 0.98;
@@ -97,6 +107,27 @@ impl HasPhysics for EntityMut<'_> {
// pushEntities
// drowning damage
}
+
+ fn jump_from_ground(&mut self) {
+ let jump_power: f64 = jump_power(self) as f64 + jump_boost_power(self);
+ let old_delta_movement = self.delta;
+ self.delta = Vec3 {
+ x: old_delta_movement.x,
+ y: jump_power,
+ z: old_delta_movement.z,
+ };
+ // if self.sprinting {
+ // let y_rot = self.y_rot * 0.017453292;
+ // self.delta = self.delta
+ // + Vec3 {
+ // x: (-f32::sin(y_rot) * 0.2) as f64,
+ // y: 0.,
+ // z: (f32::cos(y_rot) * 0.2) as f64,
+ // };
+ // }
+
+ // self.has_impulse = true;
+ }
}
fn get_block_pos_below_that_affects_movement(entity: &EntityData) -> BlockPos {
@@ -141,6 +172,54 @@ fn get_speed(entity: &EntityData, friction: f32) -> f32 {
}
}
+/// Returns the what the entity's jump should be multiplied by based on the
+/// block they're standing on.
+fn block_jump_factor(entity: &EntityMut) -> f32 {
+ let block_at_pos = entity.dimension.get_block_state(&entity.pos().into());
+ let block_below = entity
+ .dimension
+ .get_block_state(&get_block_pos_below_that_affects_movement(entity));
+
+ let block_at_pos_jump_factor = if let Some(block) = block_at_pos {
+ Box::<dyn Block>::from(block).behavior().jump_factor
+ } else {
+ 1.
+ };
+ if block_at_pos_jump_factor != 1. {
+ return block_at_pos_jump_factor;
+ }
+
+ if let Some(block) = block_below {
+ Box::<dyn Block>::from(block).behavior().jump_factor
+ } else {
+ 1.
+ }
+}
+
+// protected float getJumpPower() {
+// return 0.42F * this.getBlockJumpFactor();
+// }
+// public double getJumpBoostPower() {
+// return this.hasEffect(MobEffects.JUMP) ? (double)(0.1F * (float)(this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D;
+// }
+fn jump_power(entity: &EntityMut) -> f32 {
+ 0.42 * block_jump_factor(entity)
+}
+
+fn jump_boost_power(_entity: &EntityMut) -> f64 {
+ // TODO: potion effects
+ // if let Some(effects) = entity.effects() {
+ // if let Some(jump_effect) = effects.get(&Effect::Jump) {
+ // 0.1 * (jump_effect.amplifier + 1) as f32
+ // } else {
+ // 0.
+ // }
+ // } else {
+ // 0.
+ // }
+ 0.
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/azalea-world/src/entity/mod.rs b/azalea-world/src/entity/mod.rs
index b9c273f0..37474d1d 100644
--- a/azalea-world/src/entity/mod.rs
+++ b/azalea-world/src/entity/mod.rs
@@ -260,6 +260,10 @@ pub struct EntityData {
pub dimensions: EntityDimensions,
/// The bounding box of the entity. This is more than just width and height, unlike dimensions.
pub bounding_box: AABB,
+
+ /// Whether the entity will try to jump every tick
+ /// (equivalent to the space key being held down in vanilla).
+ pub jumping: bool,
}
impl EntityData {
@@ -291,6 +295,8 @@ impl EntityData {
// TODO: have this be based on the entity type
bounding_box: dimensions.make_bounding_box(&pos),
dimensions,
+
+ jumping: false,
}
}
diff --git a/bot/src/main.rs b/bot/src/main.rs
index 379b3af3..9b2eea1f 100644
--- a/bot/src/main.rs
+++ b/bot/src/main.rs
@@ -18,12 +18,16 @@ async fn handle_event(event: Event, mut bot: Client) -> anyhow::Result<()> {
match event {
Event::Login => {
// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
- bot.walk(MoveDirection::Forward);
+ // bot.walk(MoveDirection::Forward);
+
// loop {
// tokio::time::sleep(std::time::Duration::from_secs(2)).await;
// }
// bot.walk(MoveDirection::None);
}
+ Event::GameTick => {
+ bot.set_jumping(true);
+ }
Event::Packet(_packet) => {}
_ => {}
}