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:
parent
ba5b7b5cab
commit
13fc403484
8 changed files with 637 additions and 629 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
@ -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),
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue