2025-11-24 22:52:51 +03:00

94 lines
4.0 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* org.joml.Vector3f
* org.jspecify.annotations.Nullable
*/
package net.minecraft.client.animation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.client.animation.AnimationChannel;
import net.minecraft.client.animation.AnimationDefinition;
import net.minecraft.client.animation.Keyframe;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.AnimationState;
import org.joml.Vector3f;
import org.jspecify.annotations.Nullable;
public class KeyframeAnimation {
private final AnimationDefinition definition;
private final List<Entry> entries;
private KeyframeAnimation(AnimationDefinition definition, List<Entry> entries) {
this.definition = definition;
this.entries = entries;
}
static KeyframeAnimation bake(ModelPart root, AnimationDefinition definition) {
ArrayList<Entry> entries = new ArrayList<Entry>();
Function<String, @Nullable ModelPart> partLookup = root.createPartLookup();
for (Map.Entry<String, List<AnimationChannel>> entry : definition.boneAnimations().entrySet()) {
String partName = entry.getKey();
List<AnimationChannel> channels = entry.getValue();
ModelPart part = partLookup.apply(partName);
if (part == null) {
throw new IllegalArgumentException("Cannot animate " + partName + ", which does not exist in model");
}
for (AnimationChannel channel : channels) {
entries.add(new Entry(part, channel.target(), channel.keyframes()));
}
}
return new KeyframeAnimation(definition, List.copyOf(entries));
}
public void applyStatic() {
this.apply(0L, 1.0f);
}
public void applyWalk(float animationPos, float animationSpeed, float speedFactor, float scaleFactor) {
long time = (long)(animationPos * 50.0f * speedFactor);
float scale = Math.min(animationSpeed * scaleFactor, 1.0f);
this.apply(time, scale);
}
public void apply(AnimationState animationState, float currentTime) {
this.apply(animationState, currentTime, 1.0f);
}
public void apply(AnimationState animationState, float currentTime, float speedFactor) {
animationState.ifStarted(state -> this.apply((long)((float)state.getTimeInMillis(currentTime) * speedFactor), 1.0f));
}
public void apply(long millisSinceStart, float targetScale) {
float secondsSinceStart = this.getElapsedSeconds(millisSinceStart);
Vector3f scratchVector = new Vector3f();
for (Entry entry : this.entries) {
entry.apply(secondsSinceStart, targetScale, scratchVector);
}
}
private float getElapsedSeconds(long millisSinceStart) {
float secondsSinceStart = (float)millisSinceStart / 1000.0f;
return this.definition.looping() ? secondsSinceStart % this.definition.lengthInSeconds() : secondsSinceStart;
}
private record Entry(ModelPart part, AnimationChannel.Target target, Keyframe[] keyframes) {
public void apply(float secondsSinceStart, float targetScale, Vector3f scratchVector) {
int prev = Math.max(0, Mth.binarySearch(0, this.keyframes.length, i -> secondsSinceStart <= this.keyframes[i].timestamp()) - 1);
int next = Math.min(this.keyframes.length - 1, prev + 1);
Keyframe previousFrame = this.keyframes[prev];
Keyframe nextFrame = this.keyframes[next];
float keyframeTimeDelta = secondsSinceStart - previousFrame.timestamp();
float lerpAlpha = next != prev ? Mth.clamp(keyframeTimeDelta / (nextFrame.timestamp() - previousFrame.timestamp()), 0.0f, 1.0f) : 0.0f;
nextFrame.interpolation().apply(scratchVector, lerpAlpha, this.keyframes, prev, next, targetScale);
this.target.apply(this.part, scratchVector);
}
}
}