Skip to content

Commit

Permalink
Add AnimationUtils#animateSmoothly
Browse files Browse the repository at this point in the history
  • Loading branch information
FirstMegaGame4 committed Apr 19, 2024
1 parent 6d09912 commit 89a9f4a
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ public class AnimationData {
public final AnimationState falling = new AnimationState();
public final AnimationState dodge = new AnimationState();

public int transitionAge;
public int transitionCount;

public int fallingAge;
public int fallingCount;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mmodding.mmodding_lib.library.client.render.entity.animation;

import com.mmodding.mmodding_lib.library.client.utils.AnimationUtils;
import com.mmodding.mmodding_lib.mixin.accessors.SinglePartEntityModelAccessor;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.animation.Animation;
import net.minecraft.client.render.entity.model.SinglePartEntityModel;
Expand All @@ -15,6 +16,8 @@ public class AnimationManager {
private final Animation falling;
private final Animation dodge;

private Animation animationCache = null;

public AnimationManager(SinglePartEntityModel<?> model, Animation moving, Animation idle, Animation falling, Animation dodge) {
this.model = model;
this.moving = moving;
Expand All @@ -35,25 +38,53 @@ private void updateFall(AnimationData data, int age, GroundChecker groundChecker
}
}

private void switchAnimation(Animation animation, AnimationState state, float animationProgress) {
private void smoothTransition(Animation animation, AnimationState state, float animationProgress, int smooth) {
state.method_43686(animationProgress, 1.0f);
state.animateIfValid(current -> AnimationUtils.animateSmoothly(this.model, animation, this.animationCache, current.method_43687(), 1.0f, SinglePartEntityModelAccessor.getField39195(), smooth));
}

private void transition(Animation animation, AnimationState state, float animationProgress) {
this.animationCache = animation;
AnimationUtils.updateAnimation(this.model, animation, state, animationProgress);
// data.transition = 20;
}

private void switchAnimation(AnimationData data, Animation animation, AnimationState state, float animationProgress, int age) {
if (animation != null) {
if (data.transitionCount != 0) {
if (data.transitionAge != age) {
data.transitionAge = age;
data.transitionCount--;
}
this.smoothTransition(animation, state, animationProgress, data.transitionCount);
}
else if (this.animationCache != null && this.animationCache != animation) {
data.transitionAge = age;
data.transitionCount = 60;
this.smoothTransition(animation, state, animationProgress, data.transitionCount);
}
else {
this.transition(animation, state, animationProgress);
}
}
}

public void handle(AnimationData data, float animationProgress, int age, GroundChecker groundChecker, MovingChecker movingChecker) {
this.model.getPart().traverse().forEach(ModelPart::resetTransform);
if (data.dodge.isAnimating()) {
this.switchAnimation(this.dodge, data.dodge, animationProgress);
this.switchAnimation(data, this.dodge, data.dodge, animationProgress, age);
}
else {
this.updateFall(data, age, groundChecker);
if (data.fallingCount <= 3) {
if (data.fallingCount < 13) {
if (movingChecker.isMoving()) {
this.switchAnimation(this.moving, data.moving, animationProgress);
this.switchAnimation(data, this.moving, data.moving, animationProgress, age);
} else {
this.switchAnimation(this.idle, data.idle, animationProgress);
this.switchAnimation(data, this.idle, data.idle, animationProgress, age);
}
}
else {
this.switchAnimation(data, this.falling, data.falling, animationProgress, age);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package com.mmodding.mmodding_lib.library.client.utils;

import com.mmodding.mmodding_lib.mixin.accessors.SinglePartEntityModelAccessor;
import com.mmodding.mmodding_lib.mixin.accessors.client.AnimatorAccessor;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.animation.Animation;
import net.minecraft.client.render.animation.AnimationKeyframe;
import net.minecraft.client.render.animation.Animator;
import net.minecraft.client.render.animation.PartAnimation;
import net.minecraft.client.render.entity.model.SinglePartEntityModel;
import net.minecraft.entity.AnimationState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3f;
import org.quiltmc.loader.api.minecraft.ClientOnly;

import java.util.List;
import java.util.Optional;

@ClientOnly
public class AnimationUtils {

Expand All @@ -31,4 +39,24 @@ public static void updateAnimation(SinglePartEntityModel<?> model, Animation ani
state.method_43686(animationProgress, speedFactor);
state.animateIfValid(current -> Animator.animate(model, animation, current.method_43687(), 1.0F, SinglePartEntityModelAccessor.getField39195()));
}

public static void animateSmoothly(SinglePartEntityModel<?> model, Animation animation, Animation lastAnimation, long duration, float strength, Vec3f animationCache, int smooth) {
float f = AnimatorAccessor.invokeGetAnimationTimestamp(animation, duration);
animation.animations().forEach((string, parts) -> {
List<PartAnimation> lastParts = lastAnimation.animations().get(string);
Optional<ModelPart> optionalModelPart = model.findPart(string);
optionalModelPart.ifPresent(modelPart -> parts.forEach(current -> lastParts.forEach(lastPart -> {
AnimationKeyframe[] animationKeyframes = current.keyframes();
AnimationKeyframe[] lastAnimationKeyFrames = lastPart.keyframes();
int i = Math.max(0, MathHelper.binarySearch(0, lastAnimationKeyFrames.length, index -> f <= lastAnimationKeyFrames[index].timestamp()) - 1);
int j = Math.min(animationKeyframes.length - 1, i + 1);
AnimationKeyframe lastAnimationKeyFrame = lastAnimationKeyFrames[i];
AnimationKeyframe endAnimationKeyFrame = animationKeyframes[j];
float h = f - lastAnimationKeyFrame.timestamp();
float k = MathHelper.clamp(h / (endAnimationKeyFrame.timestamp() - lastAnimationKeyFrame.timestamp()), 0.0f, 1.0f);
endAnimationKeyFrame.interpolator().apply(animationCache, k / smooth, animationKeyframes, i, j, strength);
current.transformation().apply(modelPart, animationCache);
})));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mmodding.mmodding_lib.library.soundtracks;

import net.minecraft.sound.MusicSound;
import net.minecraft.sound.SoundEvent;

public class SoundTrack extends MusicSound {

public SoundTrack(SoundEvent sound, int minDelay, int maxDelay, boolean replaceCurrentMusic) {
super(sound, minDelay, maxDelay, replaceCurrentMusic);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.mmodding.mmodding_lib.mixin.accessors.client;

import net.minecraft.client.render.animation.Animation;
import net.minecraft.client.render.animation.Animator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;

@Mixin(Animator.class)
public interface AnimatorAccessor {

@Invoker("getAnimationTimestamp")
static float invokeGetAnimationTimestamp(Animation animation, long elapsedMillis) {
throw new IllegalStateException();
}
}
1 change: 1 addition & 0 deletions src/main/resources/mmodding_lib.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
],
"client": [
"accessors.SinglePartEntityModelAccessor",
"accessors.client.AnimatorAccessor",
"accessors.client.BufferBuilderStorageAccessor",
"accessors.client.RenderLayerFirstAccessor",
"accessors.client.RenderLayerSecondAccessor",
Expand Down

0 comments on commit 89a9f4a

Please sign in to comment.