From e11a69a8ddd24ff08151a2e95b1aff081b068c24 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sun, 18 Jan 2026 06:16:09 +0700 Subject: [PATCH 1/3] Hytale start --- .../loading/BlockyAnimLoader.java | 112 ++++++++++++++++++ .../loading/UniversalAnimLoader.java | 21 +++- .../animation/PlayerAnimResources.java | 8 +- 3 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java diff --git a/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java b/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java new file mode 100644 index 0000000..1987c5f --- /dev/null +++ b/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java @@ -0,0 +1,112 @@ +package com.zigythebird.playeranimcore.loading; + +import com.google.gson.*; +import com.zigythebird.playeranimcore.animation.Animation; +import com.zigythebird.playeranimcore.animation.ExtraAnimationData; +import com.zigythebird.playeranimcore.animation.keyframe.BoneAnimation; +import com.zigythebird.playeranimcore.math.Vec3f; + +import java.lang.reflect.Type; +import java.util.*; + +import static com.zigythebird.playeranimcore.loading.UniversalAnimLoader.NO_KEYFRAMES; +import static java.util.Map.entry; + +public class BlockyAnimLoader implements JsonDeserializer { + public static final Gson GSON = new GsonBuilder().registerTypeAdapter(Animation.class, new BlockyAnimLoader()).create(); + + private static final float TIME_SCALE = 20.0f / 60.0f; + + private static final Map RENAMES = Map.of( + "head", "headhy" + ); + private static final Map PIVOTS = Map.ofEntries( + // Body + entry("origin", new Vec3f(0, 0, 0)), + entry("pelvis", new Vec3f(0, 51, 0)), + entry("belly", new Vec3f(0, 55, 0)), + entry("chest", new Vec3f(0, 68, -3)), + + // Head + entry("headhy", new Vec3f(0, 87, -1)), + + // Right Arm + entry("r-shoulder", new Vec3f(-14.5017F, 86.594F, -0.9388F)), + entry("r-arm", new Vec3f(-14.5017F, 86.594F, -0.9388F)), + + // Left Arm + entry("l-shoulder", new Vec3f(14.5017F, 86.594F, -0.9388F)), + entry("l-arm", new Vec3f(14.5017F, 86.594F, -0.9388F)), + + // Right Leg + entry("r-thigh", new Vec3f(-7.5F, 50, 1)), + + // Left Leg + entry("l-thigh", new Vec3f(7.5F, 50, 1)), + + // Cape + entry("back-attachment", new Vec3f(0, 79, -18)) + ); + private static final Map PARENTS = Map.ofEntries( + // Body + entry("pelvis", "origin"), + entry("belly", "pelvis"), + entry("chest", "belly"), + entry("body", "pelvis"), // Minecraft + + // Torso + entry("torso", "chest"), // Minecraft TODO + + // Head + entry("headhy", "chest"), + entry("head", "headhy"), // Minecraft + + // Right Arm + entry("r-shoulder", "chest"), + entry("r-arm", "r-shoulder"), + entry("right_arm", "r-arm"), // Minecraft + + // Left Arm + entry("l-shoulder", "chest"), + entry("l-arm", "l-shoulder"), + entry("left_arm", "l-arm"), // Minecraft + + // Right Leg + entry("r-thigh", "pelvis"), + entry("right_leg", "r-thigh"), + + // Left Leg + entry("l-thigh", "pelvis"), + entry("left_leg", "l-thigh"), + + // Cape + entry("back-attachment", "chest"), + entry("cape", "back-attachment") // Minecraft + ); + private static final Map BENDS = Map.of( + "r-forearm", "right_arm", + "l-forearm", "left_arm", + "r-calf", "right_leg", + "l-calf", "left_leg" + ); + + @Override + public Animation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject root = json.getAsJsonObject(); + float duration = root.has("duration") ? root.get("duration").getAsFloat() * TIME_SCALE : 0; + boolean loop = root.has("holdLastKeyframe") && root.get("holdLastKeyframe").getAsBoolean(); + + Map animations = new HashMap<>(); + + if (root.has("nodeAnimations")) { + for (Map.Entry entry : root.getAsJsonObject("nodeAnimations").entrySet()) { + String src = entry.getKey(); + JsonObject data = entry.getValue().getAsJsonObject(); + + + } + } + + return new Animation(new ExtraAnimationData(), duration, loop ? Animation.LoopType.HOLD_ON_LAST_FRAME : Animation.LoopType.PLAY_ONCE, animations, NO_KEYFRAMES, PIVOTS, PARENTS); + } +} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/loading/UniversalAnimLoader.java b/core/src/main/java/com/zigythebird/playeranimcore/loading/UniversalAnimLoader.java index 7f5b8c8..ec8929c 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/loading/UniversalAnimLoader.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/loading/UniversalAnimLoader.java @@ -11,6 +11,7 @@ import com.zigythebird.playeranimcore.util.JsonUtil; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; @@ -31,13 +32,21 @@ public class UniversalAnimLoader implements JsonDeserializer loadAnimations(InputStream resource) throws IOException { + return loadAnimations(resource, null); + } + + public static Map loadAnimations(InputStream resource, @Nullable String name) throws IOException { try (Reader reader = new InputStreamReader(resource)) { - return loadAnimations(PlayerAnimLib.GSON.fromJson(reader, JsonObject.class)); + return loadAnimations(PlayerAnimLib.GSON.fromJson(reader, JsonObject.class), name); } } public static Map<@NotNull String, Animation> loadAnimations(JsonObject json) { - if (json.has("animations")) { + return loadAnimations(json, null); + } + + public static Map<@NotNull String, Animation> loadAnimations(JsonObject json, @Nullable String name) { + if (json.has("animations")) { // Bedrock Map animationMap = PlayerAnimLib.GSON.fromJson(json.get("animations"), PlayerAnimLib.ANIMATIONS_MAP_TYPE); if (json.has("parents") && json.has("model")) { Map parents = UniversalAnimLoader.getParents(JsonUtil.getAsJsonObject(json, "parents", new JsonObject())); @@ -52,9 +61,15 @@ public static Map loadAnimations(InputStream resource) throws } } return animationMap; - } else { + } else if (json.has("nodeAnimations")) { // Hytale + Animation animation = BlockyAnimLoader.GSON.fromJson(json, Animation.class); + if (name != null && !animation.data().has(ExtraAnimationData.NAME_KEY)) animation.data().put(ExtraAnimationData.NAME_KEY, name); + return Collections.singletonMap(animation.getNameOrId(), animation); + } else if (json.has("emote")) { // PlayerAnimator Animation animation = PlayerAnimatorLoader.GSON.fromJson(json, Animation.class); return Collections.singletonMap(animation.getNameOrId(), animation); + } else { + throw new JsonParseException("Unsupported format!"); } } diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/PlayerAnimResources.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/PlayerAnimResources.java index 647f9e6..238aa81 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/PlayerAnimResources.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/PlayerAnimResources.java @@ -8,6 +8,7 @@ import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManagerReloadListener; +import org.apache.commons.io.FilenameUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,10 +84,13 @@ public static boolean hasAnimation(Identifier id) { public void onResourceManagerReload(ResourceManager manager) { ANIMATIONS.clear(); - for (var resource : manager.listResources("player_animations", resourceLocation -> resourceLocation.getPath().endsWith(".json")).entrySet()) { + for (var resource : manager.listResources("player_animations", identifier -> { + String path = identifier.getPath(); + return path.endsWith(".json") || path.endsWith(".blockyanim"); + }).entrySet()) { String namespace = resource.getKey().getNamespace(); try (InputStream is = resource.getValue().open()) { - for (var entry : UniversalAnimLoader.loadAnimations(is).entrySet()) { + for (var entry : UniversalAnimLoader.loadAnimations(is, FilenameUtils.getBaseName(resource.getKey().getPath())).entrySet()) { ANIMATIONS.put(Identifier.fromNamespaceAndPath(namespace, entry.getKey()), entry.getValue()); } } catch (Exception e) { From 9817d6d8ba00d2413ca433456fdd5bc7e1ef0063 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sun, 18 Jan 2026 07:55:34 +0700 Subject: [PATCH 2/3] Loading --- core/build.gradle | 1 + .../loading/AnimationLoader.java | 2 +- .../loading/BlockyAnimLoader.java | 75 +- gradle.properties | 2 +- .../player_animations/wavehy.blockyanim | 1117 +++++++++++++++++ 5 files changed, 1191 insertions(+), 6 deletions(-) create mode 100644 minecraft/common/src/main/resources/assets/player_animation_library/player_animations/wavehy.blockyanim diff --git a/core/build.gradle b/core/build.gradle index f1fe073..c18f6af 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -12,6 +12,7 @@ dependencies { implementation api("org.slf4j:slf4j-api:2.0.17") implementation api("it.unimi.dsi:fastutil:8.5.18") implementation api("io.netty:netty-buffer:4.2.7.Final") + implementation api("org.joml:joml:1.10.8") // Testing testImplementation("org.junit.jupiter:junit-jupiter-api:6.0.1") diff --git a/core/src/main/java/com/zigythebird/playeranimcore/loading/AnimationLoader.java b/core/src/main/java/com/zigythebird/playeranimcore/loading/AnimationLoader.java index cdaa0c6..eeed226 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/loading/AnimationLoader.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/loading/AnimationLoader.java @@ -291,7 +291,7 @@ private static List> getEasingArgsForAxis(JsonObject entryObj, easingArg; } - private static List addArgsForKeyframes(List frames) { + public static List addArgsForKeyframes(List frames) { if (frames.getFirst().startValue().getFirst() instanceof AccessExpression accessExpression && "disabled".equals(accessExpression.property()) && accessExpression.object() instanceof IdentifierExpression identifierExpression && "pal".equals(identifierExpression.name())) diff --git a/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java b/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java index 1987c5f..8aded19 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java @@ -4,7 +4,17 @@ import com.zigythebird.playeranimcore.animation.Animation; import com.zigythebird.playeranimcore.animation.ExtraAnimationData; import com.zigythebird.playeranimcore.animation.keyframe.BoneAnimation; +import com.zigythebird.playeranimcore.animation.keyframe.Keyframe; +import com.zigythebird.playeranimcore.animation.keyframe.KeyframeStack; +import com.zigythebird.playeranimcore.easing.EasingType; +import com.zigythebird.playeranimcore.enums.TransformType; import com.zigythebird.playeranimcore.math.Vec3f; +import com.zigythebird.playeranimcore.molang.MolangLoader; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import team.unnamed.mocha.parser.ast.Expression; +import team.unnamed.mocha.parser.ast.FloatExpression; import java.lang.reflect.Type; import java.util.*; @@ -83,12 +93,12 @@ public class BlockyAnimLoader implements JsonDeserializer { entry("back-attachment", "chest"), entry("cape", "back-attachment") // Minecraft ); - private static final Map BENDS = Map.of( + /*private static final Map BENDS = Map.of( "r-forearm", "right_arm", "l-forearm", "left_arm", "r-calf", "right_leg", "l-calf", "left_leg" - ); + );*/ @Override public Animation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { @@ -100,13 +110,70 @@ public Animation deserialize(JsonElement json, Type typeOfT, JsonDeserialization if (root.has("nodeAnimations")) { for (Map.Entry entry : root.getAsJsonObject("nodeAnimations").entrySet()) { - String src = entry.getKey(); + String src = entry.getKey().toLowerCase(Locale.ROOT); JsonObject data = entry.getValue().getAsJsonObject(); - + KeyframeStack rot = parseStack(data.getAsJsonArray("orientation"), TransformType.ROTATION); + KeyframeStack pos = parseStack(data.getAsJsonArray("position"), TransformType.POSITION); + KeyframeStack scl = parseStack(data.getAsJsonArray("shapeStretch"), TransformType.SCALE); + animations.put(RENAMES.getOrDefault(src, src), new BoneAnimation(rot, pos, scl, new ArrayList<>())); } } return new Animation(new ExtraAnimationData(), duration, loop ? Animation.LoopType.HOLD_ON_LAST_FRAME : Animation.LoopType.PLAY_ONCE, animations, NO_KEYFRAMES, PIVOTS, PARENTS); } + + private KeyframeStack parseStack(JsonArray json, TransformType type) { + if (json == null || json.isEmpty()) return new KeyframeStack(); + + List xFrames = new ObjectArrayList<>(); + List yFrames = new ObjectArrayList<>(); + List zFrames = new ObjectArrayList<>(); + + List xPrev = null; + List yPrev = null; + List zPrev = null; + float prevTime = 0; + + Expression defaultValue = type == TransformType.SCALE ? FloatExpression.ONE : FloatExpression.ZERO; + + for (JsonElement element : json) { + JsonObject keyframe = element.getAsJsonObject(); + JsonObject delta = keyframe.getAsJsonObject("delta"); + + float curTime = keyframe.get("time").getAsFloat() * TIME_SCALE; + float timeDelta = curTime - prevTime; + + List xValue, yValue, zValue; + if (type == TransformType.ROTATION) { + Vector3f vector3f = new Quaternionf( + delta.get("x").getAsFloat(), delta.get("y").getAsFloat(), delta.get("z").getAsFloat(), delta.get("w").getAsFloat() + ).getEulerAnglesXYZ(new Vector3f()); + + xValue = Collections.singletonList(FloatExpression.of(vector3f.x())); + yValue = Collections.singletonList(FloatExpression.of(vector3f.y())); + zValue = Collections.singletonList(FloatExpression.of(vector3f.z())); + } else { + xValue = MolangLoader.parseJson(false, delta.get("x"), defaultValue); + yValue = MolangLoader.parseJson(false, delta.get("y"), defaultValue); + zValue = MolangLoader.parseJson(false, delta.get("z"), defaultValue); + } + + EasingType easingType = keyframe.has("interpolationType") && keyframe.get("interpolationType").getAsString().equals("smooth") ? EasingType.CATMULLROM : EasingType.LINEAR; + xFrames.add(new Keyframe(timeDelta, xPrev == null ? xValue : xPrev, xValue, easingType, Collections.emptyList())); + yFrames.add(new Keyframe(timeDelta, yPrev == null ? yValue : yPrev, yValue, easingType, Collections.emptyList())); + zFrames.add(new Keyframe(timeDelta, zPrev == null ? zValue : zPrev, zValue, easingType, Collections.emptyList())); + + xPrev = xValue; + yPrev = yValue; + zPrev = zValue; + prevTime = curTime; + } + + return new KeyframeStack( + AnimationLoader.addArgsForKeyframes(xFrames), + AnimationLoader.addArgsForKeyframes(yFrames), + AnimationLoader.addArgsForKeyframes(zFrames) + ); + } } diff --git a/gradle.properties b/gradle.properties index 39a29da..da27a7a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx2G org.gradle.parallel=true # Mod properties -mod_version = 1.1.5 +mod_version = 1.1.5+dev maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib diff --git a/minecraft/common/src/main/resources/assets/player_animation_library/player_animations/wavehy.blockyanim b/minecraft/common/src/main/resources/assets/player_animation_library/player_animations/wavehy.blockyanim new file mode 100644 index 0000000..7a60945 --- /dev/null +++ b/minecraft/common/src/main/resources/assets/player_animation_library/player_animations/wavehy.blockyanim @@ -0,0 +1,1117 @@ +{ + "duration": 120, + "holdLastKeyframe": false, + "nodeAnimations": { + "L-Arm": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.026375, + "y": -0.020314, + "z": 0.017938, + "w": 0.999285 + }, + "interpolationType": "smooth" + }, { + "time": 20, + "delta": { + "x": 0.022799, + "y": -0.020589, + "z": 0.04251, + "w": 0.998624 + }, + "interpolationType": "smooth" + }, { + "time": 40, + "delta": { + "x": 0.019718, + "y": -0.019145, + "z": 0.011385, + "w": 0.999557 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.022799, + "y": -0.020589, + "z": 0.04251, + "w": 0.998624 + }, + "interpolationType": "smooth" + }, { + "time": 80, + "delta": { + "x": 0.019308, + "y": -0.019025, + "z": 0.020558, + "w": 0.999421 + }, + "interpolationType": "smooth" + }, { + "time": 100, + "delta": { + "x": 0.021965, + "y": -0.018989, + "z": 0.045559, + "w": 0.99854 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R-Arm": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.025941, + "y": 0.020268, + "z": -0.01793, + "w": 0.999297 + }, + "interpolationType": "smooth" + }, { + "time": 15, + "delta": { + "x": -0.700871, + "y": -0.152173, + "z": -0.397702, + "w": 0.572237 + }, + "interpolationType": "smooth" + }, { + "time": 30, + "delta": { + "x": -0.47296, + "y": -0.407951, + "z": -0.380433, + "w": 0.682023 + }, + "interpolationType": "smooth" + }, { + "time": 45, + "delta": { + "x": 0.72567, + "y": 0.180487, + "z": 0.490968, + "w": -0.446965 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.58103, + "y": 0.339661, + "z": 0.494003, + "w": -0.55045 + }, + "interpolationType": "smooth" + }, { + "time": 75, + "delta": { + "x": 0.72079, + "y": 0.191678, + "z": 0.471805, + "w": -0.470235 + }, + "interpolationType": "smooth" + }, { + "time": 90, + "delta": { + "x": -0.494255, + "y": -0.395636, + "z": -0.405003, + "w": 0.659664 + }, + "interpolationType": "smooth" + }, { + "time": 105, + "delta": { + "x": 0.682615, + "y": 0.243175, + "z": 0.463967, + "w": -0.509546 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R-Forearm": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.070992, + "y": 0, + "z": 0, + "w": 0.997477 + }, + "interpolationType": "smooth" + }, { + "time": 15, + "delta": { + "x": 0.279945, + "y": 0, + "z": 0, + "w": -0.960016 + }, + "interpolationType": "smooth" + }, { + "time": 30, + "delta": { + "x": -0.065403, + "y": 0, + "z": 0, + "w": 0.997859 + }, + "interpolationType": "smooth" + }, { + "time": 45, + "delta": { + "x": -0.371541, + "y": 0, + "z": 0, + "w": 0.928417 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": -0.087156, + "y": 0, + "z": 0, + "w": 0.996195 + }, + "interpolationType": "smooth" + }, { + "time": 75, + "delta": { + "x": -0.371541, + "y": 0, + "z": 0, + "w": 0.928417 + }, + "interpolationType": "smooth" + }, { + "time": 90, + "delta": { + "x": -0.087156, + "y": 0, + "z": 0, + "w": 0.996195 + }, + "interpolationType": "smooth" + }, { + "time": 105, + "delta": { + "x": -0.371541, + "y": 0, + "z": 0, + "w": 0.928417 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L-Forearm": { + "position": [], + "orientation": [ { + "time": 20, + "delta": { + "x": -0.065403, + "y": 0, + "z": 0, + "w": 0.997859 + }, + "interpolationType": "smooth" + }, { + "time": 80, + "delta": { + "x": -0.087156, + "y": 0, + "z": 0, + "w": 0.996195 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Cape1": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.023376, + "y": 0, + "z": 0, + "w": 0.999727 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": -0.020254, + "y": 0, + "z": 0, + "w": 0.999795 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Cape2": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.043619, + "y": 0, + "z": 0, + "w": 0.999048 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.021815, + "y": 0, + "z": 0, + "w": 0.999762 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Cape3": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.043619, + "y": 0, + "z": 0, + "w": 0.999048 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.021815, + "y": 0, + "z": 0, + "w": 0.999762 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Chest": { + "position": [], + "orientation": [ { + "time": 5, + "delta": { + "x": 0.043619, + "y": 0, + "z": 0, + "w": 0.999048 + }, + "interpolationType": "smooth" + }, { + "time": 25, + "delta": { + "x": 0.039037, + "y": 0.001479, + "z": -0.03784, + "w": 0.99852 + }, + "interpolationType": "smooth" + }, { + "time": 45, + "delta": { + "x": 0.043619, + "y": 0, + "z": 0, + "w": 0.999048 + }, + "interpolationType": "smooth" + }, { + "time": 65, + "delta": { + "x": 0.039037, + "y": 0.001479, + "z": -0.03784, + "w": 0.99852 + }, + "interpolationType": "smooth" + }, { + "time": 85, + "delta": { + "x": 0.043619, + "y": 0, + "z": 0, + "w": 0.999048 + }, + "interpolationType": "smooth" + }, { + "time": 105, + "delta": { + "x": 0.039037, + "y": 0.001479, + "z": -0.03784, + "w": 0.99852 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Belly": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.021815, + "y": 0, + "z": 0, + "w": 0.999762 + }, + "interpolationType": "smooth" + }, { + "time": 20, + "delta": { + "x": -0.023754, + "y": -0.000666, + "z": -0.02801, + "w": 0.999325 + }, + "interpolationType": "smooth" + }, { + "time": 40, + "delta": { + "x": -0.025814, + "y": -0.0001, + "z": -0.004205, + "w": 0.999658 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": -0.023754, + "y": -0.000666, + "z": -0.02801, + "w": 0.999325 + }, + "interpolationType": "smooth" + }, { + "time": 80, + "delta": { + "x": -0.025814, + "y": -0.0001, + "z": -0.004205, + "w": 0.999658 + }, + "interpolationType": "smooth" + }, { + "time": 100, + "delta": { + "x": -0.023754, + "y": -0.000666, + "z": -0.02801, + "w": 0.999325 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Head": { + "position": [], + "orientation": [ { + "time": 10, + "delta": { + "x": 0.017452, + "y": 0.000015, + "z": -0.000837, + "w": 0.999847 + }, + "interpolationType": "smooth" + }, { + "time": 30, + "delta": { + "x": 0.017452, + "y": -0.000103, + "z": 0.005919, + "w": 0.99983 + }, + "interpolationType": "smooth" + }, { + "time": 50, + "delta": { + "x": 0.017447, + "y": 0.000418, + "z": -0.02395, + "w": 0.999561 + }, + "interpolationType": "smooth" + }, { + "time": 70, + "delta": { + "x": 0.017452, + "y": -0.000103, + "z": 0.005919, + "w": 0.99983 + }, + "interpolationType": "smooth" + }, { + "time": 90, + "delta": { + "x": 0.017447, + "y": 0.000418, + "z": -0.02395, + "w": 0.999561 + }, + "interpolationType": "smooth" + }, { + "time": 110, + "delta": { + "x": 0.017452, + "y": -0.000103, + "z": 0.005919, + "w": 0.99983 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R-Thigh": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.021637, + "y": -0.006414, + "z": -0.026289, + "w": 0.9994 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.000169, + "y": -0.00546, + "z": -0.026107, + "w": 0.999644 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L-Thigh": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.021842, + "y": -0.000416, + "z": 0.026079, + "w": 0.999421 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": -0.000035, + "y": -0.000986, + "z": 0.026142, + "w": 0.999658 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L-Foot": { + "position": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": -0.006238, + "y": -0.003309, + "z": -0.380529 + }, + "interpolationType": "smooth" + } ], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.02617, + "y": 0.000074, + "z": -0.026157, + "w": 0.999315 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": -0.000013, + "y": 0.001519, + "z": -0.026107, + "w": 0.999658 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R-Foot": { + "position": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.006238, + "y": -0.00331, + "z": -0.38053 + }, + "interpolationType": "smooth" + } ], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.026145, + "y": 0.002574, + "z": 0.026069, + "w": 0.999315 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.000013, + "y": 0.001519, + "z": 0.026107, + "w": 0.999658 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L_Side_Cloth_1": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.000485, + "y": 0.001803, + "z": 0.001082, + "w": 0.999998 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.00009, + "y": 0.000337, + "z": -0.000009, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R_Side_Cloth_1": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.000575, + "y": -0.002132, + "z": -0.00151, + "w": 0.999996 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0.00009, + "y": -0.000337, + "z": 0.000009, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Back_Cloth_1": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Back_Cloth_2": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": -0.087156, + "y": 0, + "z": 0, + "w": 0.996195 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Front_Cloth_1": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Front_Cloth_2": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.087156, + "y": 0, + "z": 0, + "w": 0.996195 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R-Hand": { + "position": [], + "orientation": [ { + "time": 30, + "delta": { + "x": -0.041636, + "y": 0.045437, + "z": 0.045437, + "w": 0.997064 + }, + "interpolationType": "smooth" + }, { + "time": 90, + "delta": { + "x": -0.06338, + "y": 0.046335, + "z": 0.046335, + "w": 0.995836 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L-Hand": { + "position": [], + "orientation": [ { + "time": 40, + "delta": { + "x": -0.041636, + "y": -0.045437, + "z": -0.045437, + "w": 0.997064 + }, + "interpolationType": "smooth" + }, { + "time": 100, + "delta": { + "x": -0.06338, + "y": -0.046335, + "z": -0.046335, + "w": 0.995836 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R_Side_Cloth_Side_R": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0.130526, + "z": 0, + "w": 0.991445 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L_Side_Cloth_Side_L": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": -0.130526, + "z": 0, + "w": 0.991445 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L_Side_Cloth_Side_R": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0.130526, + "z": 0, + "w": 0.991445 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R_Side_Cloth_Side_L": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": -0.130526, + "z": 0, + "w": 0.991445 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Back_Cloth_R": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Back_Cloth_L": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Front_Cloth_R": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Front_Cloth_L": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L_Side_Cloth_2": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.002847, + "y": -0.021628, + "z": -0.043609, + "w": 0.99881 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R_Side_Cloth_2": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.002847, + "y": 0.021628, + "z": 0.043609, + "w": 0.99881 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "R-Eyebrow": { + "position": [ { + "time": 0, + "delta": { + "x": 0, + "y": 1, + "z": 0 + }, + "interpolationType": "smooth" + } ], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": 0.043619, + "w": 0.999048 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L-Eyebrow": { + "position": [ { + "time": 0, + "delta": { + "x": 0, + "y": 1, + "z": 0 + }, + "interpolationType": "smooth" + } ], + "orientation": [ { + "time": 0, + "delta": { + "x": 0, + "y": 0, + "z": -0.043619, + "w": 0.999048 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Mouth": { + "position": [], + "orientation": [], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [ { + "time": 0, + "delta": { + "x": 0, + "y": -10 + } + } ] + }, + "R-Calf": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.043619, + "y": 0, + "z": 0, + "w": 0.999048 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "L-Calf": { + "position": [], + "orientation": [ { + "time": 0, + "delta": { + "x": 0.043619, + "y": 0, + "z": 0, + "w": 0.999048 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "interpolationType": "smooth" + } ], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + }, + "Pelvis": { + "position": [ { + "time": 0, + "delta": { + "x": 0, + "y": -0.925, + "z": -0.15 + }, + "interpolationType": "smooth" + }, { + "time": 60, + "delta": { + "x": 0, + "y": -0.5, + "z": 0 + }, + "interpolationType": "smooth" + } ], + "orientation": [], + "shapeStretch": [], + "shapeVisible": [], + "shapeUvOffset": [] + } + }, + "formatVersion": 1 +} \ No newline at end of file From 9f9f25a104481b0134efcaa2835260df79b0a03e Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sun, 18 Jan 2026 12:18:04 +0700 Subject: [PATCH 3/3] works --- .../loading/BlockyAnimLoader.java | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java b/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java index 8aded19..14c6e56 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/loading/BlockyAnimLoader.java @@ -30,32 +30,35 @@ public class BlockyAnimLoader implements JsonDeserializer { private static final Map RENAMES = Map.of( "head", "headhy" ); + + private static final float SCALE = 24.0f / 87.0f; + private static final Map PIVOTS = Map.ofEntries( // Body entry("origin", new Vec3f(0, 0, 0)), - entry("pelvis", new Vec3f(0, 51, 0)), - entry("belly", new Vec3f(0, 55, 0)), - entry("chest", new Vec3f(0, 68, -3)), + entry("pelvis", new Vec3f(0, 51 * SCALE, 0)), + entry("belly", new Vec3f(0, 55 * SCALE, 0)), + entry("chest", new Vec3f(0, 68 * SCALE, -3 * SCALE)), // Head - entry("headhy", new Vec3f(0, 87, -1)), + entry("headhy", new Vec3f(0, 87 * SCALE, -1 * SCALE)), // Right Arm - entry("r-shoulder", new Vec3f(-14.5017F, 86.594F, -0.9388F)), - entry("r-arm", new Vec3f(-14.5017F, 86.594F, -0.9388F)), + entry("r-shoulder", new Vec3f(14.5f * SCALE, 86.6f * SCALE, -0.94f * SCALE)), + entry("r-arm", new Vec3f(14.5f * SCALE, 86.6f * SCALE, -0.94f * SCALE)), // Left Arm - entry("l-shoulder", new Vec3f(14.5017F, 86.594F, -0.9388F)), - entry("l-arm", new Vec3f(14.5017F, 86.594F, -0.9388F)), + entry("l-shoulder", new Vec3f(-14.5f * SCALE, 86.6f * SCALE, -0.94f * SCALE)), + entry("l-arm", new Vec3f(-14.5f * SCALE, 86.6f * SCALE, -0.94f * SCALE)), // Right Leg - entry("r-thigh", new Vec3f(-7.5F, 50, 1)), + entry("r-thigh", new Vec3f(7.5f * SCALE, 50 * SCALE, 1 * SCALE)), // Left Leg - entry("l-thigh", new Vec3f(7.5F, 50, 1)), + entry("l-thigh", new Vec3f(-7.5f * SCALE, 50 * SCALE, 1 * SCALE)), // Cape - entry("back-attachment", new Vec3f(0, 79, -18)) + entry("back-attachment", new Vec3f(0, 79 * SCALE, -18 * SCALE)) ); private static final Map PARENTS = Map.ofEntries( // Body @@ -83,11 +86,11 @@ public class BlockyAnimLoader implements JsonDeserializer { // Right Leg entry("r-thigh", "pelvis"), - entry("right_leg", "r-thigh"), + entry("right_leg", "r-thigh"), // Minecraft // Left Leg entry("l-thigh", "pelvis"), - entry("left_leg", "l-thigh"), + entry("left_leg", "l-thigh"), // Minecraft // Cape entry("back-attachment", "chest"), @@ -148,11 +151,11 @@ private KeyframeStack parseStack(JsonArray json, TransformType type) { if (type == TransformType.ROTATION) { Vector3f vector3f = new Quaternionf( delta.get("x").getAsFloat(), delta.get("y").getAsFloat(), delta.get("z").getAsFloat(), delta.get("w").getAsFloat() - ).getEulerAnglesXYZ(new Vector3f()); + ).normalize().getEulerAnglesZYX(new Vector3f()); xValue = Collections.singletonList(FloatExpression.of(vector3f.x())); - yValue = Collections.singletonList(FloatExpression.of(vector3f.y())); - zValue = Collections.singletonList(FloatExpression.of(vector3f.z())); + yValue = Collections.singletonList(FloatExpression.of(-vector3f.y())); + zValue = Collections.singletonList(FloatExpression.of(-vector3f.z())); } else { xValue = MolangLoader.parseJson(false, delta.get("x"), defaultValue); yValue = MolangLoader.parseJson(false, delta.get("y"), defaultValue); @@ -164,9 +167,7 @@ private KeyframeStack parseStack(JsonArray json, TransformType type) { yFrames.add(new Keyframe(timeDelta, yPrev == null ? yValue : yPrev, yValue, easingType, Collections.emptyList())); zFrames.add(new Keyframe(timeDelta, zPrev == null ? zValue : zPrev, zValue, easingType, Collections.emptyList())); - xPrev = xValue; - yPrev = yValue; - zPrev = zValue; + xPrev = xValue; yPrev = yValue; zPrev = zValue; prevTime = curTime; }