1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 23:44:38 +00:00

different travel function in water

This commit is contained in:
mat 2025-01-09 11:08:09 +00:00
commit 63b4406af2
8 changed files with 288 additions and 93 deletions

View file

@ -325,8 +325,8 @@ pub fn local_player_ai_step(
) {
for (physics_state, mut physics, mut sprinting, mut attributes) in query.iter_mut() {
// server ai step
physics.xxa = physics_state.left_impulse;
physics.zza = physics_state.forward_impulse;
physics.x_acceleration = physics_state.left_impulse;
physics.z_acceleration = physics_state.forward_impulse;
// TODO: food data and abilities
// let has_enough_food_to_sprint = self.food_data().food_level ||

View file

@ -11,6 +11,7 @@ use thiserror::Error;
pub struct Attributes {
pub speed: AttributeInstance,
pub attack_speed: AttributeInstance,
pub water_movement_efficiency: AttributeInstance,
}
#[derive(Clone, Debug)]

View file

@ -257,12 +257,14 @@ pub struct Physics {
pub velocity: Vec3,
pub vec_delta_codec: VecDeltaCodec,
/// X acceleration.
pub xxa: f32,
/// Y acceleration.
pub yya: f32,
/// Z acceleration.
pub zza: f32,
/// The acceleration here is the force that will be attempted to be added to
/// the entity's velocity next tick.
///
/// You should typically not set this yourself, since it's controlled by how
/// the entity is trying to move.
pub x_acceleration: f32,
pub y_acceleration: f32,
pub z_acceleration: f32,
on_ground: bool,
last_on_ground: bool,
@ -295,9 +297,9 @@ impl Physics {
velocity: Vec3::default(),
vec_delta_codec: VecDeltaCodec::new(pos),
xxa: 0.,
yya: 0.,
zza: 0.,
x_acceleration: 0.,
y_acceleration: 0.,
z_acceleration: 0.,
on_ground: false,
last_on_ground: false,
@ -345,6 +347,14 @@ impl Physics {
pub fn clear_fire(&mut self) {
self.remaining_fire_ticks = 0;
}
pub fn is_in_water(&self) -> bool {
self.was_touching_water
}
pub fn is_in_lava(&self) -> bool {
// TODO: also check `!this.firstTick &&`
self.lava_fluid_height > 0.
}
}
/// Marker component for entities that are dead.
@ -444,6 +454,7 @@ impl EntityBundle {
// entities have different defaults
speed: AttributeInstance::new(0.1),
attack_speed: AttributeInstance::new(4.0),
water_movement_efficiency: AttributeInstance::new(0.0),
},
jumping: Jumping(false),

View file

@ -22,6 +22,7 @@ use tracing::warn;
use self::world_collisions::get_block_collisions;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MoverType {
Own,
Player,
@ -143,8 +144,10 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
}
/// Move an entity by a given delta, checking for collisions.
///
/// In Mojmap, this is `Entity.move`.
pub fn move_colliding(
_mover_type: &MoverType,
_mover_type: MoverType,
movement: &Vec3,
world: &Instance,
position: &mut Mut<azalea_entity::Position>,

View file

@ -25,15 +25,11 @@ pub fn update_in_water_state_and_do_fluid_pushing(
.expect("All entities should be in a valid world");
let world = world_lock.read();
println!("update_in_water_state_and_do_fluid_pushing");
physics.water_fluid_height = 0.;
physics.lava_fluid_height = 0.;
update_in_water_state_and_do_water_current_pushing(&mut physics, &world, &position);
println!("physics.water_fluid_height: {}", physics.water_fluid_height);
// let lava_push_factor = world
// .registries
// .dimension_type()
@ -117,10 +113,6 @@ fn update_fluid_height_and_do_fluid_pushing(
}
let mut additional_player_delta_for_fluid =
get_fluid_flow(&fluid_at_cur_pos, world, cur_pos);
println!(
"additional_player_delta_for_fluid: {}",
additional_player_delta_for_fluid
);
if min_height_touching < 0.4 {
additional_player_delta_for_fluid *= min_height_touching;
};
@ -131,9 +123,6 @@ fn update_fluid_height_and_do_fluid_pushing(
}
}
println!("num_fluids_being_touched: {}", num_fluids_being_touched);
println!("additional_player_delta: {}", additional_player_delta);
if additional_player_delta.length() > 0. {
additional_player_delta /= num_fluids_being_touched as f64;
@ -180,10 +169,6 @@ pub fn get_fluid_flow(fluid: &FluidState, world: &Instance, pos: BlockPos) -> Ve
.get_fluid_state(&adjacent_block_pos)
.unwrap_or_default();
if fluid.affects_flow(&adjacent_fluid_state) {
println!(
"affects flow {adjacent_block_pos} {:?}",
adjacent_fluid_state
);
let mut adjacent_fluid_height = adjacent_fluid_state.height();
let mut adjacent_height_difference: f32 = 0.;

View file

@ -7,6 +7,7 @@ pub mod fluids;
use azalea_block::{Block, BlockState};
use azalea_core::{
aabb::AABB,
math,
position::{BlockPos, Vec3},
tick::GameTick,
@ -84,76 +85,265 @@ fn travel(
continue;
};
let world = world_lock.read();
// if !self.is_effective_ai() && !self.is_controlled_by_local_instance() {
// // this.calculateEntityAnimation(this, this instanceof FlyingAnimal);
// return;
// }
let gravity: f64 = 0.08;
let sprinting = *sprinting.unwrap_or(&Sprinting(false));
// TODO: slow falling effect
// let is_falling = self.delta.y <= 0.;
// TODO: elytras
let block_position = BlockPos::from(**position);
// LivingEntity.travel
let fluid_state = world.chunks.get_fluid_state(&block_position);
// TODO: fluids
// TODO: elytra
let block_pos_below = get_block_pos_below_that_affects_movement(&position);
let block_state_below = world
.chunks
.get_block_state(&block_pos_below)
.unwrap_or(BlockState::AIR);
let block_below: Box<dyn Block> = block_state_below.into();
let block_friction = block_below.behavior().friction;
let inertia = if physics.on_ground() {
block_friction * 0.91
} else {
0.91
};
// this applies the current delta
let mut movement = handle_relative_friction_and_calculate_movement(
HandleRelativeFrictionAndCalculateMovementOpts {
block_friction,
world: &world,
physics: &mut physics,
direction: &direction,
if physics.is_in_water() || physics.is_in_lava() {
// minecraft also checks for `this.isAffectedByFluids() &&
// !this.canStandOnFluid(fluidAtBlock)` here but it doesn't matter
// for players
travel_in_fluid(
&mut physics,
&direction,
position,
attributes,
is_sprinting: sprinting.map(|s| **s).unwrap_or(false),
sprinting,
on_climbable,
pose,
jumping,
},
);
movement.y -= gravity;
// if (this.shouldDiscardFriction()) {
// this.setDeltaMovement(movement.x, yMovement, movement.z);
// } else {
// this.setDeltaMovement(movement.x * (double)inertia, yMovement *
// 0.9800000190734863D, movement.z * (double)inertia); }
// if should_discard_friction(self) {
if false {
physics.velocity = movement;
&world,
);
} else {
physics.velocity = Vec3 {
x: movement.x * inertia as f64,
y: movement.y * 0.9800000190734863f64,
z: movement.z * inertia as f64,
};
travel_in_air(
&mut physics,
&direction,
position,
&attributes,
sprinting,
&on_climbable,
pose,
&jumping,
&world,
);
}
}
}
/// The usual movement when we're not in water or using an elytra.
fn travel_in_air(
physics: &mut Physics,
direction: &LookDirection,
position: Mut<Position>,
attributes: &Attributes,
sprinting: Sprinting,
on_climbable: &OnClimbable,
pose: Option<&Pose>,
jumping: &Jumping,
world: &Instance,
) {
let gravity = get_effective_gravity();
// LivingEntity.travel starts here
// TODO: fluids
// TODO: elytra
let block_pos_below = get_block_pos_below_that_affects_movement(&position);
let block_state_below = world
.chunks
.get_block_state(&block_pos_below)
.unwrap_or(BlockState::AIR);
let block_below: Box<dyn Block> = block_state_below.into();
let block_friction = block_below.behavior().friction;
let inertia = if physics.on_ground() {
block_friction * 0.91
} else {
0.91
};
// this applies the current delta
let mut movement = handle_relative_friction_and_calculate_movement(
HandleRelativeFrictionAndCalculateMovementOpts {
block_friction,
world: &world,
physics,
direction: &direction,
position,
attributes,
is_sprinting: *sprinting,
on_climbable,
pose,
jumping,
},
);
movement.y -= gravity;
// if (this.shouldDiscardFriction()) {
// this.setDeltaMovement(movement.x, yMovement, movement.z);
// } else {
// this.setDeltaMovement(movement.x * (double)inertia, yMovement *
// 0.9800000190734863D, movement.z * (double)inertia); }
// if should_discard_friction(self) {
if false {
physics.velocity = movement;
} else {
physics.velocity = Vec3 {
x: movement.x * inertia as f64,
y: movement.y * 0.9800000190734863f64,
z: movement.z * inertia as f64,
};
}
}
fn travel_in_fluid(
physics: &mut Physics,
direction: &LookDirection,
mut position: Mut<Position>,
attributes: &Attributes,
sprinting: Sprinting,
on_climbable: &OnClimbable,
pose: Option<&Pose>,
jumping: &Jumping,
world: &Instance,
) {
let moving_down = physics.velocity.y <= 0.;
let y = position.y;
let gravity = get_effective_gravity();
let acceleration = Vec3::new(
physics.x_acceleration as f64,
physics.y_acceleration as f64,
physics.z_acceleration as f64,
);
if physics.was_touching_water {
let mut water_movement_speed = if *sprinting { 0.9 } else { 0.8 };
let mut speed = 0.02;
let mut water_efficiency_modifier = attributes.water_movement_efficiency.calculate() as f32;
if !physics.on_ground() {
water_efficiency_modifier *= 0.5;
}
if water_efficiency_modifier > 0. {
water_movement_speed += (0.54600006 - water_movement_speed) * water_efficiency_modifier;
speed += (attributes.speed.calculate() as f32 - speed) * water_efficiency_modifier;
}
// if (this.hasEffect(MobEffects.DOLPHINS_GRACE)) {
// waterMovementSpeed = 0.96F;
// }
move_relative(physics, direction, speed, &acceleration);
move_colliding(
MoverType::Own,
&physics.velocity.clone(),
world,
&mut position,
physics,
)
.expect("Entity should exist");
let mut new_velocity = physics.velocity;
if physics.horizontal_collision && **on_climbable {
// underwater ladders
new_velocity.y = 0.2;
}
new_velocity.x *= water_movement_speed as f64;
new_velocity.y *= 0.8;
new_velocity.z *= water_movement_speed as f64;
physics.velocity =
get_fluid_falling_adjusted_movement(gravity, moving_down, new_velocity, sprinting);
} else {
move_relative(physics, direction, 0.02, &acceleration);
move_colliding(
MoverType::Own,
&physics.velocity.clone(),
world,
&mut position,
physics,
)
.expect("Entity should exist");
if physics.lava_fluid_height <= fluid_jump_threshold() {
physics.velocity.x *= 0.5;
physics.velocity.y *= 0.8;
physics.velocity.z *= 0.5;
let new_velocity = get_fluid_falling_adjusted_movement(
gravity,
moving_down,
physics.velocity,
sprinting,
);
physics.velocity = new_velocity;
} else {
physics.velocity *= 0.5;
}
if gravity != 0.0 {
physics.velocity.y -= gravity / 4.0;
}
}
let velocity = physics.velocity;
if physics.horizontal_collision
&& is_free(
physics.bounding_box,
world,
velocity.x,
velocity.y + 0.6 - position.y + y,
velocity.z,
)
{
physics.velocity.y = 0.3;
}
}
fn get_fluid_falling_adjusted_movement(
gravity: f64,
moving_down: bool,
new_velocity: Vec3,
sprinting: Sprinting,
) -> Vec3 {
if gravity != 0. && !*sprinting {
let new_y_velocity;
if moving_down
&& (new_velocity.y - 0.005).abs() >= 0.003
&& f64::abs(new_velocity.y - gravity / 16.0) < 0.003
{
new_y_velocity = -0.003;
} else {
new_y_velocity = new_velocity.y - gravity / 16.0;
}
Vec3 {
x: new_velocity.x,
y: new_y_velocity,
z: new_velocity.z,
}
} else {
new_velocity
}
}
fn is_free(bounding_box: AABB, world: &Instance, x: f64, y: f64, z: f64) -> bool {
// let bounding_box = bounding_box.move_relative(Vec3::new(x, y, z));
let _ = (bounding_box, world, x, y, z);
// TODO: implement this, see Entity.isFree
true
}
fn get_effective_gravity() -> f64 {
// TODO: slow falling effect
0.08
}
fn fluid_jump_threshold() -> f64 {
// this is 0.0 for entities with an eye height lower than 0.4, but that's not
// implemented since it's usually not relevant for players (unless the player
// was shrunk)
0.4
}
/// applies air resistance, calls self.travel(), and some other random
/// stuff.
#[allow(clippy::type_complexity)]
@ -202,8 +392,8 @@ pub fn ai_step(
}
}
physics.xxa *= 0.98;
physics.zza *= 0.98;
physics.x_acceleration *= 0.98;
physics.z_acceleration *= 0.98;
// TODO: freezing, pushEntities, drowning damage (in their own systems,
// after `travel`)
@ -285,22 +475,22 @@ fn handle_relative_friction_and_calculate_movement(
direction,
get_friction_influenced_speed(physics, attributes, block_friction, is_sprinting),
&Vec3 {
x: physics.xxa as f64,
y: physics.yya as f64,
z: physics.zza as f64,
x: physics.x_acceleration as f64,
y: physics.y_acceleration as f64,
z: physics.z_acceleration as f64,
},
);
physics.velocity = handle_on_climbable(physics.velocity, on_climbable, &position, world, pose);
move_colliding(
&MoverType::Own,
MoverType::Own,
&physics.velocity.clone(),
world,
&mut position,
physics,
)
.expect("Entity should exist.");
.expect("Entity should exist");
// let delta_movement = entity.delta;
// ladders
// if ((entity.horizontalCollision || entity.jumping) && (entity.onClimbable()

View file

@ -89,8 +89,12 @@ pub struct Instance {
/// An index of all the entities we know are in the chunks of the world
pub entities_by_chunk: HashMap<ChunkPos, HashSet<Entity>>,
/// An index of Minecraft entity IDs to Azalea ECS entities. You should
/// avoid using this and instead use `azalea_entity::EntityIdIndex`
/// An index of Minecraft entity IDs to Azalea ECS entities.
///
/// You should avoid using this (particularly if you're using swarms) and
/// instead use `azalea_entity::EntityIdIndex`, since some servers may
/// give different entity IDs for the same entities to different
/// players.
pub entity_by_id: IntMap<MinecraftEntityId, Entity>,
pub registries: RegistryHolder,

View file

@ -38,6 +38,7 @@ impl SimulatedPlayerBundle {
attributes: Attributes {
speed: AttributeInstance::new(0.1),
attack_speed: AttributeInstance::new(4.0),
water_movement_efficiency: AttributeInstance::new(0.0),
},
inventory: Inventory::default(),
}