Skip to content

Commit 303f628

Browse files
authored
Merge pull request #74 from MaketendoDev/anim-lib
Animation library natively added
2 parents 06d105f + 96b8177 commit 303f628

33 files changed

Lines changed: 993 additions & 28 deletions

build.gradle

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ dependencies {
6868
modImplementation("dev.amble:lib:${project.amblekit_version}") {
6969
exclude(group: "net.fabricmc.fabric-api")
7070
}
71-
72-
modImplementation("maven.modrinth:animator:${project.animator_version}") {
73-
exclude(group: "net.fabricmc.fabric-api")
74-
}
7571
}
7672

7773
processResources {

gradle.properties

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ archives_base_name=timeless
1616

1717
# Dependencies
1818
fabric_version=0.92.2+1.20.1
19-
amblekit_version=1.1.16-dev+mc.1.20.1
20-
animator_version=1.0.1.20-1.20.1-release
19+
amblekit_version=1.1.16-dev+mc.1.20.1
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package mc.duzo.animation;
2+
3+
import net.fabricmc.api.ModInitializer;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
7+
import net.minecraft.server.network.ServerPlayerEntity;
8+
import net.minecraft.util.Identifier;
9+
10+
import mc.duzo.animation.generic.AnimationHolder;
11+
import mc.duzo.animation.generic.AnimationTracker;
12+
import mc.duzo.animation.network.Network;
13+
import mc.duzo.animation.network.PlayAnimationS2CPacket;
14+
import mc.duzo.animation.registry.AnimationRegistry;
15+
16+
public class DuzoAnimationMod implements ModInitializer {
17+
public static final String MOD_ID = "animation";
18+
19+
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
20+
21+
@Override
22+
public void onInitialize() {
23+
LOGGER.info("thank you for using duzos animator!");
24+
25+
AnimationRegistry.init();
26+
}
27+
28+
// todo - move to better place
29+
public static void play(ServerPlayerEntity target, AnimationTracker tracker, AnimationHolder animation) {
30+
Network.toTracking(new PlayAnimationS2CPacket(target, tracker, animation), target);
31+
}
32+
33+
/**
34+
* plays an animation to a target and updates all players near to the target
35+
* @param target the player to animate
36+
* @param tracker the tracker this animation should be performed on
37+
* @param animation identifier of the registered animation
38+
*/
39+
public static void play(ServerPlayerEntity target, AnimationTracker tracker, Identifier animation) {
40+
Network.toTracking(new PlayAnimationS2CPacket(target.getUuid(), tracker.id(), animation), target);
41+
}
42+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package mc.duzo.animation.api;
2+
3+
import java.util.Optional;
4+
5+
import net.fabricmc.fabric.api.event.Event;
6+
import net.fabricmc.fabric.api.event.EventFactory;
7+
8+
import net.minecraft.client.network.AbstractClientPlayerEntity;
9+
10+
import mc.duzo.animation.generic.AnimationInfo;
11+
12+
public final class AnimationEvents {
13+
public static final Event<FindAnimationInfo> FIND_ANIMATION_INFO = EventFactory.createArrayBacked(FindAnimationInfo.class, callbacks -> player -> {
14+
for (FindAnimationInfo callback : callbacks) {
15+
Result<AnimationInfo> value = callback.getAnimationInfo(player);
16+
17+
if (value.type() != Interaction.PASS || value.result().isPresent())
18+
return value;
19+
}
20+
return Result.success();
21+
});
22+
23+
@FunctionalInterface
24+
public interface FindAnimationInfo {
25+
/**
26+
* called when the animation info is queried and NONE is found
27+
* @return the overwritten result if any
28+
*/
29+
Result<AnimationInfo> getAnimationInfo(AbstractClientPlayerEntity player);
30+
}
31+
32+
33+
// from AIT
34+
public enum Interaction {
35+
SUCCESS, FAIL, PASS
36+
}
37+
38+
public record Result<T>(Interaction type, Optional<T> t) {
39+
40+
public static <T> Result<T> success() {
41+
return new Result<>(Interaction.SUCCESS);
42+
}
43+
44+
public static <T> Result<T> fail() {
45+
return new Result<>(Interaction.FAIL);
46+
}
47+
48+
public static <T> Result<T> pass() {
49+
return new Result<>(Interaction.PASS);
50+
}
51+
52+
public Result(Interaction inter) {
53+
this(inter, Optional.empty());
54+
}
55+
56+
public Result(T t) {
57+
this(Interaction.PASS, t);
58+
}
59+
60+
public Result(Interaction inter, T t) {
61+
this(inter, Optional.ofNullable(t));
62+
}
63+
64+
public Optional<T> result() {
65+
return t;
66+
}
67+
}
68+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package mc.duzo.animation.client;
2+
3+
import net.fabricmc.api.ClientModInitializer;
4+
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
5+
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
6+
7+
import mc.duzo.animation.generic.AnimationTracker;
8+
import mc.duzo.animation.network.PlayAnimationS2CPacket;
9+
import mc.duzo.animation.registry.client.TrackerRegistry;
10+
11+
public class DuzoAnimationClient implements ClientModInitializer {
12+
@Override
13+
public void onInitializeClient() {
14+
TrackerRegistry.init();
15+
16+
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> TrackerRegistry.REGISTRY.forEach(AnimationTracker::onDisconnect));
17+
18+
ClientPlayNetworking.registerGlobalReceiver(PlayAnimationS2CPacket.TYPE, PlayAnimationS2CPacket::handle);
19+
}
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package mc.duzo.animation.datagen;
2+
3+
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
4+
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
5+
6+
public class AnimationDataGenerator implements DataGeneratorEntrypoint {
7+
@Override
8+
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
9+
10+
}
11+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package mc.duzo.animation.generic;
2+
3+
import net.minecraft.client.render.entity.animation.Animation;
4+
import net.minecraft.client.render.entity.model.EntityModel;
5+
import net.minecraft.entity.AnimationState;
6+
import net.minecraft.entity.LivingEntity;
7+
import net.minecraft.util.Identifier;
8+
9+
import mc.duzo.animation.player.PlayerAnimationHelper;
10+
import mc.duzo.animation.registry.Identifiable;
11+
12+
public abstract class AnimationHolder implements Identifiable {
13+
private final Identifier id;
14+
protected final AnimationState state;
15+
protected final Animation animation;
16+
protected final AnimationInfo info;
17+
18+
protected AnimationHolder(Identifier id, Animation anim, AnimationInfo info) {
19+
this.id = id;
20+
this.state = new AnimationState();
21+
this.animation = anim;
22+
this.info = info;
23+
}
24+
protected AnimationHolder(Identifier id, Animation anim) {
25+
this(id, anim, new AnimationInfo(VisibilityList.all(), AnimationInfo.Perspective.THIRD_PERSON_FRONT, AnimationInfo.Movement.DISABLE, AnimationInfo.Transform.ALL));
26+
}
27+
28+
@Override
29+
public Identifier id() {
30+
return this.id;
31+
}
32+
33+
public void update(EntityModel<?> model, float progress, LivingEntity player) {
34+
// overwritten update method goes here
35+
36+
if (this.isFinished(player)) {
37+
this.state.stop();
38+
this.onFinished(player);
39+
return;
40+
}
41+
42+
if (!this.state.isRunning()) {
43+
this.onStart(player);
44+
}
45+
46+
this.state.startIfNotRunning(player.age);
47+
}
48+
49+
public boolean isFinished(LivingEntity entity) {
50+
if (this.animation.looping()) return false; // Looping animations should extend this class so they properly finish
51+
52+
return this.getRunningSeconds() >= this.animation.lengthInSeconds();
53+
}
54+
55+
protected void onFinished(LivingEntity player) {
56+
57+
}
58+
protected void onStart(LivingEntity player) {
59+
60+
}
61+
62+
protected float getRunningSeconds() {
63+
return PlayerAnimationHelper.getRunningSeconds(this.animation, this.state.getTimeRunning());
64+
}
65+
public Animation getAnimation() {
66+
return animation;
67+
}
68+
69+
public AnimationInfo getInfo() {
70+
return this.info;
71+
}
72+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package mc.duzo.animation.generic;
2+
3+
public record AnimationInfo(VisibilityList render, Perspective perspective, Movement movement, Transform transform) {
4+
5+
public enum Movement {
6+
ALLOW,
7+
DISABLE;
8+
}
9+
10+
public enum Perspective {
11+
FIRST_PERSON(true, false),
12+
THIRD_PERSON_BACK(false, false),
13+
THIRD_PERSON_FRONT(false, true);
14+
private final boolean firstPerson;
15+
private final boolean frontView;
16+
17+
Perspective(boolean firstPerson, boolean frontView) {
18+
this.firstPerson = firstPerson;
19+
this.frontView = frontView;
20+
}
21+
22+
public boolean isFirstPerson() {
23+
return this.firstPerson;
24+
}
25+
26+
public boolean isFrontView() {
27+
return this.frontView;
28+
}
29+
}
30+
31+
public enum Transform {
32+
ALL,
33+
TARGETED;
34+
}
35+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package mc.duzo.animation.generic;
2+
3+
import java.util.HashMap;
4+
import java.util.UUID;
5+
6+
import net.minecraft.entity.LivingEntity;
7+
import net.minecraft.server.network.ServerPlayerEntity;
8+
import net.minecraft.util.Identifier;
9+
10+
import mc.duzo.animation.DuzoAnimationMod;
11+
import mc.duzo.animation.registry.Identifiable;
12+
import mc.duzo.animation.registry.client.TrackerRegistry;
13+
14+
public abstract class AnimationTracker<T extends AnimationHolder> implements Identifiable {
15+
private final Identifier id;
16+
protected final HashMap<UUID, T> animations = new HashMap<>();
17+
18+
protected AnimationTracker(Identifier id) {
19+
this.id = id;
20+
}
21+
@Override
22+
public Identifier id() {
23+
return id;
24+
}
25+
26+
public T get(LivingEntity entity) {
27+
UUID uuid = entity.getUuid();
28+
29+
T anim = animations.get(uuid);
30+
31+
if (anim != null && anim.isFinished(entity)) {
32+
clear(uuid);
33+
return null;
34+
}
35+
36+
return anim;
37+
}
38+
public void add(UUID uuid, T animation) {
39+
animations.put(uuid, animation);
40+
}
41+
public void clear(UUID uuid) {
42+
animations.remove(uuid);
43+
}
44+
public void play(ServerPlayerEntity player, Identifier animation) {
45+
DuzoAnimationMod.play(player, this, animation);
46+
}
47+
48+
public void onDisconnect() {
49+
animations.clear();
50+
}
51+
52+
public AnimationTracker<T> register() {
53+
return TrackerRegistry.register(this);
54+
}
55+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package mc.duzo.animation.generic;
2+
3+
import net.minecraft.client.MinecraftClient;
4+
import net.minecraft.client.network.AbstractClientPlayerEntity;
5+
import net.minecraft.client.render.entity.model.PlayerEntityModel;
6+
import org.jetbrains.annotations.Nullable;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
public class VisibilityList extends ArrayList<VisiblePart> {
12+
public VisibilityList() {
13+
super();
14+
}
15+
16+
public VisibilityList(List<VisiblePart> parts) {
17+
super(parts);
18+
}
19+
20+
public void apply(PlayerEntityModel<AbstractClientPlayerEntity> model, @Nullable AbstractClientPlayerEntity player) {
21+
model.setVisible(false);
22+
23+
for (VisiblePart part : this) {
24+
part.apply(model);
25+
}
26+
27+
if (player == null) return;
28+
29+
MinecraftClient client = MinecraftClient.getInstance();
30+
if (player.equals(client.player) && !client.gameRenderer.getCamera().isThirdPerson()) {
31+
// force everything to be visible in first person
32+
model.setVisible(true);
33+
}
34+
}
35+
36+
public static VisibilityList all() {
37+
return new VisibilityList(List.of(VisiblePart.values()));
38+
}
39+
40+
public static VisibilityList none() {
41+
return new VisibilityList();
42+
}
43+
44+
public static VisibilityList firstLayer() {
45+
return of(VisiblePart.HEAD,
46+
VisiblePart.BODY,
47+
VisiblePart.LEFT_ARM,
48+
VisiblePart.RIGHT_ARM,
49+
VisiblePart.LEFT_LEG,
50+
VisiblePart.RIGHT_LEG);
51+
}
52+
53+
public static VisibilityList headOnly() {
54+
return of(VisiblePart.HEAD);
55+
}
56+
57+
public static VisibilityList of(VisiblePart... parts) {
58+
return new VisibilityList(List.of(parts));
59+
}
60+
}

0 commit comments

Comments
 (0)