-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
todo: finish player animation
- Loading branch information
Showing
18 changed files
with
1,702 additions
and
9 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
src/main/java/mc/duzo/timeless/client/animation/AnimationHolder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package mc.duzo.timeless.client.animation; | ||
|
||
import net.minecraft.client.network.AbstractClientPlayerEntity; | ||
import net.minecraft.client.render.entity.animation.Animation; | ||
import net.minecraft.client.render.entity.model.EntityModel; | ||
import net.minecraft.entity.AnimationState; | ||
|
||
import mc.duzo.timeless.client.animation.player.PlayerAnimationHelper; | ||
|
||
public abstract class AnimationHolder { | ||
protected final AnimationState state; | ||
protected final Animation animation; | ||
|
||
protected AnimationHolder(Animation anim) { | ||
this.state = new AnimationState(); | ||
this.animation = anim; | ||
} | ||
|
||
public void update(EntityModel<?> model, float progress, AbstractClientPlayerEntity player) { | ||
// overwritten update method goes here | ||
|
||
if (this.isFinished(player)) { | ||
this.state.stop(); | ||
this.onFinished(player); | ||
} else { | ||
if (!this.state.isRunning()) { | ||
this.onStart(player); | ||
} | ||
this.state.startIfNotRunning(player.age); | ||
} | ||
} | ||
|
||
public boolean isFinished(AbstractClientPlayerEntity entity) { | ||
if (this.animation.looping()) return false; // Looping animations should extend this class so they properly finish | ||
|
||
return this.getRunningSeconds() >= this.animation.lengthInSeconds(); | ||
} | ||
|
||
protected void onFinished(AbstractClientPlayerEntity player) { | ||
|
||
} | ||
protected void onStart(AbstractClientPlayerEntity player) { | ||
|
||
} | ||
|
||
protected float getRunningSeconds() { | ||
return PlayerAnimationHelper.getRunningSeconds(this.animation, this.state.getTimeRunning()); | ||
} | ||
public Animation getAnimation() { | ||
return animation; | ||
} | ||
} |
128 changes: 128 additions & 0 deletions
128
src/main/java/mc/duzo/timeless/client/animation/player/PlayerAnimationHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package mc.duzo.timeless.client.animation.player; | ||
|
||
import java.util.Optional; | ||
|
||
import net.fabricmc.api.EnvType; | ||
import net.fabricmc.api.Environment; | ||
import org.joml.Vector3f; | ||
|
||
import net.minecraft.client.model.ModelPart; | ||
import net.minecraft.client.network.AbstractClientPlayerEntity; | ||
import net.minecraft.client.render.entity.animation.Animation; | ||
import net.minecraft.client.render.entity.animation.Keyframe; | ||
import net.minecraft.client.render.entity.animation.Transformation; | ||
import net.minecraft.client.render.entity.model.PlayerEntityModel; | ||
import net.minecraft.entity.AnimationState; | ||
import net.minecraft.util.math.MathHelper; | ||
|
||
import mc.duzo.timeless.client.animation.player.holder.PlayerAnimationHolder; | ||
import mc.duzo.timeless.suit.client.animation.SuitAnimationHolder; | ||
import mc.duzo.timeless.suit.client.animation.SuitAnimationTracker; | ||
|
||
/** | ||
* From {@link net.minecraft.client.render.entity.animation.AnimationHelper}, | ||
* Edited for animating PlayerModel | ||
* | ||
* @author duzo | ||
*/ | ||
@Environment(value= EnvType.CLIENT) | ||
public class PlayerAnimationHelper { | ||
public static void animate(PlayerEntityModel<?> model, Animation animation, long runningTime, float scale, Vector3f tempVec) { | ||
float f = getRunningSeconds(animation, runningTime); | ||
animation.boneAnimations().forEach((key, list) -> { | ||
// TODO - fix "player" / "root" part not animating properly | ||
Optional<ModelPart> optional = getChild(model, key); | ||
optional.ifPresent(part -> list.forEach(transformation -> { | ||
Keyframe[] keyframes = transformation.keyframes(); | ||
int i = Math.max(0, MathHelper.binarySearch(0, keyframes.length, index -> f <= keyframes[index].timestamp()) - 1); | ||
int j = Math.min(keyframes.length - 1, i + 1); | ||
Keyframe keyframe = keyframes[i]; | ||
Keyframe keyframe2 = keyframes[j]; | ||
float h = f - keyframe.timestamp(); | ||
float k = j != i ? MathHelper.clamp(h / (keyframe2.timestamp() - keyframe.timestamp()), 0.0f, 1.0f) : 0.0f; | ||
keyframe2.interpolation().apply(tempVec, k, keyframes, i, j, scale); | ||
transformation.target().apply(part, tempVec); | ||
})); | ||
}); | ||
|
||
correctSleevies(model); | ||
} | ||
|
||
private static void correctSleevies(PlayerEntityModel<?> model) { | ||
model.hat.copyTransform(model.head); | ||
model.leftSleeve.copyTransform(model.leftArm); | ||
model.rightSleeve.copyTransform(model.rightArm); | ||
model.leftPants.copyTransform(model.leftLeg); | ||
model.rightPants.copyTransform(model.rightLeg); | ||
model.jacket.copyTransform(model.body); | ||
} | ||
|
||
public static void updateAnimation(AnimationState animationState, Animation animation, float animationProgress, float speedMultiplier, PlayerEntityModel<?> model) { | ||
animationState.update(animationProgress, speedMultiplier); | ||
animationState.run(state -> animate(model, animation, state.getTimeRunning(), 1.0f, new Vector3f())); | ||
} | ||
public static void updateAnimation(AnimationState animationState, Animation animation, float animationProgress, PlayerEntityModel<?> model) { | ||
updateAnimation(animationState, animation, animationProgress, 1.0f, model); | ||
} | ||
|
||
public static float getRunningSeconds(Animation animation, long runningTime) { | ||
float f = (float)runningTime / 1000.0f; | ||
return animation.looping() ? f % animation.lengthInSeconds() : f; | ||
} | ||
|
||
private static Optional<ModelPart> getChild(PlayerEntityModel<?> model, String name) { | ||
return ((PlayerModelHook) model).timeless$getChild(name); | ||
} | ||
|
||
public static Vector3f getModelPartPivot(PlayerEntityModel<?> model, String name) { | ||
Optional<ModelPart> optional = getChild(model, name); | ||
if(optional.isEmpty()) return new Vector3f(0.0F, 0.0F, 0.0F); | ||
Vector3f pivot = new Vector3f(optional.get().pivotX, optional.get().pivotY, optional.get().pivotZ); | ||
return pivot; | ||
} | ||
|
||
public static Vector3f getModelPartRotation(PlayerEntityModel<?> model, String name) { | ||
Optional<ModelPart> optional = getChild(model, name); | ||
if(optional.isEmpty()) return new Vector3f(0.0F, 0.0F, 0.0F); | ||
Vector3f rotation = new Vector3f(optional.get().pivotX, optional.get().pivotY, optional.get().pivotZ); | ||
return rotation; | ||
} | ||
|
||
public static void runAnimations(AbstractClientPlayerEntity livingEntity, PlayerEntityModel<?> model, float progress) { | ||
PlayerAnimationHolder anim = PlayerAnimationTracker.getAnimation(livingEntity); | ||
|
||
if (anim != null) { | ||
anim.update(model, progress, livingEntity); | ||
return; | ||
} | ||
|
||
SuitAnimationHolder animSuit = SuitAnimationTracker.getAnimation(livingEntity); | ||
if (animSuit.getModel() == null) return; | ||
animSuit.getModel().copyTo(model); | ||
} | ||
|
||
public static void startAnimations(AbstractClientPlayerEntity entity) { | ||
|
||
} | ||
public static boolean isRunningAnimations(AbstractClientPlayerEntity livingEntity) { | ||
PlayerAnimationHolder anim = PlayerAnimationTracker.getAnimation(livingEntity); | ||
SuitAnimationHolder animSuit = SuitAnimationTracker.getAnimation(livingEntity); | ||
return (anim != null && !anim.isFinished(livingEntity)) || (animSuit != null && animSuit.shouldPlayerMimic() && !animSuit.isFinished(livingEntity)); | ||
} | ||
|
||
public static void playAnimation(AbstractClientPlayerEntity player, Animation animation) { | ||
playAnimation(player, new PlayerAnimationHolder(animation)); | ||
} | ||
public static void playAnimation(AbstractClientPlayerEntity player, PlayerAnimationHolder holder) { | ||
stopAnimation(player); | ||
PlayerAnimationTracker.addAnimation(player.getUuid(), holder); | ||
} | ||
public static void stopAnimation(AbstractClientPlayerEntity player) { | ||
PlayerAnimationTracker.clearAnimation(player.getUuid()); | ||
} | ||
public static final Transformation.Interpolation STEP = (dest, delta, keyframes, start, end, scale) -> { | ||
Vector3f vector3f = keyframes[start].target(); | ||
Vector3f vector3f2 = keyframes[end].target(); | ||
return vector3f.lerp(vector3f2, 0, dest).mul(scale); | ||
}; | ||
} |
30 changes: 30 additions & 0 deletions
30
src/main/java/mc/duzo/timeless/client/animation/player/PlayerAnimationTracker.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package mc.duzo.timeless.client.animation.player; | ||
|
||
import java.util.HashMap; | ||
import java.util.UUID; | ||
|
||
import net.minecraft.client.network.AbstractClientPlayerEntity; | ||
|
||
import mc.duzo.timeless.client.animation.player.holder.PlayerAnimationHolder; | ||
|
||
public class PlayerAnimationTracker { | ||
private static final HashMap<UUID, PlayerAnimationHolder> ANIMATIONS = new HashMap<>(); | ||
|
||
public static PlayerAnimationHolder getAnimation(AbstractClientPlayerEntity entity) { | ||
UUID uuid = entity.getUuid(); | ||
|
||
PlayerAnimationHolder anim = ANIMATIONS.get(uuid); | ||
|
||
if (anim != null && anim.isFinished(entity)) { | ||
ANIMATIONS.remove(uuid); | ||
} | ||
|
||
return anim; | ||
} | ||
public static void addAnimation(UUID uuid, PlayerAnimationHolder animation) { | ||
ANIMATIONS.put(uuid, animation); | ||
} | ||
public static void clearAnimation(UUID uuid) { | ||
ANIMATIONS.remove(uuid); | ||
} | ||
} |
Oops, something went wrong.