Skip to content

Instantly share code, notes, and snippets.

@Commoble
Created July 3, 2022 22:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Commoble/ddb139a1e34bd1c78791569080741c02 to your computer and use it in GitHub Desktop.
Save Commoble/ddb139a1e34bd1c78791569080741c02 to your computer and use it in GitHub Desktop.
Animation Codecs
package commoble.databuddy.codec;
import java.util.Map;
import com.google.common.collect.Lists;
import com.mojang.math.Vector3f;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.client.animation.AnimationChannel;
import net.minecraft.client.animation.AnimationChannel.Interpolation;
import net.minecraft.client.animation.AnimationChannel.Interpolations;
import net.minecraft.client.animation.AnimationChannel.Target;
import net.minecraft.client.animation.AnimationChannel.Targets;
import net.minecraft.client.animation.AnimationDefinition;
import net.minecraft.client.animation.Keyframe;
import net.minecraft.util.StringRepresentable;
/**
* <p>Codecs for mojang's keyframe system. Json format of an AnimationDefinition by way of {@link #ANIMATION_DEFINITION}:</p>
* <pre>
* {
* "lengthInSeconds" : float,
* "looping": boolean (optional, defaults to false),
* "bone_animations": // map of named lists of animation channel objects
* {
* "name":
* [
* {
* "target": "position" or "rotation" or "scale",
* "keyframes": // list of keyframe objects
* [
* {
* "timestamp": float,
* "target": [x, y, z], // floats
* "interpolation": "linear" or "catmullrom"
* }
* ]
* }
* ]
* }
* }
* </pre>
* <p>Custom target types and interpolation types are not currently supported</p>
*/
public class AnimationCodecs
{
public static final Codec<Target> TARGET = TargetType.CODEC.flatComapMap(TargetType::target, target ->
{
TargetType type = TargetType.BY_TARGET.get(target);
return type == null
? DataResult.error("Unknown target type (custom target types are not currently supported)")
: DataResult.success(type);
});
public static final Codec<Interpolation> INTERPOLATION = InterpolationType.CODEC.flatComapMap(InterpolationType::interpolation, interpolation ->
{
InterpolationType type = InterpolationType.BY_INTERPOLATION.get(interpolation);
return type == null
? DataResult.error("Unknown interpolation type (custom interpolation types are not currently supported)")
: DataResult.success(type);
});
public static final Codec<Keyframe> KEYFRAME = RecordCodecBuilder.create(builder -> builder.group(
Codec.FLOAT.fieldOf("timestamp").forGetter(Keyframe::timestamp),
Vector3f.CODEC.fieldOf("target").forGetter(Keyframe::target),
INTERPOLATION.fieldOf("interpolation").forGetter(Keyframe::interpolation)
).apply(builder, Keyframe::new));
public static final Codec<AnimationChannel> ANIMATION_CHANNEL = RecordCodecBuilder.create(builder -> builder.group(
TARGET.fieldOf("target").forGetter(AnimationChannel::target),
KEYFRAME.listOf().xmap(list -> list.toArray(Keyframe[]::new), arr -> Lists.newArrayList(arr)).fieldOf("keyframes").forGetter(AnimationChannel::keyframes)
).apply(builder, AnimationChannel::new));
public static final Codec<AnimationDefinition> ANIMATION_DEFINITION = RecordCodecBuilder.create(builder -> builder.group(
Codec.FLOAT.fieldOf("length_in_seconds").forGetter(AnimationDefinition::lengthInSeconds),
Codec.BOOL.optionalFieldOf("looping", false).forGetter(AnimationDefinition::looping),
Codec.unboundedMap(Codec.STRING, ANIMATION_CHANNEL.listOf()).fieldOf("bone_animations").forGetter(AnimationDefinition::boneAnimations)
).apply(builder, AnimationDefinition::new));
public static enum TargetType implements StringRepresentable
{
POSITION("position", Targets.POSITION),
ROTATION("rotation", Targets.ROTATION),
SCALE("scale", Targets.SCALE);
public static final Map<Target, TargetType> BY_TARGET = Map.of(
Targets.POSITION, POSITION,
Targets.ROTATION, ROTATION,
Targets.SCALE, SCALE);
public static final Codec<TargetType> CODEC = StringRepresentable.fromEnum(() -> TargetType.values());
private final String name;
private final Target target;
TargetType(String name, Target target)
{
this.name = name;
this.target = target;
}
@Override
public String getSerializedName()
{
return this.name;
}
public Target target()
{
return this.target;
}
}
public static enum InterpolationType implements StringRepresentable
{
LINEAR("linear", Interpolations.LINEAR),
CATMULLROM("catmullrom", Interpolations.CATMULLROM);
public static final Codec<InterpolationType> CODEC = StringRepresentable.fromEnum(() -> InterpolationType.values());
public static final Map<Interpolation, InterpolationType> BY_INTERPOLATION = Map.of(
Interpolations.LINEAR, LINEAR,
Interpolations.CATMULLROM, CATMULLROM);
private final String name;
private final Interpolation interpolation;
InterpolationType(String name, Interpolation interpolation)
{
this.name = name;
this.interpolation = interpolation;
}
@Override
public String getSerializedName()
{
return this.name;
}
public Interpolation interpolation()
{
return this.interpolation;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment