Merge pull request #2007 from rdbtCVS/fix/1962-passenger-animation
🤖 Agent: contrib-gate-17 verified this head (26.3 sources, integration tree build, clippy, tests, parity; details in the PR comment). Thanks @rdbtCVS!
This commit is contained in:
@@ -393,7 +393,7 @@ pub fn main() -> horizon_client::Result<()> {
|
||||
mob.extra.age = -24000;
|
||||
}
|
||||
mob.age = f("ageInTicks") as u32;
|
||||
let state = State {
|
||||
let mut state = State {
|
||||
pos: f("walkAnimationPos"),
|
||||
speed: f("walkAnimationSpeed"),
|
||||
age: f("ageInTicks"),
|
||||
@@ -405,6 +405,20 @@ pub fn main() -> horizon_client::Result<()> {
|
||||
};
|
||||
let mut poses = Poses::new(&model);
|
||||
entity_state(&mut mob, def.species, case);
|
||||
if let Some(ticks) = case["@walkTicks"].as_array() {
|
||||
for speed in ticks {
|
||||
mob.previous_limb_speed = mob.limb_speed;
|
||||
mob.limb_speed += (speed.as_f64().unwrap() as f32 - mob.limb_speed) * 0.4;
|
||||
mob.limb_position += mob.limb_speed;
|
||||
}
|
||||
if !case["@alive"].as_bool().unwrap() {
|
||||
mob.health = 0.0;
|
||||
}
|
||||
let extracted = anim::state(&mob, f("@partial"));
|
||||
state.pos = extracted.pos;
|
||||
state.speed = extracted.speed;
|
||||
}
|
||||
|
||||
let flag = |k: &str| case[k].as_bool().unwrap_or(false);
|
||||
let num = |k: &str| case[k].as_f64().unwrap_or(0.0) as f32;
|
||||
let started = |k: &str| AnimationState {
|
||||
@@ -598,7 +612,11 @@ pub fn main() -> horizon_client::Result<()> {
|
||||
}
|
||||
_ => anim::setup(&mob, s, p, &animations),
|
||||
}
|
||||
out.push_str(&format!("{}\n", emit(&model, &mut poses, case, layer)));
|
||||
let mut result = emit(&model, &mut poses, case, layer);
|
||||
if case["@walkTicks"].is_array() {
|
||||
result["walk"] = json!([state.pos, state.speed]);
|
||||
}
|
||||
out.push_str(&format!("{result}\n"));
|
||||
}
|
||||
fs::write(&args[2], out)?;
|
||||
Ok(())
|
||||
|
||||
@@ -189,14 +189,15 @@ pub fn state(m: &Mob, alpha: f32) -> State {
|
||||
swing += 1.0;
|
||||
}
|
||||
let swing = m.anim.attack_anim_o + swing * alpha;
|
||||
let alive = m.alive();
|
||||
// LivingEntityRenderer.extractRenderState: riding motion is not walking.
|
||||
let walking = m.alive() && !m.extra.passenger;
|
||||
State {
|
||||
pos: if alive {
|
||||
pos: if walking {
|
||||
m.limb_position - m.limb_speed * (1.0 - alpha)
|
||||
} else {
|
||||
0.0
|
||||
},
|
||||
speed: if alive {
|
||||
speed: if walking {
|
||||
(m.previous_limb_speed + (m.limb_speed - m.previous_limb_speed) * alpha).min(1.0)
|
||||
} else {
|
||||
0.0
|
||||
|
||||
@@ -312,6 +312,19 @@ public final class VanillaEntityAnimOracle {
|
||||
state.getClass();
|
||||
for (var entry : kase.entrySet())
|
||||
if (!entry.getKey().startsWith("@")) set(state, entry.getKey(), entry.getValue());
|
||||
if (kase.has("@walkTicks")) {
|
||||
var walk = new net.minecraft.world.entity.WalkAnimationState();
|
||||
for (var speed : kase.getAsJsonArray("@walkTicks"))
|
||||
walk.update(speed.getAsFloat(), 0.4F, 1.0F);
|
||||
// LivingEntity.calculateEntityAnimation stops passengers/dead entities;
|
||||
// LivingEntityRenderer.extractRenderState also zeros both fields.
|
||||
if (kase.get("isPassenger").getAsBoolean() || !kase.get("@alive").getAsBoolean())
|
||||
walk.stop();
|
||||
float partial = kase.get("@partial").getAsFloat();
|
||||
set(state, "walkAnimationPos", gson.toJsonTree(walk.position(partial)));
|
||||
set(state, "walkAnimationSpeed", gson.toJsonTree(walk.speed(partial)));
|
||||
result.add("walk", gson.toJsonTree(new float[]{walk.position(partial), walk.speed(partial)}));
|
||||
}
|
||||
hooks(state, kase);
|
||||
if (state instanceof net.minecraft.client.renderer.entity.state.ArmedEntityRenderState armed && armed.swingAnimation > 0)
|
||||
armed.currentSwing = new net.minecraft.world.entity.LivingEntity.SwingDescription(net.minecraft.world.InteractionHand.MAIN_HAND, net.minecraft.world.item.component.SwingAnimation.DEFAULT, 6);
|
||||
|
||||
@@ -164,6 +164,15 @@ def cases(layer, model=None):
|
||||
cases_out = [{**c, **DEFAULTS.get(name, {})} for c in cases_out]
|
||||
yield from cases_out
|
||||
yield from species_cases(layer, cases_out)
|
||||
# Exercise render-state extraction with a live walk clock, including the
|
||||
# first mounted frame. Existing setupAnim cases bypass anim::state.
|
||||
if name == 'skeleton':
|
||||
for passenger in [False, True]:
|
||||
for alive in [False, True]:
|
||||
for partial in [0.0, 0.5, 1.0]:
|
||||
yield {**cases_out[2], 'isPassenger': passenger,
|
||||
'@walkTicks': [0.5, 1.0, 0.75],
|
||||
'@alive': alive, '@partial': partial}
|
||||
part = model and scaled_part(model)
|
||||
if part:
|
||||
for index, scale in enumerate(PART_SCALES):
|
||||
@@ -387,6 +396,10 @@ def main():
|
||||
skipped.add(layer); continue
|
||||
checked += 1
|
||||
bad = []
|
||||
if 'walk' in v:
|
||||
for a, b in zip(v['walk'], r['walk']):
|
||||
if abs(a - b) > args.tolerance * (1.0 + abs(a)):
|
||||
bad.append(('@walk', f'{v["walk"]} != {r["walk"]}'))
|
||||
for path, expected in v['parts'].items():
|
||||
got = r['parts'].get(path)
|
||||
if got is None:
|
||||
|
||||
Reference in New Issue
Block a user