Advertisement
TurtyWurty

AnimatableModel.java

Sep 20th, 2023
988
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.26 KB | None | 0 0
  1. package dev.turtywurty.turtyissinking.client.animation;
  2.  
  3. import net.minecraft.client.animation.AnimationChannel;
  4. import net.minecraft.client.animation.AnimationDefinition;
  5. import net.minecraft.client.animation.Keyframe;
  6. import net.minecraft.client.model.HierarchicalModel;
  7. import net.minecraft.client.model.Model;
  8. import net.minecraft.client.model.geom.ModelPart;
  9. import net.minecraft.client.renderer.RenderType;
  10. import net.minecraft.resources.ResourceLocation;
  11. import net.minecraft.util.Mth;
  12. import org.joml.Vector3f;
  13.  
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Optional;
  17. import java.util.function.Function;
  18.  
  19. /**
  20.  * A model that can be animated (usable with anything, not just limited to entities like {@link HierarchicalModel})
  21.  */
  22. public abstract class AnimatableModel extends Model {
  23.     private final ModelPart root;
  24.  
  25.     /**
  26.      * Creates a new animatable model
  27.      *
  28.      * @param pRenderType The render type of the model
  29.      * @param root        The root part of the model
  30.      */
  31.     public AnimatableModel(Function<ResourceLocation, RenderType> pRenderType, ModelPart root) {
  32.         super(pRenderType);
  33.         this.root = root;
  34.     }
  35.  
  36.     /**
  37.      * Gets the root part of the model
  38.      *
  39.      * @return The root part
  40.      */
  41.     public ModelPart getRoot() {
  42.         return this.root;
  43.     }
  44.  
  45.     /**
  46.      * Gets a descendant part of the model with the given name
  47.      *
  48.      * @param name The name of the descendant
  49.      * @return The descendant part
  50.      */
  51.     public Optional<ModelPart> getAnyDescendantWithName(String name) {
  52.         return name.equals("root") ? Optional.of(getRoot()) : getRoot()
  53.                 .getAllParts()
  54.                 .filter(part -> part.hasChild(name))
  55.                 .findFirst()
  56.                 .map(part -> part.getChild(name));
  57.     }
  58.  
  59.     /**
  60.      * Animates the model with the given animation definition (sequence of keyframes)
  61.      *
  62.      * @param pModel               The model to animate
  63.      * @param pAnimationDefinition The animation definition
  64.      * @param pAccumulatedTime     The accumulated time in milliseconds
  65.      * @param pScale               The scale of the animation
  66.      * @param pAnimationVecCache   The animation vector cache
  67.      */
  68.     public static void animate(AnimatableModel pModel, AnimationDefinition pAnimationDefinition, long pAccumulatedTime, float pScale, Vector3f pAnimationVecCache) {
  69.         float elapsedSeconds = getElapsedSeconds(pAnimationDefinition, pAccumulatedTime);
  70.  
  71.         for(Map.Entry<String, List<AnimationChannel>> entry : pAnimationDefinition.boneAnimations().entrySet()) {
  72.             // Find a part with the name of the entry
  73.             Optional<ModelPart> optPart = pModel.getAnyDescendantWithName(entry.getKey());
  74.             if(optPart.isEmpty())
  75.                 continue;
  76.  
  77.             ModelPart part = optPart.get();
  78.             List<AnimationChannel> animations = entry.getValue();
  79.             for (AnimationChannel animation : animations) {
  80.                 if (animation == null)
  81.                     continue;
  82.  
  83.                 // Get the keyframes of the animation
  84.                 Keyframe[] keyframes = animation.keyframes();
  85.  
  86.                 // Find the current and next keyframes by comparing if the elapsed time is less than the timestamp
  87.                 int foundIndex = Mth.binarySearch(
  88.                         0,
  89.                         keyframes.length,
  90.                         threshold -> elapsedSeconds <= keyframes[threshold].timestamp());
  91.                 int currentFrameIdx = Math.max(0, foundIndex - 1);
  92.                 int nextFrameIdx = Math.min(keyframes.length - 1, currentFrameIdx + 1);
  93.  
  94.                 // Get the current and next keyframes
  95.                 Keyframe currentFrame = keyframes[currentFrameIdx];
  96.                 Keyframe nextFrame = keyframes[nextFrameIdx];
  97.  
  98.                 // Calculate the progress between the current and next keyframes
  99.                 float timeLeft = elapsedSeconds - currentFrame.timestamp();
  100.                 float progress = Mth.clamp(
  101.                         timeLeft / (nextFrame.timestamp() - currentFrame.timestamp()),
  102.                         0.0F,
  103.                         1.0F);
  104.  
  105.                 // Interpolate the keyframes
  106.                 nextFrame.interpolation().apply(
  107.                         pAnimationVecCache,
  108.                         progress,
  109.                         keyframes,
  110.                         currentFrameIdx,
  111.                         nextFrameIdx,
  112.                         pScale);
  113.  
  114.                 // Apply the interpolated keyframes to the part
  115.                 animation.target().apply(part, pAnimationVecCache);
  116.             }
  117.         }
  118.     }
  119.  
  120.     /**
  121.      * Gets the elapsed seconds of the animation
  122.      *
  123.      * @param pAnimationDefinition The animation definition
  124.      * @param pAccumulatedTime     The accumulated time in milliseconds
  125.      * @return The elapsed seconds
  126.      */
  127.     public static float getElapsedSeconds(AnimationDefinition pAnimationDefinition, long pAccumulatedTime) {
  128.         float secondsAccumulated = (float)pAccumulatedTime / 1000.0F;
  129.  
  130.         return pAnimationDefinition.looping()
  131.                 ? secondsAccumulated % pAnimationDefinition.lengthInSeconds()
  132.                 : secondsAccumulated;
  133.     }
  134. }
  135.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement