From 89a9f4a4aa6ad6d6c5a4603b860b7340293e3a0c Mon Sep 17 00:00:00 2001 From: FirstMegaGame4 <84094287+FirstMegaGame4@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:53:54 +0200 Subject: [PATCH] Add AnimationUtils#animateSmoothly --- .../entity/animation/AnimationData.java | 3 ++ .../entity/animation/AnimationManager.java | 43 ++++++++++++++++--- .../library/client/utils/AnimationUtils.java | 28 ++++++++++++ .../library/soundtracks/SoundTrack.java | 11 +++++ .../accessors/client/AnimatorAccessor.java | 15 +++++++ src/main/resources/mmodding_lib.mixins.json | 1 + 6 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/mmodding/mmodding_lib/library/soundtracks/SoundTrack.java create mode 100644 src/main/java/com/mmodding/mmodding_lib/mixin/accessors/client/AnimatorAccessor.java diff --git a/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationData.java b/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationData.java index a05490c..0462142 100644 --- a/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationData.java +++ b/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationData.java @@ -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; diff --git a/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationManager.java b/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationManager.java index 0ac815b..9cbf1e0 100644 --- a/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationManager.java +++ b/src/main/java/com/mmodding/mmodding_lib/library/client/render/entity/animation/AnimationManager.java @@ -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; @@ -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; @@ -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); + } } } diff --git a/src/main/java/com/mmodding/mmodding_lib/library/client/utils/AnimationUtils.java b/src/main/java/com/mmodding/mmodding_lib/library/client/utils/AnimationUtils.java index dcc1f54..e901d33 100644 --- a/src/main/java/com/mmodding/mmodding_lib/library/client/utils/AnimationUtils.java +++ b/src/main/java/com/mmodding/mmodding_lib/library/client/utils/AnimationUtils.java @@ -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 { @@ -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 lastParts = lastAnimation.animations().get(string); + Optional 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); + }))); + }); + } } diff --git a/src/main/java/com/mmodding/mmodding_lib/library/soundtracks/SoundTrack.java b/src/main/java/com/mmodding/mmodding_lib/library/soundtracks/SoundTrack.java new file mode 100644 index 0000000..5f59476 --- /dev/null +++ b/src/main/java/com/mmodding/mmodding_lib/library/soundtracks/SoundTrack.java @@ -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); + } +} diff --git a/src/main/java/com/mmodding/mmodding_lib/mixin/accessors/client/AnimatorAccessor.java b/src/main/java/com/mmodding/mmodding_lib/mixin/accessors/client/AnimatorAccessor.java new file mode 100644 index 0000000..157fe39 --- /dev/null +++ b/src/main/java/com/mmodding/mmodding_lib/mixin/accessors/client/AnimatorAccessor.java @@ -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(); + } +} diff --git a/src/main/resources/mmodding_lib.mixins.json b/src/main/resources/mmodding_lib.mixins.json index b0990ad..bc11226 100644 --- a/src/main/resources/mmodding_lib.mixins.json +++ b/src/main/resources/mmodding_lib.mixins.json @@ -100,6 +100,7 @@ ], "client": [ "accessors.SinglePartEntityModelAccessor", + "accessors.client.AnimatorAccessor", "accessors.client.BufferBuilderStorageAccessor", "accessors.client.RenderLayerFirstAccessor", "accessors.client.RenderLayerSecondAccessor",