mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Your body keeps up with the camera at Levitation 255
The third-person model dropped its interpolation whenever it moved more than 10 blocks in a tick, while the camera kept lerping from the old position. Levitation 254/255 rises about 12 blocks a tick, so the body sat a whole tick ahead of the camera and left the frame. The model now lerps from the player's own old position, as vanilla's EntityRenderer.extractRenderState does from Entity.xOld/yOld/zOld, the same one Camera.setup uses. Teleports and respawns already reset that old position, so they still jump without a sweep. Fixes #3616 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
224b99b724
commit
14d453048e
1 file changed
+48
-15
@@ -377,6 +377,7 @@ impl Game<'_> {
|
||||
let riding = self.riding.is_some();
|
||||
let hurt = p.health.hurt_animation_time;
|
||||
let avatar = self.avatar;
|
||||
let previous_position = self.previous_position;
|
||||
// LivingEntity.getBedOrientation: the model lies in the bed as
|
||||
// another player's does (`villager::sleep_pose`).
|
||||
let bed = self.sleeping.map_or(0, |head| self.bed_facing(head));
|
||||
@@ -385,22 +386,13 @@ impl Game<'_> {
|
||||
};
|
||||
m.extra.ints[1] = bed;
|
||||
m.extra.model_scale = scale;
|
||||
let at = Vec3::new(
|
||||
position.x,
|
||||
position.y - if crouching { 0.125 } else { 0.0 },
|
||||
position.z,
|
||||
);
|
||||
let (dx, dy, dz) = (
|
||||
at.x - m.position.x,
|
||||
at.y - m.position.y,
|
||||
at.z - m.position.z,
|
||||
);
|
||||
let walked = player_walk_distance(m.position, at);
|
||||
m.previous = m.position;
|
||||
// The crouch flag is still last tick's here.
|
||||
let (from, at) =
|
||||
player_model_positions(previous_position, position, m.extra.crouching, crouching);
|
||||
m.previous = from;
|
||||
m.position = at;
|
||||
if dx * dx + dy * dy + dz * dz > 100.0 {
|
||||
m.previous = at;
|
||||
}
|
||||
let (dx, dz) = (at.x - m.previous.x, at.z - m.previous.z);
|
||||
let walked = player_walk_distance(m.previous, at);
|
||||
m.previous_yaw = m.yaw;
|
||||
m.previous_body_yaw = m.body_yaw;
|
||||
m.previous_head_yaw = m.head_yaw;
|
||||
@@ -851,6 +843,27 @@ fn player_preview_quads(
|
||||
quads
|
||||
}
|
||||
|
||||
/// The player's model's old and new positions for a tick: the player's old
|
||||
/// (`Entity.xo`, `yo`, `zo`) and new positions, each 0.125 lower while
|
||||
/// crouching. The model is the player itself in vanilla, so
|
||||
/// `EntityRenderer.extractRenderState` lerps it from the same old position
|
||||
/// `Camera.setup` does, however far it moved: at Levitation 255 (12.75 blocks
|
||||
/// a tick) the body keeps up with the camera. A teleport or respawn resets
|
||||
/// the old position, and the model jumps with it.
|
||||
fn player_model_positions(
|
||||
previous_position: Vec3,
|
||||
position: Vec3,
|
||||
was_crouching: bool,
|
||||
crouching: bool,
|
||||
) -> (Vec3, Vec3) {
|
||||
let drop =
|
||||
|p: Vec3, crouching: bool| Vec3::new(p.x, p.y - if crouching { 0.125 } else { 0.0 }, p.z);
|
||||
(
|
||||
drop(previous_position, was_crouching),
|
||||
drop(position, crouching),
|
||||
)
|
||||
}
|
||||
|
||||
/// The distance `LivingEntity.calculateEntityAnimation` walks the player's
|
||||
/// model for a move from `from` to `to`. `omnidirectionalAirMover()` is false
|
||||
/// for every player (`Entity`'s, not overridden), so only the horizontal
|
||||
@@ -865,6 +878,26 @@ fn player_walk_distance(from: Vec3, to: Vec3) -> f32 {
|
||||
mod preview_tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn the_player_model_rises_with_the_camera_at_levitation_255() {
|
||||
// LivingEntity.travel at Levitation 255: 0.05 * 255 blocks a tick.
|
||||
let from = Vec3::new(0.5, 80.0, 0.5);
|
||||
let to = Vec3::new(0.5, 92.75, 0.5);
|
||||
// The camera lerps from the old position: so does the body.
|
||||
assert_eq!(
|
||||
player_model_positions(from, to, false, false),
|
||||
(from, to),
|
||||
"the body jumps instead of rising (#3616)"
|
||||
);
|
||||
// Any distance, crouching on both ends.
|
||||
let far = Vec3::new(40.5, 80.0, 0.5);
|
||||
assert_eq!(
|
||||
player_model_positions(from, far, true, true),
|
||||
(Vec3::new(0.5, 79.875, 0.5), Vec3::new(40.5, 79.875, 0.5)),
|
||||
);
|
||||
// A teleport resets the old position to the new one: no sweep.
|
||||
assert_eq!(player_model_positions(to, to, false, false), (to, to));
|
||||
}
|
||||
#[test]
|
||||
fn flying_straight_up_does_not_walk_the_player_model() {
|
||||
let from = Vec3::new(0.5, 80.0, 0.5);
|
||||
// Creative flight straight up (#3302) and straight down.
|
||||
|
||||
Reference in new issue
Block a user