1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 23:44:38 +00:00
This commit is contained in:
mat 2025-06-16 17:08:09 -06:30
commit f82cf7fa85
4 changed files with 80 additions and 70 deletions

View file

@ -481,6 +481,7 @@ fn update_attributes_for_held_item(
} }
} }
#[allow(clippy::type_complexity)]
fn update_attributes_for_gamemode( fn update_attributes_for_gamemode(
query: Query<(&mut Attributes, &LocalGameMode), (With<LocalEntity>, Changed<LocalGameMode>)>, query: Query<(&mut Attributes, &LocalGameMode), (With<LocalEntity>, Changed<LocalGameMode>)>,
) { ) {

View file

@ -64,18 +64,17 @@ pub fn update_hit_result_component(
}; };
let world = world_lock.read(); let world = world_lock.read();
let aabb = &physics.bounding_box; let hit_result = pick(PickOpts {
let hit_result = pick( source_entity: entity,
entity, look_direction: *look_direction,
*look_direction,
eye_position, eye_position,
aabb, aabb: &physics.bounding_box,
&world, world: &world,
entity_pick_range, entity_pick_range,
block_pick_range, block_pick_range,
&physics_query, physics_query: &physics_query,
&pickable_query, pickable_query: &pickable_query,
); });
if let Some(mut hit_result_ref) = hit_result_ref { if let Some(mut hit_result_ref) = hit_result_ref {
**hit_result_ref = hit_result; **hit_result_ref = hit_result;
} else { } else {
@ -93,6 +92,18 @@ pub type PickableEntityQuery<'world, 'state, 'a> = Query<
(Without<Dead>, Without<Marker>, Without<LocalEntity>), (Without<Dead>, Without<Marker>, Without<LocalEntity>),
>; >;
pub struct PickOpts<'world, 'state, 'a, 'b, 'c> {
source_entity: Entity,
look_direction: LookDirection,
eye_position: Vec3,
aabb: &'a AABB,
world: &'a Instance,
entity_pick_range: f64,
block_pick_range: f64,
physics_query: &'a PhysicsQuery<'world, 'state, 'b>,
pickable_query: &'a PickableEntityQuery<'world, 'state, 'c>,
}
/// Get the block or entity that a player would be looking at if their eyes were /// Get the block or entity that a player would be looking at if their eyes were
/// at the given direction and position. /// at the given direction and position.
/// ///
@ -100,44 +111,40 @@ pub type PickableEntityQuery<'world, 'state, 'a> = Query<
/// [`HitResultComponent`]. /// [`HitResultComponent`].
/// ///
/// Also see [`pick_block`]. /// Also see [`pick_block`].
/// pub fn pick(opts: PickOpts<'_, '_, '_, '_, '_>) -> HitResult {
/// TODO: does not currently check for entities
pub fn pick(
source_entity: Entity,
look_direction: LookDirection,
eye_position: Vec3,
aabb: &AABB,
world: &Instance,
entity_pick_range: f64,
block_pick_range: f64,
physics_query: &PhysicsQuery,
pickable_query: &PickableEntityQuery,
) -> HitResult {
// vanilla does extra math here to calculate the pick result in between ticks by // vanilla does extra math here to calculate the pick result in between ticks by
// interpolating, but since clients can still only interact on exact ticks, that // interpolating, but since clients can still only interact on exact ticks, that
// isn't relevant for us. // isn't relevant for us.
let mut max_range = entity_pick_range.max(block_pick_range); let mut max_range = opts.entity_pick_range.max(opts.block_pick_range);
let mut max_range_squared = max_range.powi(2); let mut max_range_squared = max_range.powi(2);
let block_hit_result = pick_block(look_direction, eye_position, &world.chunks, max_range); let block_hit_result = pick_block(
let block_hit_result_dist_squared = block_hit_result.location.distance_squared_to(eye_position); opts.look_direction,
opts.eye_position,
&opts.world.chunks,
max_range,
);
let block_hit_result_dist_squared = block_hit_result
.location
.distance_squared_to(opts.eye_position);
if !block_hit_result.miss { if !block_hit_result.miss {
max_range_squared = block_hit_result_dist_squared; max_range_squared = block_hit_result_dist_squared;
max_range = block_hit_result_dist_squared.sqrt(); max_range = block_hit_result_dist_squared.sqrt();
} }
let view_vector = view_vector(look_direction); let view_vector = view_vector(opts.look_direction);
let end_position = eye_position + (view_vector * max_range); let end_position = opts.eye_position + (view_vector * max_range);
let inflate_by = 1.; let inflate_by = 1.;
let pick_aabb = aabb let pick_aabb = opts
.aabb
.expand_towards(view_vector * max_range) .expand_towards(view_vector * max_range)
.inflate_all(inflate_by); .inflate_all(inflate_by);
let is_pickable = |entity: Entity| { let is_pickable = |entity: Entity| {
// TODO: ender dragon and projectiles have extra logic here. also, we shouldn't // TODO: ender dragon and projectiles have extra logic here. also, we shouldn't
// be able to pick spectators. // be able to pick spectators.
if let Ok(armor_stand_marker) = pickable_query.get(entity) { if let Ok(armor_stand_marker) = opts.pickable_query.get(entity) {
if let Some(armor_stand_marker) = armor_stand_marker if let Some(armor_stand_marker) = armor_stand_marker
&& armor_stand_marker.0 && armor_stand_marker.0
{ {
@ -149,32 +156,33 @@ pub fn pick(
true true
} }
}; };
let entity_hit_result = pick_entity( let entity_hit_result = pick_entity(PickEntityOpts {
source_entity, source_entity: opts.source_entity,
eye_position, eye_position: opts.eye_position,
end_position, end_position,
world, world: opts.world,
max_range_squared, pick_range_squared: max_range_squared,
&is_pickable, predicate: &is_pickable,
&pick_aabb, aabb: &pick_aabb,
physics_query, physics_query: opts.physics_query,
); });
// TODO
if let Some(entity_hit_result) = entity_hit_result if let Some(entity_hit_result) = entity_hit_result
&& entity_hit_result.location.distance_squared_to(eye_position) && entity_hit_result
.location
.distance_squared_to(opts.eye_position)
< block_hit_result_dist_squared < block_hit_result_dist_squared
{ {
filter_hit_result( filter_hit_result(
HitResult::Entity(entity_hit_result), HitResult::Entity(entity_hit_result),
eye_position, opts.eye_position,
entity_pick_range, opts.entity_pick_range,
) )
} else { } else {
filter_hit_result( filter_hit_result(
HitResult::Block(block_hit_result), HitResult::Block(block_hit_result),
eye_position, opts.eye_position,
block_pick_range, opts.block_pick_range,
) )
} }
} }
@ -213,40 +221,46 @@ pub fn pick_block(
) )
} }
// port of getEntityHitResult struct PickEntityOpts<'world, 'state, 'a, 'b> {
fn pick_entity(
source_entity: Entity, source_entity: Entity,
eye_position: Vec3, eye_position: Vec3,
end_position: Vec3, end_position: Vec3,
world: &azalea_world::Instance, world: &'a azalea_world::Instance,
pick_range_squared: f64, pick_range_squared: f64,
predicate: &dyn Fn(Entity) -> bool, predicate: &'a dyn Fn(Entity) -> bool,
aabb: &AABB, aabb: &'a AABB,
physics_query: &PhysicsQuery, physics_query: &'a PhysicsQuery<'world, 'state, 'b>,
) -> Option<EntityHitResult> { }
let mut picked_distance_squared = pick_range_squared;
// port of getEntityHitResult
fn pick_entity(opts: PickEntityOpts) -> Option<EntityHitResult> {
let mut picked_distance_squared = opts.pick_range_squared;
let mut result = None; let mut result = None;
for (candidate, candidate_aabb) in for (candidate, candidate_aabb) in get_entities(
get_entities(world, Some(source_entity), aabb, predicate, physics_query) opts.world,
{ Some(opts.source_entity),
opts.aabb,
opts.predicate,
opts.physics_query,
) {
// TODO: if the entity is "REDIRECTABLE_PROJECTILE" then this should be 1.0. // TODO: if the entity is "REDIRECTABLE_PROJECTILE" then this should be 1.0.
// azalea needs support for entity tags first for this to be possible. see // azalea needs support for entity tags first for this to be possible. see
// getPickRadius in decompiled minecraft source // getPickRadius in decompiled minecraft source
let candidate_pick_radius = 0.; let candidate_pick_radius = 0.;
let candidate_aabb = candidate_aabb.inflate_all(candidate_pick_radius); let candidate_aabb = candidate_aabb.inflate_all(candidate_pick_radius);
let clip_location = candidate_aabb.clip(eye_position, end_position); let clip_location = candidate_aabb.clip(opts.eye_position, opts.end_position);
if candidate_aabb.contains(eye_position) { if candidate_aabb.contains(opts.eye_position) {
if picked_distance_squared >= 0. { if picked_distance_squared >= 0. {
result = Some(EntityHitResult { result = Some(EntityHitResult {
location: clip_location.unwrap_or(eye_position), location: clip_location.unwrap_or(opts.eye_position),
entity: candidate, entity: candidate,
}); });
picked_distance_squared = 0.; picked_distance_squared = 0.;
} }
} else if let Some(clip_location) = clip_location { } else if let Some(clip_location) = clip_location {
let distance_squared = eye_position.distance_squared_to(clip_location); let distance_squared = opts.eye_position.distance_squared_to(clip_location);
if distance_squared < picked_distance_squared || picked_distance_squared == 0. { if distance_squared < picked_distance_squared || picked_distance_squared == 0. {
// TODO: don't pick the entity we're riding on // TODO: don't pick the entity we're riding on
// if candidate_root_vehicle == entity_root_vehicle { // if candidate_root_vehicle == entity_root_vehicle {

View file

@ -18,7 +18,7 @@ impl HitResult {
pub fn miss(&self) -> bool { pub fn miss(&self) -> bool {
match self { match self {
HitResult::Block(r) => r.miss, HitResult::Block(r) => r.miss,
HitResult::Entity(_) => false, _ => false,
} }
} }
pub fn location(&self) -> Vec3 { pub fn location(&self) -> Vec3 {

View file

@ -6,25 +6,20 @@ use std::{
pub const EPSILON: f64 = 1.0E-7; pub const EPSILON: f64 = 1.0E-7;
pub static SIN: LazyLock<[f32; 65536]> = LazyLock::new(|| { pub static SIN: LazyLock<[f32; 65536]> =
let mut sin = [0.0; 65536]; LazyLock::new(|| std::array::from_fn(|i| f64::sin((i as f64) * PI * 2. / 65536.) as f32));
for (i, item) in sin.iter_mut().enumerate() {
*item = f64::sin((i as f64) * PI * 2.0 / 65536.0) as f32;
}
sin
});
/// A sine function that uses a lookup table. /// A sine function that uses a lookup table.
pub fn sin(x: f32) -> f32 { pub fn sin(x: f32) -> f32 {
let x = x * 10430.378; let x = x * 10430.378;
let x = x as i32 as usize & 65535; let x = x as i32 as usize & 0xFFFF;
SIN[x] SIN[x]
} }
/// A cosine function that uses a lookup table. /// A cosine function that uses a lookup table.
pub fn cos(x: f32) -> f32 { pub fn cos(x: f32) -> f32 {
let x = x * 10430.378 + 16384.0; let x = x * 10430.378 + 16384.;
let x = x as i32 as usize & 65535; let x = x as i32 as usize & 0xFFFF;
SIN[x] SIN[x]
} }