mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-09 02:29:50 -10:00
Endermen teleport inside the world border
LivingEntity.randomTeleport clamps its target with WorldBorder.clampVec3ToBound (Mth.clamp to [min, max - 1.0E-5F] on x and z) before looking for ground; Enderman.teleport skipped it, so an enderman could land outside the border. Refs #7080 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
9e78d076c4
commit
df7f4fbd7c
1 file changed
+60
@@ -84,6 +84,19 @@ pub fn teleport_to(
|
||||
if m.extra.passenger {
|
||||
return false;
|
||||
}
|
||||
// LivingEntity.randomTeleport: WorldBorder.clampVec3ToBound keeps the
|
||||
// target inside the border (Mth.clamp, 1.0E-5F inside the far edges).
|
||||
let (x, z) = match w.border {
|
||||
Some(border) => {
|
||||
let [min_x, min_z, max_x, max_z] = border.bounds(0.0);
|
||||
let clamp = |v: f64, low: f64, high: f64| if v < low { low } else { v.min(high) };
|
||||
(
|
||||
clamp(x, min_x, max_x - f64::from(1.0e-5_f32)),
|
||||
clamp(z, min_z, max_z - f64::from(1.0e-5_f32)),
|
||||
)
|
||||
}
|
||||
None => (x, z),
|
||||
};
|
||||
let (bx, bz) = (x.floor() as i32, z.floor() as i32);
|
||||
if !w.world.loaded(bx, bz) {
|
||||
return false;
|
||||
@@ -583,6 +596,53 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
/// LivingEntity.randomTeleport clamps the target into the world border
|
||||
/// (`WorldBorder.clampVec3ToBound`), so an enderman never lands outside
|
||||
/// it (#7080). A border of size 10 around the origin ends at x = 5.
|
||||
#[test]
|
||||
fn an_enderman_teleports_inside_the_world_border() {
|
||||
let build = |world: &mut crate::world::World, registry: &BlockRegistry| {
|
||||
let stone = registry.default_state("minecraft:stone").unwrap();
|
||||
for cx in -2..2 {
|
||||
for cz in -2..2 {
|
||||
world
|
||||
.chunks
|
||||
.insert((cx, cz), Arc::new(crate::chunk::Chunk::empty(cx, cz)));
|
||||
}
|
||||
}
|
||||
for x in -32..32 {
|
||||
for z in -32..32 {
|
||||
world.set(x, -1, z, stone).unwrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
let border =
|
||||
horizon_core::geometry::border::BorderGeometry::new([0.0, 0.0], 10.0, 29_999_984)
|
||||
.unwrap();
|
||||
crate::mobs::world::with_built_test_world(&[], build, |w, _| {
|
||||
let mut free = enderman();
|
||||
assert!(teleport_to(&mut free, w, 20.5, 0.0, 0.5, &mut Vec::new()));
|
||||
assert_eq!(free.position, Vec3::new(20.5, 0.0, 0.5), "no border");
|
||||
|
||||
let w = MobWorld {
|
||||
border: Some(&border),
|
||||
..w.clone()
|
||||
};
|
||||
let mut bounded = enderman();
|
||||
assert!(teleport_to(
|
||||
&mut bounded,
|
||||
&w,
|
||||
20.5,
|
||||
0.0,
|
||||
-20.5,
|
||||
&mut Vec::new()
|
||||
));
|
||||
// Mth.clamp to [min, max - 1.0E-5F] on x and z.
|
||||
let edge = 5.0 - f64::from(1.0e-5_f32);
|
||||
assert_eq!(bounded.position, Vec3::new(edge, 0.0, -5.0));
|
||||
});
|
||||
}
|
||||
|
||||
/// Enderman.dropCustomDeathLoot (#3513): a killed enderman drops the
|
||||
/// block it carries, mined with a silk touch diamond axe, so a grass
|
||||
/// block comes back as a grass block (not dirt) and a nylium as itself.
|
||||
|
||||
Reference in new issue
Block a user