From ed0780a03aacebe154ad978cd4b0ead0272bb4f9 Mon Sep 17 00:00:00 2001 From: Riccardo Guerriero Date: Fri, 6 Nov 2026 19:48:41 +0100 Subject: [PATCH] Count collidable entities in auto-jump like vanilla LocalPlayer.updateAutoJump reads Level.getCollisions, which returns the collidable entities' boxes (EntityGetter.getEntityCollisions, query inflated by 1e-7) before the block shapes. Horizon's auto-jump only saw blocks, so walking into a boat, a shulker or a happy ghast never auto-jumped onto it. Co-Authored-By: Codex (gpt-6.1-terra) Co-Authored-By: Claude Opus 5.5 --- crates/horizon-client/src/motion.rs | 43 ++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/crates/horizon-client/src/motion.rs b/crates/horizon-client/src/motion.rs index 64a7f0a769..50c53ae23f 100644 --- a/crates/horizon-client/src/motion.rs +++ b/crates/horizon-client/src/motion.rs @@ -2270,9 +2270,17 @@ impl crate::auto_jump::AutoJumpWorld for MotionWorld<'_, '_, '_> { Ok(binding.collision_shape_with_context(&mut self.collisions(), state, p, &context)?) } fn collision_boxes(&mut self, bounds: Aabb) -> Result> { + // EntityGetter.getEntityCollisions queries with a small inflation, and + // CollisionGetter.getCollisions returns these before block shapes. + let query = bounds.inflate(Vec3::new(1.0e-7, 1.0e-7, 1.0e-7)); + let mut boxes: Vec<_> = self + .entities + .iter() + .copied() + .filter(|b| b.intersects(query)) + .collect(); let context = self.context(); let mut scene = self.collisions(); - let mut boxes = Vec::new(); for hit in horizon_world::block_collision_scan::BlockCollisionScan::new( &mut scene, context, bounds, false, 1_000_000, )? { @@ -3306,6 +3314,39 @@ mod tests { assert_eq!(back.health.health(), 40.0); } + #[test] + #[ignore = "needs prepared resources in HORIZON_TEST_RESOURCES"] + fn auto_jump_detects_collidable_entities() { + let root = std::path::PathBuf::from( + std::env::var_os("HORIZON_TEST_RESOURCES").expect("HORIZON_TEST_RESOURCES"), + ); + let assets = Assets::load(&root).unwrap(); + let render = assets.reload(&root).unwrap(); + let binding = crate::collisions::load(&root, assets.registry).unwrap(); + let resources = MotionResources::load(&root, &assets).unwrap(); + let mut scene = World::test_scene(&assets, &render, 1).unwrap(); + let mut player = PlayerMotion::new(&resources, Vec3::new(10.0, 100.0, 10.0)).unwrap(); + player.auto_jump_enabled = true; + player.ground.on_ground = true; + player.move_vector = [0.0, 1.0]; + let entities = [Aabb::new( + Vec3::new(9.5, 100.0, 10.5), + Vec3::new(10.5, 100.8, 11.5), + )]; + MotionWorld { + entities: &entities, + player: &mut player, + scene: &mut scene, + assets: &assets, + collision_binding: &binding, + resources: &resources, + health: &resources.health, + } + .update_auto_jump(0.0, 0.1) + .unwrap(); + assert_eq!(player.auto_jump_time, 1); + } + #[test] fn player_stands_walks_sneaks_and_jumps_on_ghast() { let root = std::env::var_os("HORIZON_TEST_RESOURCES")