1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

change a bunch of entity things to use the components

This commit is contained in:
mat 2022-12-24 19:21:11 -06:00
parent ba5b7b5cab
commit 13fc403484
8 changed files with 637 additions and 629 deletions

View file

@ -5,13 +5,16 @@ mod shape;
mod world_collisions;
use azalea_core::{Axis, Vec3, AABB, EPSILON};
use azalea_world::entity::{Entity, EntityData};
use azalea_world::{MoveEntityError, WeakWorld};
use azalea_world::{
entity::{self, EntityId},
MoveEntityError, WeakWorld,
};
pub use blocks::BlockWithShape;
pub use discrete_voxel_shape::*;
pub use shape::*;
use std::ops::Deref;
use world_collisions::CollisionGetter;
use self::world_collisions::get_block_collisions;
pub enum MoverType {
Own,
@ -21,189 +24,168 @@ pub enum MoverType {
Shulker,
}
pub trait HasCollision {
fn collide(&self, movement: &Vec3, entity: &EntityData) -> Vec3;
// private Vec3 collide(Vec3 var1) {
// AABB var2 = this.getBoundingBox();
// List var3 = this.level.getEntityCollisions(this,
// var2.expandTowards(var1)); Vec3 var4 = var1.lengthSqr() == 0.0D ?
// var1 : collideBoundingBox(this, var1, var2, this.level, var3);
// boolean var5 = var1.x != var4.x;
// boolean var6 = var1.y != var4.y;
// boolean var7 = var1.z != var4.z;
// boolean var8 = this.onGround || var6 && var1.y < 0.0D;
// if (this.maxUpStep > 0.0F && var8 && (var5 || var7)) {
// Vec3 var9 = collideBoundingBox(this, new Vec3(var1.x,
// (double)this.maxUpStep, var1.z), var2, this.level, var3); Vec3
// var10 = collideBoundingBox(this, new Vec3(0.0D, (double)this.maxUpStep,
// 0.0D), var2.expandTowards(var1.x, 0.0D, var1.z), this.level, var3);
// if (var10.y < (double)this.maxUpStep) {
// Vec3 var11 = collideBoundingBox(this, new Vec3(var1.x, 0.0D,
// var1.z), var2.move(var10), this.level, var3).add(var10); if
// (var11.horizontalDistanceSqr() > var9.horizontalDistanceSqr()) {
// var9 = var11;
// }
// }
// if (var9.horizontalDistanceSqr() > var4.horizontalDistanceSqr()) {
// return var9.add(collideBoundingBox(this, new Vec3(0.0D, -var9.y +
// var1.y, 0.0D), var2.move(var9), this.level, var3)); }
// }
// return var4;
// }
fn collide(movement: &Vec3, world: &WeakWorld, physics: &entity::Physics) -> Vec3 {
let entity_bounding_box = physics.bounding_box;
// TODO: get_entity_collisions
// let entity_collisions = world.get_entity_collisions(self,
// entity_bounding_box.expand_towards(movement));
let entity_collisions = Vec::new();
if movement.length_sqr() == 0.0 {
*movement
} else {
collide_bounding_box(movement, &entity_bounding_box, world, entity_collisions)
}
// TODO: stepping (for stairs and stuff)
// collided_movement
}
pub trait MovableEntity {
fn move_colliding(
&mut self,
mover_type: &MoverType,
movement: &Vec3,
) -> Result<(), MoveEntityError>;
}
/// Move an entity by a given delta, checking for collisions.
pub fn move_colliding(
_mover_type: &MoverType,
movement: &Vec3,
entity_id: EntityId,
world: &WeakWorld,
position: &mut entity::Position,
physics: &mut entity::Physics,
) -> Result<(), MoveEntityError> {
// TODO: do all these
impl<D: Deref<Target = WeakWorld>> HasCollision for D {
// private Vec3 collide(Vec3 var1) {
// AABB var2 = this.getBoundingBox();
// List var3 = this.level.getEntityCollisions(this,
// var2.expandTowards(var1)); Vec3 var4 = var1.lengthSqr() == 0.0D ?
// var1 : collideBoundingBox(this, var1, var2, this.level, var3);
// boolean var5 = var1.x != var4.x;
// boolean var6 = var1.y != var4.y;
// boolean var7 = var1.z != var4.z;
// boolean var8 = this.onGround || var6 && var1.y < 0.0D;
// if (this.maxUpStep > 0.0F && var8 && (var5 || var7)) {
// Vec3 var9 = collideBoundingBox(this, new Vec3(var1.x,
// (double)this.maxUpStep, var1.z), var2, this.level, var3); Vec3
// var10 = collideBoundingBox(this, new Vec3(0.0D, (double)this.maxUpStep,
// 0.0D), var2.expandTowards(var1.x, 0.0D, var1.z), this.level, var3);
// if (var10.y < (double)this.maxUpStep) {
// Vec3 var11 = collideBoundingBox(this, new Vec3(var1.x, 0.0D,
// var1.z), var2.move(var10), this.level, var3).add(var10); if
// (var11.horizontalDistanceSqr() > var9.horizontalDistanceSqr()) {
// var9 = var11;
// }
// }
// if self.no_physics {
// return;
// };
// if (var9.horizontalDistanceSqr() > var4.horizontalDistanceSqr()) {
// return var9.add(collideBoundingBox(this, new Vec3(0.0D, -var9.y +
// var1.y, 0.0D), var2.move(var9), this.level, var3)); }
// if (var1 == MoverType.PISTON) {
// var2 = this.limitPistonMovement(var2);
// if (var2.equals(Vec3.ZERO)) {
// return;
// }
// return var4;
// }
fn collide(&self, movement: &Vec3, entity: &EntityData) -> Vec3 {
let entity_bounding_box = entity.bounding_box;
// TODO: get_entity_collisions
// let entity_collisions = world.get_entity_collisions(self,
// entity_bounding_box.expand_towards(movement));
let entity_collisions = Vec::new();
if movement.length_sqr() == 0.0 {
*movement
} else {
collide_bounding_box(
Some(entity),
movement,
&entity_bounding_box,
self,
entity_collisions,
)
}
// TODO: stepping (for stairs and stuff)
// if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) {
// var2 = var2.multiply(this.stuckSpeedMultiplier);
// this.stuckSpeedMultiplier = Vec3.ZERO;
// this.setDeltaMovement(Vec3.ZERO);
// }
// collided_movement
}
}
// movement = this.maybeBackOffFromEdge(movement, moverType);
impl<D: Deref<Target = WeakWorld>> MovableEntity for Entity<'_, D> {
/// Move an entity by a given delta, checking for collisions.
fn move_colliding(
&mut self,
_mover_type: &MoverType,
movement: &Vec3,
) -> Result<(), MoveEntityError> {
// TODO: do all these
let collide_result = { collide(movement, world, physics) };
// if self.no_physics {
// return;
// };
let move_distance = collide_result.length_sqr();
// if (var1 == MoverType.PISTON) {
// var2 = this.limitPistonMovement(var2);
// if (var2.equals(Vec3.ZERO)) {
// return;
// }
// }
if move_distance > EPSILON {
// TODO: fall damage
// if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) {
// var2 = var2.multiply(this.stuckSpeedMultiplier);
// this.stuckSpeedMultiplier = Vec3.ZERO;
// this.setDeltaMovement(Vec3.ZERO);
// }
// movement = this.maybeBackOffFromEdge(movement, moverType);
let collide_result = { self.world.collide(movement, self) };
let move_distance = collide_result.length_sqr();
if move_distance > EPSILON {
// TODO: fall damage
let new_pos = {
let entity_pos = self.pos();
Vec3 {
x: entity_pos.x + collide_result.x,
y: entity_pos.y + collide_result.y,
z: entity_pos.z + collide_result.z,
}
};
self.world.set_entity_pos(self.id, new_pos)?;
}
let x_collision = movement.x != collide_result.x;
let z_collision = movement.z != collide_result.z;
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;
// TODO: minecraft checks for a "minor" horizontal collision here
let _block_pos_below = self.on_pos_legacy();
// let _block_state_below = self
// .world
// .get_block_state(&block_pos_below)
// .expect("Couldn't get block state below");
// self.check_fall_damage(collide_result.y, on_ground, block_state_below,
// block_pos_below);
// if self.isRemoved() { return; }
if horizontal_collision {
let delta_movement = &self.delta;
self.delta = Vec3 {
x: if x_collision { 0. } else { delta_movement.x },
y: delta_movement.y,
z: if z_collision { 0. } else { delta_movement.z },
let new_pos = {
Vec3 {
x: position.x + collide_result.x,
y: position.y + collide_result.y,
z: position.z + collide_result.z,
}
}
};
if vertical_collision {
// blockBelow.updateEntityAfterFallOn(this.level, this);
// the default implementation of updateEntityAfterFallOn sets the y movement to
// 0
self.delta.y = 0.;
}
if on_ground {
// blockBelow.stepOn(this.level, blockPosBelow, blockStateBelow,
// this);
}
// sounds
// this.tryCheckInsideBlocks();
// float var25 = this.getBlockSpeedFactor();
// this.setDeltaMovement(this.getDeltaMovement().multiply((double)var25, 1.0D,
// (double)var25)); if (this.level.getBlockStatesIfLoaded(this.
// getBoundingBox().deflate(1.0E-6D)).noneMatch((var0) -> {
// return var0.is(BlockTags.FIRE) || var0.is(Blocks.LAVA);
// })) {
// if (this.remainingFireTicks <= 0) {
// this.setRemainingFireTicks(-this.getFireImmuneTicks());
// }
// if (this.wasOnFire && (this.isInPowderSnow ||
// this.isInWaterRainOrBubble())) { this.
// playEntityOnFireExtinguishedSound(); }
// }
// if (this.isOnFire() && (this.isInPowderSnow || this.isInWaterRainOrBubble()))
// { this.setRemainingFireTicks(-this.getFireImmuneTicks());
// }
Ok(())
world.set_entity_pos_from_refs(entity_id, new_pos, position, physics)?;
}
let x_collision = movement.x != collide_result.x;
let z_collision = movement.z != collide_result.z;
let horizontal_collision = x_collision || z_collision;
let vertical_collision = movement.y != collide_result.y;
let on_ground = vertical_collision && movement.y < 0.;
physics.on_ground = on_ground;
// TODO: minecraft checks for a "minor" horizontal collision here
let _block_pos_below = entity::on_pos_legacy(world, position, physics);
// let _block_state_below = self
// .world
// .get_block_state(&block_pos_below)
// .expect("Couldn't get block state below");
// self.check_fall_damage(collide_result.y, on_ground, block_state_below,
// block_pos_below);
// if self.isRemoved() { return; }
if horizontal_collision {
let delta_movement = &physics.delta;
physics.delta = Vec3 {
x: if x_collision { 0. } else { delta_movement.x },
y: delta_movement.y,
z: if z_collision { 0. } else { delta_movement.z },
}
}
if vertical_collision {
// blockBelow.updateEntityAfterFallOn(this.level, this);
// the default implementation of updateEntityAfterFallOn sets the y movement to
// 0
physics.delta.y = 0.;
}
if on_ground {
// blockBelow.stepOn(this.level, blockPosBelow, blockStateBelow,
// this);
}
// sounds
// this.tryCheckInsideBlocks();
// float var25 = this.getBlockSpeedFactor();
// this.setDeltaMovement(this.getDeltaMovement().multiply((double)var25, 1.0D,
// (double)var25)); if (this.level.getBlockStatesIfLoaded(this.
// getBoundingBox().deflate(1.0E-6D)).noneMatch((var0) -> {
// return var0.is(BlockTags.FIRE) || var0.is(Blocks.LAVA);
// })) {
// if (this.remainingFireTicks <= 0) {
// this.setRemainingFireTicks(-this.getFireImmuneTicks());
// }
// if (this.wasOnFire && (this.isInPowderSnow ||
// this.isInWaterRainOrBubble())) { this.
// playEntityOnFireExtinguishedSound(); }
// }
// if (this.isOnFire() && (this.isInPowderSnow || this.isInWaterRainOrBubble()))
// { this.setRemainingFireTicks(-this.getFireImmuneTicks());
// }
Ok(())
}
fn collide_bounding_box(
entity: Option<&EntityData>,
movement: &Vec3,
entity_bounding_box: &AABB,
world: &WeakWorld,
@ -218,7 +200,7 @@ fn collide_bounding_box(
// TODO: world border
let block_collisions =
world.get_block_collisions(entity, entity_bounding_box.expand_towards(movement));
get_block_collisions(world, entity_bounding_box.expand_towards(movement));
let block_collisions = block_collisions.collect::<Vec<_>>();
collision_boxes.extend(block_collisions);
collide_with_shapes(movement, *entity_bounding_box, &collision_boxes)

View file

@ -1,34 +1,17 @@
use super::Shapes;
use crate::collision::{BlockWithShape, VoxelShape, AABB};
use azalea_block::BlockState;
use azalea_core::{ChunkPos, ChunkSectionPos, Cursor3d, CursorIterationType, EPSILON};
use azalea_world::entity::EntityData;
use azalea_world::{Chunk, WeakWorld};
use azalea_world::{entity::EntityId, Chunk, WeakWorld};
use parking_lot::RwLock;
use std::sync::Arc;
use super::Shapes;
pub trait CollisionGetter {
fn get_block_collisions<'a>(
&'a self,
entity: Option<&EntityData>,
aabb: AABB,
) -> BlockCollisions<'a>;
}
impl CollisionGetter for WeakWorld {
fn get_block_collisions<'a>(
&'a self,
entity: Option<&EntityData>,
aabb: AABB,
) -> BlockCollisions<'a> {
BlockCollisions::new(self, entity, aabb)
}
pub fn get_block_collisions<'a>(world: &'a WeakWorld, aabb: AABB) -> BlockCollisions<'a> {
BlockCollisions::new(world, aabb)
}
pub struct BlockCollisions<'a> {
pub world: &'a WeakWorld,
// context: CollisionContext,
pub aabb: AABB,
pub entity_shape: VoxelShape,
pub cursor: Cursor3d,
@ -36,8 +19,7 @@ pub struct BlockCollisions<'a> {
}
impl<'a> BlockCollisions<'a> {
// TODO: the entity is stored in the context
pub fn new(world: &'a WeakWorld, _entity: Option<&EntityData>, aabb: AABB) -> Self {
pub fn new(world: &'a WeakWorld, aabb: AABB) -> Self {
let origin_x = (aabb.min_x - EPSILON) as i32 - 1;
let origin_y = (aabb.min_y - EPSILON) as i32 - 1;
let origin_z = (aabb.min_z - EPSILON) as i32 - 1;

View file

@ -4,154 +4,191 @@ pub mod collision;
use azalea_block::{Block, BlockState};
use azalea_core::{BlockPos, Vec3};
use azalea_world::WeakWorld;
use collision::MoverType;
use azalea_world::{
entity::{self, EntityId},
WeakWorld,
};
use collision::{move_colliding, MoverType};
use std::ops::Deref;
pub trait HasPhysics {
fn travel(&mut self, acceleration: &Vec3);
fn ai_step(&mut self);
/// Move the entity with the given acceleration while handling friction,
/// gravity, collisions, and some other stuff.
fn travel(
entity_id: EntityId,
world: &WeakWorld,
physics: &mut entity::Physics,
position: &mut entity::Position,
attributes: &entity::Attributes,
acceleration: &Vec3,
) {
// if !self.is_effective_ai() && !self.is_controlled_by_local_instance() {
// // this.calculateEntityAnimation(this, this instanceof FlyingAnimal);
// return;
// }
fn jump_from_ground(&mut self);
}
let gravity: f64 = 0.08;
impl<D: Deref<Target = WeakWorld>> HasPhysics for Entity<'_, D> {
/// Move the entity with the given acceleration while handling friction,
/// gravity, collisions, and some other stuff.
fn travel(&mut self, acceleration: &Vec3) {
// if !self.is_effective_ai() && !self.is_controlled_by_local_instance() {
// // this.calculateEntityAnimation(this, this instanceof FlyingAnimal);
// return;
// }
// TODO: slow falling effect
// let is_falling = self.delta.y <= 0.;
let gravity: f64 = 0.08;
// TODO: fluids
// TODO: slow falling effect
// let is_falling = self.delta.y <= 0.;
// TODO: elytra
// TODO: fluids
let block_pos_below = get_block_pos_below_that_affects_movement(position);
// TODO: elytra
let block_state_below = world
.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 block_pos_below = get_block_pos_below_that_affects_movement(self);
let inertia = if physics.on_ground {
block_friction * 0.91
} else {
0.91
};
let block_state_below = self
.world
.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;
// this applies the current delta
let mut movement = handle_relative_friction_and_calculate_movement(
acceleration,
block_friction,
entity_id,
world,
physics,
position,
attributes,
);
let inertia = if self.on_ground {
block_friction * 0.91
} else {
0.91
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.delta = movement;
} else {
physics.delta = Vec3 {
x: movement.x * inertia as f64,
y: movement.y * 0.98f64,
z: movement.z * inertia as f64,
};
// this applies the current delta
let mut movement =
handle_relative_friction_and_calculate_movement(self, acceleration, block_friction);
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 {
self.delta = movement;
} else {
self.delta = Vec3 {
x: movement.x * inertia as f64,
y: movement.y * 0.98f64,
z: movement.z * inertia as f64,
};
}
}
/// applies air resistance, calls self.travel(), and some other random
/// stuff.
fn ai_step(&mut self) {
// vanilla does movement interpolation here, doesn't really matter much for a
// bot though
if self.delta.x.abs() < 0.003 {
self.delta.x = 0.;
}
if self.delta.y.abs() < 0.003 {
self.delta.y = 0.;
}
if self.delta.z.abs() < 0.003 {
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;
self.travel(&Vec3 {
x: self.xxa as f64,
y: self.yya as f64,
z: self.zza as f64,
});
// freezing
// 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.metadata.sprinting {
let y_rot = self.y_rot * 0.017453292;
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 {
/// applies air resistance, calls self.travel(), and some other random
/// stuff.
fn ai_step(
entity_id: EntityId,
world: &WeakWorld,
physics: &mut entity::Physics,
position: &mut entity::Position,
sprinting: &entity::metadata::Sprinting,
attributes: &entity::Attributes,
) {
// vanilla does movement interpolation here, doesn't really matter much for a
// bot though
if physics.delta.x.abs() < 0.003 {
physics.delta.x = 0.;
}
if physics.delta.y.abs() < 0.003 {
physics.delta.y = 0.;
}
if physics.delta.z.abs() < 0.003 {
physics.delta.z = 0.;
}
if physics.jumping {
// TODO: jumping in liquids and jump delay
if physics.on_ground {
jump_from_ground(world, physics, position, sprinting);
}
}
physics.xxa *= 0.98;
physics.zza *= 0.98;
travel(
entity_id,
world,
physics,
position,
attributes,
&Vec3 {
x: physics.xxa as f64,
y: physics.yya as f64,
z: physics.zza as f64,
},
);
// freezing
// pushEntities
// drowning damage
}
fn jump_from_ground(
world: &WeakWorld,
physics: &mut entity::Physics,
position: &entity::Position,
sprinting: &entity::metadata::Sprinting,
) {
let jump_power: f64 = jump_power(world, position) as f64 + jump_boost_power();
let old_delta_movement = physics.delta;
physics.delta = Vec3 {
x: old_delta_movement.x,
y: jump_power,
z: old_delta_movement.z,
};
if **sprinting {
let y_rot = physics.y_rot * 0.017453292;
physics.delta += Vec3 {
x: (-f32::sin(y_rot) * 0.2) as f64,
y: 0.,
z: (f32::cos(y_rot) * 0.2) as f64,
};
}
physics.has_impulse = true;
}
fn get_block_pos_below_that_affects_movement(position: &entity::Position) -> BlockPos {
BlockPos::new(
entity.pos().x.floor() as i32,
position.x.floor() as i32,
// TODO: this uses bounding_box.min_y instead of position.y
(entity.pos().y - 0.5f64).floor() as i32,
entity.pos().z.floor() as i32,
(position.y - 0.5f64).floor() as i32,
position.z.floor() as i32,
)
}
fn handle_relative_friction_and_calculate_movement<D: Deref<Target = WeakWorld>>(
entity: &mut Entity<D>,
fn handle_relative_friction_and_calculate_movement(
acceleration: &Vec3,
block_friction: f32,
entity_id: EntityId,
world: &WeakWorld,
physics: &mut entity::Physics,
position: &mut entity::Position,
attributes: &entity::Attributes,
) -> Vec3 {
entity.move_relative(
get_friction_influenced_speed(&*entity, block_friction),
entity::move_relative(
physics,
get_friction_influenced_speed(physics, attributes, block_friction),
acceleration,
);
// entity.delta = entity.handle_on_climbable(entity.delta);
entity
.move_colliding(&MoverType::Own, &entity.delta.clone())
.expect("Entity should exist.");
move_colliding(
&MoverType::Own,
&physics.delta.clone(),
entity_id,
world,
position,
physics,
)
.expect("Entity should exist.");
// let delta_movement = entity.delta;
// ladders
// if ((entity.horizontalCollision || entity.jumping) && (entity.onClimbable()
@ -160,16 +197,20 @@ fn handle_relative_friction_and_calculate_movement<D: Deref<Target = WeakWorld>>
// Vec3(var3.x, 0.2D, var3.z); }
// TODO: powdered snow
entity.delta
physics.delta
}
// private float getFrictionInfluencedSpeed(float friction) {
// return this.onGround ? this.getSpeed() * (0.21600002F / (friction *
// friction * friction)) : this.flyingSpeed; }
fn get_friction_influenced_speed(entity: &EntityData, friction: f32) -> f32 {
fn get_friction_influenced_speed(
physics: &entity::Physics,
attributes: &entity::Attributes,
friction: f32,
) -> f32 {
// TODO: have speed & flying_speed fields in entity
if entity.on_ground {
let speed: f32 = entity.attributes.speed.calculate() as f32;
if physics.on_ground {
let speed: f32 = attributes.speed.calculate() as f32;
speed * (0.216f32 / (friction * friction * friction))
} else {
// entity.flying_speed
@ -179,11 +220,9 @@ fn get_friction_influenced_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<D: Deref<Target = WeakWorld>>(entity: &Entity<D>) -> f32 {
let block_at_pos = entity.world.get_block_state(&entity.pos().into());
let block_below = entity
.world
.get_block_state(&get_block_pos_below_that_affects_movement(entity));
fn block_jump_factor(world: &WeakWorld, position: &entity::Position) -> f32 {
let block_at_pos = world.get_block_state(&position.into());
let block_below = world.get_block_state(&get_block_pos_below_that_affects_movement(position));
let block_at_pos_jump_factor = if let Some(block) = block_at_pos {
Box::<dyn Block>::from(block).behavior().jump_factor
@ -207,11 +246,11 @@ fn block_jump_factor<D: Deref<Target = WeakWorld>>(entity: &Entity<D>) -> f32 {
// public double getJumpBoostPower() {
// return this.hasEffect(MobEffects.JUMP) ? (double)(0.1F *
// (float)(this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D; }
fn jump_power<D: Deref<Target = WeakWorld>>() -> f32 {
0.42 * block_jump_factor(entity)
fn jump_power(world: &WeakWorld, position: &entity::Position) -> f32 {
0.42 * block_jump_factor(world, position)
}
fn jump_boost_power<D: Deref<Target = WeakWorld>>() -> f64 {
fn jump_boost_power() -> f64 {
// TODO: potion effects
// if let Some(effects) = entity.effects() {
// if let Some(jump_effect) = effects.get(&Effect::Jump) {

View file

@ -11,7 +11,7 @@ use thiserror::Error;
use uuid::{uuid, Uuid};
#[derive(Clone, Debug, Component)]
pub struct AttributeModifiers {
pub struct Attributes {
pub speed: AttributeInstance,
}

File diff suppressed because it is too large Load diff

View file

@ -3,18 +3,12 @@ mod data;
mod dimensions;
pub mod metadata;
use self::{
attributes::{AttributeInstance, AttributeModifiers},
metadata::UpdateMetadataError,
};
use self::{attributes::AttributeInstance, metadata::UpdateMetadataError};
use crate::WeakWorld;
pub use attributes::Attributes;
use azalea_block::BlockState;
use azalea_core::{BlockPos, ChunkPos, Vec3, AABB};
use bevy_ecs::{
bundle::Bundle,
component::Component,
world::{EntityMut, Mut},
};
use bevy_ecs::{bundle::Bundle, component::Component, world::EntityMut};
pub use data::*;
use derive_more::{Deref, DerefMut};
pub use dimensions::EntityDimensions;
@ -162,12 +156,8 @@ pub fn make_bounding_box(pos: &Position, physics: &Physics) -> AABB {
}
/// Get the position of the block below the entity, but a little lower.
pub fn on_pos_legacy<W: Deref<Target = WeakWorld>>(
world: &W,
pos: &Position,
physics: &Physics,
) -> BlockPos {
on_pos(world, pos, physics, 0.2)
pub fn on_pos_legacy(world: &WeakWorld, position: &Position, physics: &Physics) -> BlockPos {
on_pos(world, position, physics, 0.2)
}
// int x = Mth.floor(this.position.x);
@ -182,12 +172,7 @@ pub fn on_pos_legacy<W: Deref<Target = WeakWorld>>(
// }
// }
// return var5;
pub fn on_pos<W: Deref<Target = WeakWorld>>(
world: &W,
pos: &Position,
physics: &Physics,
offset: f32,
) -> BlockPos {
pub fn on_pos(world: &WeakWorld, pos: &Position, physics: &Physics, offset: f32) -> BlockPos {
let x = pos.x.floor() as i32;
let y = (pos.y - offset as f64).floor() as i32;
let z = pos.z.floor() as i32;
@ -225,6 +210,11 @@ impl From<&Position> for ChunkPos {
ChunkPos::from(&value.0)
}
}
impl From<&Position> for BlockPos {
fn from(value: &Position) -> Self {
BlockPos::from(&value.0)
}
}
/// The physics data relating to the entity, such as position, velocity, and
/// bounding box.
@ -275,7 +265,7 @@ pub struct EntityBundle {
pub uuid: EntityUuid,
pub position: Position,
pub physics: Physics,
pub attributes: AttributeModifiers,
pub attributes: Attributes,
}
impl EntityBundle {
@ -315,7 +305,7 @@ impl EntityBundle {
jumping: false,
},
attributes: AttributeModifiers {
attributes: Attributes {
// TODO: do the correct defaults for everything, some
// entities have different defaults
speed: AttributeInstance::new(0.1),

View file

@ -168,6 +168,11 @@ impl WeakWorld {
self.entity_storage.write().query::<Q>()
}
/// Set an entity's position in the world.
///
/// Note that this will access the [`Position`] and [`Physics`] components,
/// so if you already references to those components, you should use
/// [`Self::set_entity_pos_from_refs`] instead.
pub fn set_entity_pos(
&self,
entity_id: EntityId,
@ -179,10 +184,22 @@ impl WeakWorld {
.get_mut(&mut entity_storage.ecs, entity_id.into())
.unwrap();
let old_chunk = ChunkPos::from(pos.as_ref());
self.set_entity_pos_from_refs(entity_id, new_pos, pos.into_inner(), physics.into_inner())
}
/// Set an entity's position in the world when we already have references
/// to the [`Position`] and [`Physics`] components.
pub fn set_entity_pos_from_refs(
&self,
entity_id: EntityId,
new_pos: Vec3,
pos: &mut Position,
physics: &mut Physics,
) -> Result<(), MoveEntityError> {
let old_chunk = ChunkPos::from(&*pos);
let new_chunk = ChunkPos::from(&new_pos);
// this is fine because we update the chunk below
unsafe { move_unchecked(pos.into_inner(), physics.into_inner(), new_pos) };
unsafe { move_unchecked(pos, physics, new_pos) };
if old_chunk != new_chunk {
self.entity_storage
.write()

View file

@ -40,14 +40,12 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
code.append('''// This file is generated from codegen/lib/code/entity.py.
// Don't change it manually!
#![allow(clippy::clone_on_copy, clippy::derivable_impls)]
use super::{
EntityDataValue, OptionalUnsignedInt, Pose, Rotations, VillagerData, EntityDataItem,
};
use super::{EntityDataItem, EntityDataValue, OptionalUnsignedInt, Pose, Rotations, VillagerData};
use azalea_block::BlockState;
use azalea_chat::FormattedText;
use azalea_core::{BlockPos, Direction, Particle, Slot};
use bevy_ecs::{bundle::Bundle, component::Component};
use derive_more::{Deref, DerefMut};
use thiserror::Error;
use uuid::Uuid;
@ -162,14 +160,14 @@ impl From<EntityDataValue> for UpdateMetadataError {
metadata_type_data = metadata_types[type_id]
rust_type = metadata_type_data['type']
code.append(f'#[derive(Component)]')
code.append(f'#[derive(Component, Deref, DerefMut)]')
code.append(f'pub struct {struct_name}(pub {rust_type});')
else:
# if it's a bitfield just make a struct for each bit
for mask, name in name_or_bitfield.items():
name = maybe_rename_field(name, index)
struct_name = upper_first_letter(to_camel_case(name))
code.append(f'#[derive(Component)]')
code.append(f'#[derive(Component, Deref, DerefMut)]')
code.append(f'pub struct {struct_name}(pub bool);')
# add the entity struct and Bundle struct