From 23105ebf060c26166669f601dddd14bef38f27e2 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Fri, 6 Feb 2026 22:53:41 +0700 Subject: [PATCH 01/28] basic --- .github/workflows/release.yml | 4 +- build.gradle | 14 ++++-- gradle.properties | 9 ++-- minecraft/build.gradle | 20 ++------ minecraft/common/build.gradle | 10 ++-- .../playeranim/molang/MolangQueries.java | 2 +- .../main/resources/architectury.common.json | 11 ----- .../main/resources/architectury.common.marker | 0 .../player_animation_library.accesswidener | 5 +- minecraft/fabric/build.gradle | 49 ++++++++----------- .../fabric/PlayerAnimLibModFabric.java | 2 +- minecraft/neoforge/build.gradle | 45 +++++++---------- minecraft/neoforge/gradle.properties | 1 - settings.gradle | 7 ++- 14 files changed, 73 insertions(+), 106 deletions(-) delete mode 100644 minecraft/common/src/main/resources/architectury.common.json delete mode 100644 minecraft/common/src/main/resources/architectury.common.marker delete mode 100644 minecraft/neoforge/gradle.properties diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 79d7d565..30a3ba03 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'adopt' - java-version: 21 + java-version: 25 - name: Grant Execute Permission run: chmod +x gradlew @@ -61,7 +61,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'adopt' - java-version: 21 + java-version: 25 - name: Get Artifact Id uses: actions/github-script@v5 diff --git a/build.gradle b/build.gradle index 3be9f587..9adb81c7 100644 --- a/build.gradle +++ b/build.gradle @@ -3,13 +3,13 @@ import org.apache.commons.lang3.StringUtils plugins { id "org.redlance.dima_dencep.gradle.PublishToDiscord" version "1.0.6" - id "dev.architectury.loom" version "1.13-SNAPSHOT" apply false - id "architectury-plugin" version "3.4-SNAPSHOT" apply false + id "xyz.wagyourtail.unimined" version "1.4.2" apply false id "com.gradleup.shadow" version "9.3.0" apply false } allprojects { apply plugin: "java" + apply plugin: "java-library" apply plugin: "maven-publish" base.archivesName = "${rootProject.archives_base_name}${StringUtils.capitalize(project.name)}" @@ -32,11 +32,19 @@ allprojects { name = "RedlanceMinecraft" url = "https://repo.redlance.org/public" } + maven { + name = "Maven for PR #2879" // https://github.com/neoforged/NeoForge/pull/2879 + url = uri("https://prmaven.neoforged.net/NeoForge/pr2879") + content { + includeModule("net.neoforged", "neoforge") + includeModule("net.neoforged", "testframework") + } + } } tasks.withType(JavaCompile).configureEach { options.encoding = "UTF-8" - options.release.set 21 + options.release.set 25 } java { diff --git a/gradle.properties b/gradle.properties index 7028a9de..2bfb2d41 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,12 +8,11 @@ maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib # Minecraft properties -minecraft_version = 1.21.11 -parchment_version = 2025.12.20 +minecraft_version = 26.1-snapshot-6 # Dependencies -fabric_loader_version = 0.18.3 -fabric_api_version = 0.140.2+1.21.11 -neoforge_version = 21.11.13-beta +fabric_loader_version = 0.18.4 +fabric_api_version = 0.143.2+26.1 +neoforge_version = 26.1.0.0-alpha.0+snapshot-6.20260203.212009 molang_version = 4.1.5 javassist_version = 3.30.2-GA diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 1896e1fa..76bb5c16 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -1,17 +1,8 @@ -plugins { - id "architectury-plugin" -} - -architectury { - minecraft = rootProject.minecraft_version -} - subprojects { - apply plugin: "architectury-plugin" - apply plugin: "dev.architectury.loom" + apply plugin: "xyz.wagyourtail.unimined" - loom { - silentMojangMappingsLicense() + unimined.minecraft(sourceSets.main, true) { + version rootProject.minecraft_version } jar { @@ -20,11 +11,6 @@ subprojects { } dependencies { - minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip") - } implementation project(":core") } diff --git a/minecraft/common/build.gradle b/minecraft/common/build.gradle index f72ddb67..fda9c3c1 100644 --- a/minecraft/common/build.gradle +++ b/minecraft/common/build.gradle @@ -1,9 +1,13 @@ -loom { - accessWidenerPath = file("src/main/resources/player_animation_library.accesswidener") +unimined.minecraft { + fabric { + loader rootProject.fabric_loader_version + accessWidener file("src/main/resources/player_animation_library.accesswidener") + } + + defaultRemapJar = false } dependencies { - modCompileOnly "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" implementation project(path: ":core") } diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/molang/MolangQueries.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/molang/MolangQueries.java index adb6e600..2e202f15 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/molang/MolangQueries.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/molang/MolangQueries.java @@ -154,7 +154,7 @@ public static void setDefaultQueryValues(QueryBinding bindi return 0.0D; } }); - MolangLoader.setDoubleQuery(binding, TIME_OF_DAY, actor -> ((PlayerAnimationController) actor).getAvatar().level().getDayTime() / 24000d); + MolangLoader.setDoubleQuery(binding, TIME_OF_DAY, actor -> ((PlayerAnimationController) actor).getAvatar().level().getDefaultClockTime() / 24000d); MolangLoader.setDoubleQuery(binding, TIME_STAMP, actor -> ((PlayerAnimationController) actor).getAvatar().level().getGameTime()); setDefaultEntityQueryValues(binding); diff --git a/minecraft/common/src/main/resources/architectury.common.json b/minecraft/common/src/main/resources/architectury.common.json deleted file mode 100644 index ab4f3715..00000000 --- a/minecraft/common/src/main/resources/architectury.common.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "injected_interfaces": { - "net/minecraft/class_11890": [ - "com/zigythebird/playeranim/accessors/IAnimatedAvatar" - ], - "net/minecraft/class_10055": [ - "com/zigythebird/playeranim/accessors/IAvatarAnimationState" - ] - }, - "accessWidener": "player_animation_library.accesswidener" -} \ No newline at end of file diff --git a/minecraft/common/src/main/resources/architectury.common.marker b/minecraft/common/src/main/resources/architectury.common.marker deleted file mode 100644 index e69de29b..00000000 diff --git a/minecraft/common/src/main/resources/player_animation_library.accesswidener b/minecraft/common/src/main/resources/player_animation_library.accesswidener index 50690074..50bfba25 100644 --- a/minecraft/common/src/main/resources/player_animation_library.accesswidener +++ b/minecraft/common/src/main/resources/player_animation_library.accesswidener @@ -1,6 +1,5 @@ -accessWidener v2 named - +accessWidener v2 official extendable class net/minecraft/client/model/geom/ModelPart accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; -accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; \ No newline at end of file +accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; diff --git a/minecraft/fabric/build.gradle b/minecraft/fabric/build.gradle index d6efe654..cb939d62 100644 --- a/minecraft/fabric/build.gradle +++ b/minecraft/fabric/build.gradle @@ -2,63 +2,54 @@ plugins { id "com.gradleup.shadow" } -loom { - accessWidenerPath = project(":minecraft:common").loom.accessWidenerPath -} +unimined.minecraft { + // Combine with common, for identifying both together as one mod for dev runs + combineWith(project(":minecraft:common").sourceSets.main) -architectury { - platformSetupLoomIde() - fabric() + fabric { + loader project.fabric_loader_version + accessWidener project(":minecraft:common").file("src/main/resources/player_animation_library.accesswidener") + } } configurations { - shadowCommon - compileClasspath.extendsFrom shadowCommon - runtimeClasspath.extendsFrom shadowCommon - developmentFabric.extendsFrom shadowCommon + shadow + compileClasspath.extendsFrom shadow + runtimeClasspath.extendsFrom shadow } dependencies { - modImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" + implementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" // Fabric API - modApi fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version) - modApi fabricApi.module("fabric-resource-loader-v1", rootProject.fabric_api_version) + api fabricApi.fabricModule("fabric-command-api-v2", rootProject.fabric_api_version) + api fabricApi.fabricModule("fabric-resource-loader-v1", rootProject.fabric_api_version) - implementation api(include("com.zigythebird:mochafloats:$rootProject.molang_version")) { + api(include("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false - } - modRuntimeOnly include("org.javassist:javassist:$rootProject.javassist_version") + }) + runtimeOnly include("org.javassist:javassist:$rootProject.javassist_version") - shadowCommon(project(path: ":minecraft:common", configuration: "namedElements")) { transitive = false } - shadowCommon(project(path: ":core")) { transitive = false } + shadow(project(path: ":core")) { transitive = false } } shadowJar { - configurations = [project.configurations.shadowCommon] + configurations = [project.configurations.shadow] archiveClassifier = 'dev-shadow' mergeServiceFiles() exclude "architectury.common.marker" } -remapJar { - injectAccessWidener = true - - inputFile.set shadowJar.archiveFile - dependsOn shadowJar - archiveClassifier.set null -} - jar { archiveClassifier.set "dev" } -sourcesJar { +/*sourcesJar { def commonSources = project(":minecraft:common").sourcesJar dependsOn commonSources from commonSources.archiveFile.map { zipTree(it) } -} +}*/ shadow { addShadowVariantIntoJavaComponent = false diff --git a/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibModFabric.java b/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibModFabric.java index 44752d95..2141c695 100644 --- a/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibModFabric.java +++ b/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibModFabric.java @@ -12,7 +12,7 @@ public final class PlayerAnimLibModFabric extends PlayerAnimLibMod implements ClientModInitializer { @Override public void onInitializeClient() { - ResourceLoader.get(PackType.CLIENT_RESOURCES).registerReloader(PlayerAnimResources.KEY, new PlayerAnimResources()); + ResourceLoader.get(PackType.CLIENT_RESOURCES).registerReloadListener(PlayerAnimResources.KEY, new PlayerAnimResources()); if (FabricLoader.getInstance().isDevelopmentEnvironment() || FabricLoader.getInstance().getModContainer(PlayerAnimLibMod.MOD_ID).get().getMetadata().getVersion().getFriendlyString().contains("dev")) ClientCommandRegistrationCallback.EVENT.register(PlayerAnimCommands::register); diff --git a/minecraft/neoforge/build.gradle b/minecraft/neoforge/build.gradle index 7e067092..c384948e 100644 --- a/minecraft/neoforge/build.gradle +++ b/minecraft/neoforge/build.gradle @@ -2,32 +2,33 @@ plugins { id "com.gradleup.shadow" } -loom { - accessWidenerPath = project(":minecraft:common").loom.accessWidenerPath -} +unimined.minecraft { + // Combine with common, for identifying both together as one mod for dev runs + combineWith(project(":minecraft::common").sourceSets.main) + + neoForged { + loader rootProject.neoforge_version + mixinConfig("player_animation_library.mixins.json") -architectury { - platformSetupLoomIde() - neoForge() + //accessTransformer aw2at(project(":minecraft:common").unimined.minecraft.fabric.accessWidener) + } } configurations { - shadowCommon - compileClasspath.extendsFrom shadowCommon - runtimeClasspath.extendsFrom shadowCommon - developmentNeoForge.extendsFrom shadowCommon + shadow + compileClasspath.extendsFrom shadow + runtimeClasspath.extendsFrom shadow } dependencies { neoForge "net.neoforged:neoforge:$rootProject.neoforge_version" - implementation forgeRuntimeLibrary(api(include("com.zigythebird:mochafloats:$rootProject.molang_version"))) { + /* api(include("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false - } - modRuntimeOnly forgeRuntimeLibrary(include("org.javassist:javassist:$rootProject.javassist_version")) + }) + modRuntimeOnly include("org.javassist:javassist:$rootProject.javassist_version"))*/ - shadowCommon(project(path: ":minecraft:common", configuration: "namedElements")) { transitive = false } - shadowCommon(project(path: ":core")) { transitive = false } + shadow(project(path: ":core")) { transitive = false } } shadowJar { @@ -35,29 +36,21 @@ shadowJar { exclude "architectury.common.json" exclude "architectury.common.marker" - configurations = [project.configurations.shadowCommon] + configurations = [project.configurations.shadow] archiveClassifier.set "dev-shadow" mergeServiceFiles() } -remapJar { - atAccessWideners.add(loom.accessWidenerPath.get().asFile.name) - - inputFile.set shadowJar.archiveFile - dependsOn shadowJar - archiveClassifier.set null -} - jar { archiveClassifier.set "dev" } -sourcesJar { +/*sourcesJar { def commonSources = project(":minecraft:common").sourcesJar dependsOn commonSources from commonSources.archiveFile.map { zipTree(it) } -} +}*/ shadow { addShadowVariantIntoJavaComponent = false diff --git a/minecraft/neoforge/gradle.properties b/minecraft/neoforge/gradle.properties deleted file mode 100644 index 2e6ed767..00000000 --- a/minecraft/neoforge/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -loom.platform = neoforge diff --git a/settings.gradle b/settings.gradle index bf4d7959..11fba2b3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,8 @@ pluginManagement { repositories { - maven { url = "https://maven.fabricmc.net/" } - maven { url = "https://maven.architectury.dev/" } - maven { url = "https://maven.neoforged.net/releases" } maven { url = "https://repo.redlance.org/public" } + maven { url = "https://maven.wagyourtail.xyz/releases" } + maven { url = "https://maven.wagyourtail.xyz/snapshots" } gradlePluginPortal() } } @@ -15,4 +14,4 @@ include("minecraft") include("minecraft:common") include("minecraft:fabric") -include("minecraft:neoforge") +// include("minecraft:neoforge") From a8c6afb771a5b2bdcc0c98ca4fef0b39db39e2b2 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Fri, 6 Feb 2026 23:01:26 +0700 Subject: [PATCH 02/28] Migrate to classTweaker --- minecraft/common/build.gradle | 2 +- ...ry.accesswidener => player_animation_library.classtweaker} | 4 +++- minecraft/fabric/build.gradle | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) rename minecraft/common/src/main/resources/{player_animation_library.accesswidener => player_animation_library.classtweaker} (61%) diff --git a/minecraft/common/build.gradle b/minecraft/common/build.gradle index fda9c3c1..38a7bf48 100644 --- a/minecraft/common/build.gradle +++ b/minecraft/common/build.gradle @@ -1,7 +1,7 @@ unimined.minecraft { fabric { loader rootProject.fabric_loader_version - accessWidener file("src/main/resources/player_animation_library.accesswidener") + accessWidener file("src/main/resources/player_animation_library.classtweaker") } defaultRemapJar = false diff --git a/minecraft/common/src/main/resources/player_animation_library.accesswidener b/minecraft/common/src/main/resources/player_animation_library.classtweaker similarity index 61% rename from minecraft/common/src/main/resources/player_animation_library.accesswidener rename to minecraft/common/src/main/resources/player_animation_library.classtweaker index 50bfba25..4230fc4b 100644 --- a/minecraft/common/src/main/resources/player_animation_library.accesswidener +++ b/minecraft/common/src/main/resources/player_animation_library.classtweaker @@ -1,5 +1,7 @@ -accessWidener v2 official +classTweaker v1 official extendable class net/minecraft/client/model/geom/ModelPart accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; +inject-interface com/zigythebird/playeranim/accessors/IAnimatedAvatar net/minecraft/world/entity/Avatar +inject-interface com/zigythebird/playeranim/accessors/IAvatarAnimationState net/minecraft/client/renderer/entity/state/AvatarRenderState diff --git a/minecraft/fabric/build.gradle b/minecraft/fabric/build.gradle index cb939d62..92892fe9 100644 --- a/minecraft/fabric/build.gradle +++ b/minecraft/fabric/build.gradle @@ -8,7 +8,7 @@ unimined.minecraft { fabric { loader project.fabric_loader_version - accessWidener project(":minecraft:common").file("src/main/resources/player_animation_library.accesswidener") + accessWidener project(":minecraft:common").file("src/main/resources/player_animation_library.classtweaker") } } From b626fd5703ba47a1fcc2b766101b5a362fd45242 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Fri, 6 Feb 2026 23:02:31 +0700 Subject: [PATCH 03/28] get rid of deprecated stuff --- .../zigythebird/playeranim/PlayerAnimLibPlatform.java | 9 --------- .../com/zigythebird/playeranim/accessors/ICapeLayer.java | 9 --------- .../playeranim/mixin/PlayerCapeModelMixin.java | 6 ++---- 3 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibPlatform.java delete mode 100644 minecraft/common/src/main/java/com/zigythebird/playeranim/accessors/ICapeLayer.java diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibPlatform.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibPlatform.java deleted file mode 100644 index 032826dc..00000000 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibPlatform.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.zigythebird.playeranim; - -@Deprecated(forRemoval = true) -public class PlayerAnimLibPlatform { - @Deprecated(forRemoval = true) - public static boolean isModLoaded(String id) { - return PlayerAnimLibService.INSTANCE.isModLoaded(id); - } -} diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/accessors/ICapeLayer.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/accessors/ICapeLayer.java deleted file mode 100644 index 0eb40c85..00000000 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/accessors/ICapeLayer.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.zigythebird.playeranim.accessors; - -import com.zigythebird.playeranim.animation.AvatarAnimManager; - -@Deprecated(forRemoval = true) -public interface ICapeLayer { - default void applyBend(AvatarAnimManager manager, float bend) {} - default void resetBend() {} -} diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java index c0c44b8a..ab7a4ca1 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java @@ -2,7 +2,6 @@ import com.zigythebird.playeranim.accessors.IAvatarAnimationState; import com.zigythebird.playeranim.accessors.IBoneUpdater; -import com.zigythebird.playeranim.accessors.ICapeLayer; import com.zigythebird.playeranim.animation.AvatarAnimManager; import com.zigythebird.playeranim.util.RenderUtil; import com.zigythebird.playeranimcore.bones.PlayerAnimBone; @@ -20,7 +19,7 @@ //Set the priority high cause why not! @Mixin(value = PlayerCapeModel.class, priority = 2001) -public class PlayerCapeModelMixin implements IBoneUpdater, ICapeLayer { +public class PlayerCapeModelMixin implements IBoneUpdater { @Shadow @Final private ModelPart cape; @@ -50,11 +49,10 @@ private void setupAnim(AvatarRenderState avatarRenderState, CallbackInfo ci) { @Override public void pal$updatePart(AvatarAnimManager emote, ModelPart part, PlayerAnimBone bone) { RenderUtil.translatePartToCape(part, bone, part.getInitialPose()); - this.applyBend(emote, bone.getBend()); } @Override public void pal$resetAll(@Nullable AvatarAnimManager emote) { - this.resetBend(); + // no-op } } From e803658a0093dfe39e614556fd3521eb07518243 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Fri, 6 Feb 2026 23:05:59 +0700 Subject: [PATCH 04/28] Update player_animation_library.classtweaker --- .../src/main/resources/player_animation_library.classtweaker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minecraft/common/src/main/resources/player_animation_library.classtweaker b/minecraft/common/src/main/resources/player_animation_library.classtweaker index 4230fc4b..cd3470de 100644 --- a/minecraft/common/src/main/resources/player_animation_library.classtweaker +++ b/minecraft/common/src/main/resources/player_animation_library.classtweaker @@ -1,4 +1,4 @@ -classTweaker v1 official +classTweaker v1 named extendable class net/minecraft/client/model/geom/ModelPart accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; From 0005dc21410e02aebbb57e69d3f3dc5b0844301a Mon Sep 17 00:00:00 2001 From: Zigy <105124180+ZigyTheBird@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:37:55 +0330 Subject: [PATCH 05/28] Better RawAnimation (#83) --- .../playeranimcore/animation/Animation.java | 3 +- .../animation/AnimationController.java | 9 +--- .../animation/RawAnimation.java | 53 ++++++++++++------- .../playeranimcore/enums/AnimationStage.java | 6 --- 4 files changed, 35 insertions(+), 36 deletions(-) delete mode 100644 core/src/main/java/com/zigythebird/playeranimcore/enums/AnimationStage.java diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/Animation.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/Animation.java index 12411667..b93786fc 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/Animation.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/Animation.java @@ -30,7 +30,6 @@ import com.zigythebird.playeranimcore.animation.keyframe.event.data.CustomInstructionKeyframeData; import com.zigythebird.playeranimcore.animation.keyframe.event.data.ParticleKeyframeData; import com.zigythebird.playeranimcore.animation.keyframe.event.data.SoundKeyframeData; -import com.zigythebird.playeranimcore.enums.AnimationStage; import com.zigythebird.playeranimcore.loading.UniversalAnimLoader; import com.zigythebird.playeranimcore.math.Vec3f; import org.jetbrains.annotations.NotNull; @@ -54,7 +53,7 @@ public int hashCode() { } static Animation generateWaitAnimation(float length) { - return new Animation(new ExtraAnimationData(ExtraAnimationData.NAME_KEY, AnimationStage.WAIT.name()), length, LoopType.PLAY_ONCE, + return new Animation(new ExtraAnimationData(ExtraAnimationData.NAME_KEY, "internal.wait"), length, LoopType.PLAY_ONCE, Collections.emptyMap(), UniversalAnimLoader.NO_KEYFRAMES, new HashMap<>(), new HashMap<>()); } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java index f017c5cc..f9ad2f3b 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java @@ -41,7 +41,6 @@ import com.zigythebird.playeranimcore.api.firstPerson.FirstPersonMode; import com.zigythebird.playeranimcore.bones.*; import com.zigythebird.playeranimcore.easing.EasingType; -import com.zigythebird.playeranimcore.enums.AnimationStage; import com.zigythebird.playeranimcore.enums.PlayState; import com.zigythebird.playeranimcore.enums.State; import com.zigythebird.playeranimcore.enums.TransformType; @@ -364,13 +363,7 @@ protected void setAnimation(RawAnimation rawAnimation) { protected Queue getQueuedAnimations(RawAnimation rawAnimation) { LinkedList animations = new LinkedList<>(); for (RawAnimation.Stage stage : rawAnimation.getAnimationStages()) { - Animation animation; - if (stage.stage() == AnimationStage.WAIT) { // This is intentional. Do not change this or T̶s̶l̶a̶t̶ I will be unhappy!!! - animation = Animation.generateWaitAnimation(stage.additionalTicks()); - } else { - animation = stage.animation(); - } - + Animation animation = stage.animation(); if (animation != null) animations.add(new QueuedAnimation(animation, stage.loopType())); } return animations; diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/RawAnimation.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/RawAnimation.java index 3879df4e..0d789232 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/RawAnimation.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/RawAnimation.java @@ -9,10 +9,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -24,17 +24,14 @@ package com.zigythebird.playeranimcore.animation; -import com.zigythebird.playeranimcore.enums.AnimationStage; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; /** - * A builder class for a raw/unbaked animation. These are constructed to pass to the - * {@link AnimationController} to build into full-fledged animations for usage - *

* Animations added to this builder are added in order of insertion - the animations will play in the order that you define them *

* RawAnimation instances should be cached statically where possible to reduce overheads and improve efficiency @@ -43,10 +40,17 @@ *

{@code RawAnimation.begin().thenPlay(openBox).thenLoop(stayOpen)}
*/ public final class RawAnimation { - private final List animationList = new ObjectArrayList<>(); + private final List animationList; // Private constructor to force usage of factory for logical operations - private RawAnimation() {} + private RawAnimation() { + this(new ObjectArrayList<>()); + } + + // Private constructor to force usage of factory for logical operations + private RawAnimation(List animationList) { + this.animationList = animationList; + } /** * Start a new RawAnimation instance. This is the start point for creating an animation chain @@ -84,7 +88,7 @@ public RawAnimation thenLoop(Animation animation) { * @param ticks The number of ticks to 'wait' for */ public RawAnimation thenWait(int ticks) { - this.animationList.add(new Stage(AnimationStage.WAIT, null, Animation.LoopType.PLAY_ONCE, ticks)); + this.animationList.add(new Stage(Animation.generateWaitAnimation(ticks), Animation.LoopType.PLAY_ONCE)); return this; } @@ -103,7 +107,7 @@ public RawAnimation thenPlayAndHold(Animation animation) { * Append an animation to the animation chain, playing the named animation playCount times, * then stopping or progressing to the next chained animation depending on the loop type set in the animation json * - * @param animation The animation to play X times + * @param animation The animation to play X times * @param playCount The number of times to repeat the animation before proceeding */ public RawAnimation thenPlayXTimes(Animation animation, int playCount) { @@ -146,6 +150,18 @@ public static RawAnimation copyOf(RawAnimation other) { return newInstance; } + @Override + public String toString() { + return "RawAnimation{" + this.animationList.stream().map(Stage::toString).collect(Collectors.joining(" -> ")) + "}"; + } + + /** + * Get the number of animation stages this RawAnimation contains + */ + public int getStageCount() { + return this.animationList.size(); + } + @Override public boolean equals(Object obj) { if (this == obj) @@ -167,15 +183,7 @@ public int hashCode() { *

* This is an entry object representing a single animation stage of the final compiled animation. */ - public record Stage(AnimationStage stage, @Nullable Animation animation, Animation.LoopType loopType, int additionalTicks) { - public Stage(AnimationStage stage, Animation animation, Animation.LoopType loopType) { - this(stage, animation, loopType, 0); - } - - public Stage(Animation animation, Animation.LoopType loopType) { - this(AnimationStage.ANIMATION, animation, loopType); - } - + public record Stage(@Nullable Animation animation, Animation.LoopType loopType) { @Override public boolean equals(Object obj) { if (this == obj) @@ -187,9 +195,14 @@ public boolean equals(Object obj) { return hashCode() == obj.hashCode(); } + @Override + public String toString() { + return animation == null ? "Invalid animation stage." : this.animation.toString(); + } + @Override public int hashCode() { - return Objects.hash(this.stage, this.animation, this.loopType); + return Objects.hash(this.animation, this.loopType); } } } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/enums/AnimationStage.java b/core/src/main/java/com/zigythebird/playeranimcore/enums/AnimationStage.java deleted file mode 100644 index 96283aff..00000000 --- a/core/src/main/java/com/zigythebird/playeranimcore/enums/AnimationStage.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.zigythebird.playeranimcore.enums; - -public enum AnimationStage { - WAIT, - ANIMATION -} From ac2598e8ab308119bca45f5f97a4e3909630ed45 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 7 Feb 2026 00:08:11 +0700 Subject: [PATCH 06/28] make get3DTransform return void (#89) --- .../playeranimcore/animation/AnimationController.java | 11 ++++++----- .../animation/layered/AnimationContainer.java | 5 ++--- .../animation/layered/AnimationSnapshot.java | 5 ++--- .../animation/layered/AnimationStack.java | 5 ++--- .../playeranimcore/animation/layered/IAnimation.java | 6 +++++- .../animation/layered/ModifierLayer.java | 9 +++++---- .../animation/layered/PlayerAnimationFrame.java | 5 ++--- .../layered/modifier/AbstractFadeModifier.java | 7 ++++--- .../layered/modifier/AdjustmentModifier.java | 9 +++++---- .../animation/layered/modifier/MirrorModifier.java | 10 ++++++---- .../playeranim/animation/AvatarAnimManager.java | 2 +- .../layered/modifier/MirrorIfLeftHandModifier.java | 6 +++--- .../playeranim/mixin/ElytraLayerMixin.java | 4 ++-- .../playeranim/mixin/LivingEntityRendererMixin.java | 2 +- .../playeranim/mixin/PlayerCapeModelMixin.java | 2 +- 15 files changed, 47 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java index f9ad2f3b..8faeed05 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java @@ -856,11 +856,12 @@ else if (hasEndTick() && extraData.get(ExtraAnimationData.END_TICK_KEY).g } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + public void get3DTransform(@NotNull PlayerAnimBone bone) { if (!modifiers.isEmpty()) { - return modifiers.getFirst().get3DTransform(bone); + modifiers.getFirst().get3DTransform(bone); + return; } - return get3DTransformRaw(bone); + get3DTransformRaw(bone); } @Override @@ -1075,8 +1076,8 @@ public void setupAnim(AnimationData state) { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { - return this.anim.get3DTransformRaw(bone); + public void get3DTransform(@NotNull PlayerAnimBone bone) { + this.anim.get3DTransformRaw(bone); } } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationContainer.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationContainer.java index a8d80301..5433348a 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationContainer.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationContainer.java @@ -69,9 +69,8 @@ public void tick(AnimationData state) { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { - if (anim != null) return anim.get3DTransform(bone); - return bone; + public void get3DTransform(@NotNull PlayerAnimBone bone) { + if (anim != null) anim.get3DTransform(bone); } @Override diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java index 24e53a12..5256a1d1 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java @@ -13,11 +13,10 @@ public boolean isActive() { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + public void get3DTransform(@NotNull PlayerAnimBone bone) { if (snapshots.containsKey(bone.getName())) { - return bone.copySnapshotSafe(snapshots.get(bone.getName())); + bone.copySnapshotSafe(snapshots.get(bone.getName())); } - return bone; } @Override diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationStack.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationStack.java index 65466bbb..82b5793f 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationStack.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationStack.java @@ -37,16 +37,15 @@ public void tick(AnimationData state) { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + public void get3DTransform(@NotNull PlayerAnimBone bone) { for (Pair layer : layers) { if (layer.right().isActive() /* Not sure if this is necessary, hard to implement rn && (!FirstPersonMode.isFirstPersonPass() || layer.right().getFirstPersonMode().isEnabled()) */) { - bone = layer.right().get3DTransform(bone); + layer.right().get3DTransform(bone); } } - return bone; } @Override diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/IAnimation.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/IAnimation.java index 039619b3..87aaff0b 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/IAnimation.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/IAnimation.java @@ -58,7 +58,11 @@ default void setupAnim(AnimationData state) {} * @param bone the bone being currently animated. * KEEP IN MIND THAT THE BONE RETURNED ISN'T ALWAYS THE SAME AS THE INPUT BONE! */ - default PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + void get3DTransform(@NotNull PlayerAnimBone bone); + + default PlayerAnimBone get3DTransform(@NotNull String name) { + PlayerAnimBone bone = new PlayerAnimBone(name); + get3DTransform(bone); return bone; } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/ModifierLayer.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/ModifierLayer.java index 7b9ef2f9..407b9504 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/ModifierLayer.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/ModifierLayer.java @@ -148,11 +148,12 @@ public boolean isActive() { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + public void get3DTransform(@NotNull PlayerAnimBone bone) { if (!modifiers.isEmpty()) { - return modifiers.get(0).get3DTransform(bone); - } else if (animation != null) return animation.get3DTransform(bone); - return bone; + modifiers.getFirst().get3DTransform(bone); + } else if (animation != null) { + animation.get3DTransform(bone); + } } @Override diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java index 551c75a5..be55a37b 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java @@ -92,10 +92,9 @@ public void enableAll() { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + public void get3DTransform(@NotNull PlayerAnimBone bone) { PlayerBone part = parts.get(bone.getName()); - if (part != null) return part.applyToBone(bone); - return bone; + if (part != null) part.applyToBone(bone); } public static class PlayerBone { diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AbstractFadeModifier.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AbstractFadeModifier.java index d6578b99..86fb015b 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AbstractFadeModifier.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AbstractFadeModifier.java @@ -84,9 +84,10 @@ public void tick(AnimationData state) { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + public void get3DTransform(@NotNull PlayerAnimBone bone) { if (calculateProgress(tickDelta, bone.getName()) > 1) { - return super.get3DTransform(bone); + super.get3DTransform(bone); + return; } PlayerAnimBone copy2 = new PlayerAnimBone(bone.getName()); copy2.copyOtherBone(bone); @@ -95,7 +96,7 @@ public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { if (getFadeType() == FadeType.FADE_IN) { if (transitionAnimation != null && transitionAnimation.isActive()) transitionAnimation.get3DTransform(bone); } - return bone.scale(1 - a).add(copy2.scale(a)); + bone.scale(1 - a).add(copy2.scale(a)); } protected float calculateProgress(float f, String boneName) { diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java index fcb166ae..a0c55a3a 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java @@ -207,9 +207,10 @@ protected float getFadeIn() { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { + public void get3DTransform(@NotNull PlayerAnimBone bone) { if (!enabled) { - return super.get3DTransform(bone); + super.get3DTransform(bone); + return; } Optional partModifier = source.apply(bone.getName(), data); @@ -218,9 +219,9 @@ public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { if (partModifier.isPresent()) { super.get3DTransform(bone); transformBone(bone, partModifier.get(), fade); - return bone; + return; } - return super.get3DTransform(bone); + super.get3DTransform(bone); } protected void transformBone(PlayerAnimBone bone, PartModifier partModifier, float fade) { diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java index bfece8c9..20502393 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java @@ -38,8 +38,11 @@ public class MirrorModifier extends AbstractModifier { public boolean enabled = true; @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { - if (!enabled) return super.get3DTransform(bone); + public void get3DTransform(@NotNull PlayerAnimBone bone) { + if (!enabled) { + super.get3DTransform(bone); + return; + } String modelName = bone.getName(); if (mirrorMap.containsKey(modelName)) modelName = mirrorMap.get(modelName); @@ -47,10 +50,9 @@ public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { PlayerAnimBone newBone = new PlayerAnimBone(modelName); newBone.copyOtherBone(bone); - newBone = super.get3DTransform(newBone); + super.get3DTransform(newBone); transformBone(newBone); bone.copyOtherBone(newBone); - return bone; } @Override diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/AvatarAnimManager.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/AvatarAnimManager.java index 9ae7d31f..a8f2dd2f 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/AvatarAnimManager.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/AvatarAnimManager.java @@ -77,7 +77,7 @@ public void setTickDelta(float tickDelta) { public void updatePart(ModelPart part, PlayerAnimBone bone) { PartPose initialPose = part.getInitialPose(); - bone = this.get3DTransform(bone); + this.get3DTransform(bone); RenderUtil.translatePartToBone(part, bone, initialPose); } diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/layered/modifier/MirrorIfLeftHandModifier.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/layered/modifier/MirrorIfLeftHandModifier.java index e4259988..bccba01f 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/layered/modifier/MirrorIfLeftHandModifier.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/animation/layered/modifier/MirrorIfLeftHandModifier.java @@ -14,8 +14,8 @@ public MirrorIfLeftHandModifier() { } @Override - public PlayerAnimBone get3DTransform(@NotNull PlayerAnimBone bone) { - if (getController() instanceof PlayerAnimationController controller && controller.getAvatar() == Minecraft.getInstance().player && Minecraft.getInstance().options.mainHand().get() == HumanoidArm.LEFT) return bone; - return super.get3DTransform(bone); + public void get3DTransform(@NotNull PlayerAnimBone bone) { + if (getController() instanceof PlayerAnimationController controller && controller.getAvatar() == Minecraft.getInstance().player && Minecraft.getInstance().options.mainHand().get() == HumanoidArm.LEFT) return; + super.get3DTransform(bone); } } diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/ElytraLayerMixin.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/ElytraLayerMixin.java index 11032719..59cf7538 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/ElytraLayerMixin.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/ElytraLayerMixin.java @@ -30,8 +30,8 @@ private void inject(PoseStack poseStack, SubmitNodeCollector submitNodeCollector if (emote != null && emote.isActive() && this.renderer instanceof AvatarRenderer playerRenderer) { playerRenderer.getModel().body.translateAndRotate(poseStack); poseStack.translate(0, 0, 0.125); - PlayerAnimBone bone = emote.get3DTransform(new PlayerAnimBone("elytra")); - bone.applyOtherBone(emote.get3DTransform(new PlayerAnimBone("cape"))); + PlayerAnimBone bone = emote.get3DTransform("elytra"); + bone.applyOtherBone(emote.get3DTransform("cape")); bone.positionY *= -1; RenderUtil.translateMatrixToBone(poseStack, bone); poseStack.translate(0, 0, -0.125); diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java index 327727ec..b447efdb 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java @@ -48,7 +48,7 @@ private void doTranslations(S livingEntityRenderState, PoseStack poseStack, Subm poseStack.scale(-1.0F, -1.0F, 1.0F); //These are additive properties - PlayerAnimBone body = animationPlayer.get3DTransform(new PlayerAnimBone("body")); + PlayerAnimBone body = animationPlayer.get3DTransform("body"); poseStack.translate(-body.getPosX()/16, body.getPosY()/16 + 0.75, body.getPosZ()/16); body.rotX *= -1; diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java index ab7a4ca1..67aec597 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java @@ -34,7 +34,7 @@ private void setupAnim(AvatarRenderState avatarRenderState, CallbackInfo ci) { bone.rotZ -= MochaMath.PI; bone.rotX *= -1; bone.rotY *= -1; - bone = emote.get3DTransform(bone); + emote.get3DTransform(bone); bone.rotX *= -1; bone.rotY *= -1; bone.rotX += MochaMath.PI; From 8eeb22e8df598075037d69029a3375524ba64e35 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 7 Feb 2026 00:17:45 +0700 Subject: [PATCH 07/28] neoforge --- .../playeranimcore/util/ServiceUtil.java | 26 +++++++++++++++++++ .../playeranim/PlayerAnimLibService.java | 15 +++-------- minecraft/fabric/build.gradle | 15 +++++------ .../fabric/PlayerAnimLibServiceImpl.java | 10 +++++++ minecraft/neoforge/build.gradle | 26 +++++++++---------- .../neoforge/PlayerAnimLibServiceImpl.java | 10 +++++++ settings.gradle | 2 +- 7 files changed, 70 insertions(+), 34 deletions(-) create mode 100644 core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java diff --git a/core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java b/core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java new file mode 100644 index 00000000..b8f593a3 --- /dev/null +++ b/core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java @@ -0,0 +1,26 @@ +package com.zigythebird.playeranimcore.util; + +import java.util.ServiceLoader; +import java.util.stream.Stream; + +public class ServiceUtil { + public static Stream loadServices(Class serviceClass) { + ModuleLayer layer = serviceClass.getModule().getLayer(); // NeoForge compat? + + ServiceLoader loader = layer == null ? ServiceLoader.load(serviceClass, + serviceClass.getClassLoader() + ) : ServiceLoader.load(layer, serviceClass); + + return loader.stream() + .map(ServiceLoader.Provider::get) + .filter(ActiveService::isActive); + } + + public static T loadService(Class serviceClass) { + return ServiceUtil.loadServices(serviceClass).findAny().orElseThrow(); + } + + public interface ActiveService { + boolean isActive(); + } +} diff --git a/minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java b/minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java index 2374bca3..6fd5acd7 100644 --- a/minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java +++ b/minecraft/common/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java @@ -1,18 +1,9 @@ package com.zigythebird.playeranim; -import java.util.ServiceLoader; -import java.util.stream.Stream; +import com.zigythebird.playeranimcore.util.ServiceUtil; -public interface PlayerAnimLibService { - PlayerAnimLibService INSTANCE = loadServices(PlayerAnimLibService.class).findAny().orElseThrow(); +public interface PlayerAnimLibService extends ServiceUtil.ActiveService { + PlayerAnimLibService INSTANCE = ServiceUtil.loadService(PlayerAnimLibService.class); boolean isModLoaded(String id); - - static Stream loadServices(Class serviceClass) { - ModuleLayer layer = serviceClass.getModule().getLayer(); // NeoForge compat? - ServiceLoader loader = layer == null ? ServiceLoader.load(serviceClass, - serviceClass.getClassLoader() - ) : ServiceLoader.load(layer, serviceClass); - return loader.stream().map(ServiceLoader.Provider::get); - } } diff --git a/minecraft/fabric/build.gradle b/minecraft/fabric/build.gradle index 92892fe9..009c41d6 100644 --- a/minecraft/fabric/build.gradle +++ b/minecraft/fabric/build.gradle @@ -12,12 +12,6 @@ unimined.minecraft { } } -configurations { - shadow - compileClasspath.extendsFrom shadow - runtimeClasspath.extendsFrom shadow -} - dependencies { implementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" @@ -34,11 +28,16 @@ dependencies { } shadowJar { + duplicatesStrategy = DuplicatesStrategy.WARN configurations = [project.configurations.shadow] - archiveClassifier = 'dev-shadow' + archiveClassifier = "dev-shadow" mergeServiceFiles() +} - exclude "architectury.common.marker" +remapJar { + inputFile.set shadowJar.archiveFile + dependsOn shadowJar + archiveClassifier.set null } jar { diff --git a/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibServiceImpl.java b/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibServiceImpl.java index b07d88a7..c33e8938 100644 --- a/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibServiceImpl.java +++ b/minecraft/fabric/src/main/java/com/zigythebird/playeranim/fabric/PlayerAnimLibServiceImpl.java @@ -4,6 +4,16 @@ import net.fabricmc.loader.api.FabricLoader; public final class PlayerAnimLibServiceImpl implements PlayerAnimLibService { + @Override + public boolean isActive() { + try { + Class.forName("net.fabricmc.loader.api.FabricLoader"); + return true; + } catch (Exception th) { + return false; + } + } + @Override public boolean isModLoaded(String id) { return FabricLoader.getInstance().isModLoaded(id); diff --git a/minecraft/neoforge/build.gradle b/minecraft/neoforge/build.gradle index c384948e..2a6c9448 100644 --- a/minecraft/neoforge/build.gradle +++ b/minecraft/neoforge/build.gradle @@ -6,11 +6,11 @@ unimined.minecraft { // Combine with common, for identifying both together as one mod for dev runs combineWith(project(":minecraft::common").sourceSets.main) - neoForged { - loader rootProject.neoforge_version + neoForge { + loader("net.neoforged:neoforge:$rootProject.neoforge_version:universal") mixinConfig("player_animation_library.mixins.json") - //accessTransformer aw2at(project(":minecraft:common").unimined.minecraft.fabric.accessWidener) + // accessTransformer aw2at(project(":minecraft:common").file("src/main/resources/player_animation_library.classtweaker")) } } @@ -21,27 +21,27 @@ configurations { } dependencies { - neoForge "net.neoforged:neoforge:$rootProject.neoforge_version" - - /* api(include("com.zigythebird:mochafloats:$rootProject.molang_version") { + api(include("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false }) - modRuntimeOnly include("org.javassist:javassist:$rootProject.javassist_version"))*/ + runtimeOnly include("org.javassist:javassist:$rootProject.javassist_version") shadow(project(path: ":core")) { transitive = false } } shadowJar { - exclude "fabric.mod.json" - exclude "architectury.common.json" - exclude "architectury.common.marker" - + duplicatesStrategy = DuplicatesStrategy.WARN configurations = [project.configurations.shadow] - archiveClassifier.set "dev-shadow" - + archiveClassifier = "dev-shadow" mergeServiceFiles() } +remapJar { + inputFile.set shadowJar.archiveFile + dependsOn shadowJar + archiveClassifier.set null +} + jar { archiveClassifier.set "dev" } diff --git a/minecraft/neoforge/src/main/java/com/zigythebird/playeranim/neoforge/PlayerAnimLibServiceImpl.java b/minecraft/neoforge/src/main/java/com/zigythebird/playeranim/neoforge/PlayerAnimLibServiceImpl.java index 35e10ea5..5bdd337d 100644 --- a/minecraft/neoforge/src/main/java/com/zigythebird/playeranim/neoforge/PlayerAnimLibServiceImpl.java +++ b/minecraft/neoforge/src/main/java/com/zigythebird/playeranim/neoforge/PlayerAnimLibServiceImpl.java @@ -4,6 +4,16 @@ import net.neoforged.fml.loading.FMLLoader; public final class PlayerAnimLibServiceImpl implements PlayerAnimLibService { + @Override + public boolean isActive() { + try { + Class.forName("net.neoforged.fml.loading.FMLLoader"); + return true; + } catch (Exception th) { + return false; + } + } + @Override public boolean isModLoaded(String id) { return FMLLoader.getCurrent().getLoadingModList().getModFileById(id) != null; diff --git a/settings.gradle b/settings.gradle index 11fba2b3..2c376577 100644 --- a/settings.gradle +++ b/settings.gradle @@ -14,4 +14,4 @@ include("minecraft") include("minecraft:common") include("minecraft:fabric") -// include("minecraft:neoforge") +include("minecraft:neoforge") From fcfd587504674fc3ac40713486ad7643ff1d9dd3 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 7 Feb 2026 01:45:34 +0700 Subject: [PATCH 08/28] merged jar --- minecraft/build.gradle | 189 ++++++++++++++++-- minecraft/common/build.gradle | 26 --- minecraft/fabric/build.gradle | 64 ------ minecraft/neoforge/build.gradle | 66 ------ .../neoforge/src/main/resources/icon.png | Bin 14226 -> 0 bytes .../fabric/PlayerAnimLibModFabric.java | 0 .../fabric/PlayerAnimLibServiceImpl.java | 0 ...igythebird.playeranim.PlayerAnimLibService | 0 .../fabric}/resources/fabric.mod.json | 0 .../playeranim/PlayerAnimLibMod.java | 0 .../playeranim/PlayerAnimLibService.java | 0 .../playeranim/accessors/IAnimatedAvatar.java | 0 .../accessors/IAvatarAnimationState.java | 0 .../playeranim/accessors/IBoneUpdater.java | 0 .../animation/AvatarAnimManager.java | 0 .../animation/PlayerAnimResources.java | 0 .../animation/PlayerAnimationController.java | 0 .../animation/PlayerRawAnimationBuilder.java | 0 .../AutoPlayingSoundKeyframeHandler.java | 0 .../modifier/HeadBoundCameraModifier.java | 0 .../modifier/MirrorIfLeftHandModifier.java | 0 .../playeranim/api/PlayerAnimationAccess.java | 0 .../api/PlayerAnimationFactory.java | 0 .../commands/AnimationArgumentProvider.java | 0 .../commands/PlayerAnimCommands.java | 0 .../playeranim/mixin/AvatarMixin.java | 0 .../mixin/AvatarRenderStateMixin.java | 0 .../playeranim/mixin/AvatarRendererMixin.java | 0 .../playeranim/mixin/CapeModelAccessor.java | 0 .../playeranim/mixin/ElytraLayerMixin.java | 0 .../mixin/ItemInHandLayerMixin.java | 0 .../mixin/LivingEntityRendererMixin.java | 0 .../mixin/PlayerCapeModelMixin.java | 0 .../playeranim/mixin/PlayerModelMixin.java | 0 .../firstPerson/HumanoidArmorLayerMixin.java | 0 .../firstPerson/ItemInHandLayerMixin.java | 0 .../firstPerson/ItemInHandRendererMixin.java | 0 .../mixin/firstPerson/LevelRendererMixin.java | 0 .../LivingEntityRendererMixin.java | 0 .../playeranim/molang/MolangQueries.java | 0 .../playeranim/util/ClientUtil.java | 0 .../playeranim/util/RenderUtil.java | 0 .../player_animation_library/lang/es_ar.json | 0 .../player_animation_library/lang/tt_ru.json | 0 .../player_animations/.gitignore | 0 .../arm_scale_test_legacy.json | 0 .../player_animations/arm_stretch_test.json | 0 .../player_animations/axis_test.json | 0 .../player_animations/axis_test_blender.json | 0 .../player_animations/axis_test_body.json | 0 .../axis_test_body_blender.json | 0 .../player_animations/backflip.json | 0 .../player_animations/bend_test.json | 0 .../player_animations/bend_test7.json | 0 .../player_animations/bend_test8.json | 0 .../body_translation_axis_test.json | 0 .../body_translation_axis_test_blender.json | 0 .../player_animations/camera_test.json | 0 .../cape_elytra_testing.json | 0 .../player_animations/cape_rot_axis_test.json | 0 .../cape_translation_axis_test.json | 0 .../player_animations/club_penguin_dance.json | 0 .../player_animations/custom_pivot_test.json | 0 .../player_animations/disable_tests.json | 0 .../player_animations/gun_reload.json | 0 .../player_animations/hold_on_last_frame.json | 0 .../player_animations/item_pos_axis_test.json | 0 .../item_pos_axis_test2_blender.json | 0 .../item_pos_axis_test_blender.json | 0 .../player_animations/item_rot_axis_test.json | 0 .../item_rot_axis_test2_blender.json | 0 .../item_rot_axis_test_blender.json | 0 .../player_animations/kazotsky_kick.json | 0 .../player_animations/molang_tests.json | 0 .../player_animations/running.json | 0 .../player_animations/test_cape_example.json | 0 .../test_cape_example_head.json | 0 .../test_cape_example_torso_0.json | 0 .../test_cape_example_torso_1.json | 0 .../test_cape_example_torso_2.json | 0 .../player_animations/test_cape_shit.json | 0 .../player_animations/test_cape_shit2.json | 0 .../test_test_cape_axes.json | 0 .../torso_rot_axis_test.json | 0 .../torso_translation_axis_test.json | 0 .../translation_axis_test.json | 0 .../translation_axis_test_blender.json | 0 .../player_animations/twerk.json | 0 .../player_animations/wave.json | 0 .../player_animations/waving.json | 0 .../{fabric => }/src/main/resources/icon.png | Bin .../player_animation_library.classtweaker | 0 .../player_animation_library.mixins.json | 0 .../neoforge/PlayerAnimLibModNeo.java | 0 .../neoforge/PlayerAnimLibServiceImpl.java | 0 .../neoforge/event/MolangEvent.java | 0 .../event/PlayerAnimationRegisterEvent.java | 0 .../resources/META-INF/neoforge.mods.toml | 0 ...igythebird.playeranim.PlayerAnimLibService | 0 settings.gradle | 4 - 100 files changed, 176 insertions(+), 173 deletions(-) delete mode 100644 minecraft/common/build.gradle delete mode 100644 minecraft/fabric/build.gradle delete mode 100644 minecraft/neoforge/build.gradle delete mode 100644 minecraft/neoforge/src/main/resources/icon.png rename minecraft/{fabric/src/main => src/fabric}/java/com/zigythebird/playeranim/fabric/PlayerAnimLibModFabric.java (100%) rename minecraft/{fabric/src/main => src/fabric}/java/com/zigythebird/playeranim/fabric/PlayerAnimLibServiceImpl.java (100%) rename minecraft/{fabric/src/main => src/fabric}/resources/META-INF/services/com.zigythebird.playeranim.PlayerAnimLibService (100%) rename minecraft/{fabric/src/main => src/fabric}/resources/fabric.mod.json (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/PlayerAnimLibMod.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/accessors/IAnimatedAvatar.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/accessors/IAvatarAnimationState.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/accessors/IBoneUpdater.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/animation/AvatarAnimManager.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/animation/PlayerAnimResources.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/animation/PlayerAnimationController.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/animation/PlayerRawAnimationBuilder.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/animation/keyframe/event/builtin/AutoPlayingSoundKeyframeHandler.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/animation/layered/modifier/HeadBoundCameraModifier.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/animation/layered/modifier/MirrorIfLeftHandModifier.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/api/PlayerAnimationAccess.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/api/PlayerAnimationFactory.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/commands/AnimationArgumentProvider.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/commands/PlayerAnimCommands.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/AvatarMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/AvatarRenderStateMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/AvatarRendererMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/CapeModelAccessor.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/ElytraLayerMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/ItemInHandLayerMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/PlayerCapeModelMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/PlayerModelMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/HumanoidArmorLayerMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/ItemInHandLayerMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/ItemInHandRendererMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LevelRendererMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LivingEntityRendererMixin.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/molang/MolangQueries.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/util/ClientUtil.java (100%) rename minecraft/{common => }/src/main/java/com/zigythebird/playeranim/util/RenderUtil.java (100%) rename minecraft/{fabric => }/src/main/resources/assets/player_animation_library/lang/es_ar.json (100%) rename minecraft/{fabric => }/src/main/resources/assets/player_animation_library/lang/tt_ru.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/.gitignore (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/arm_scale_test_legacy.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/arm_stretch_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/axis_test_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/axis_test_body.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/axis_test_body_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/backflip.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/bend_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/bend_test7.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/bend_test8.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/body_translation_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/body_translation_axis_test_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/camera_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/cape_elytra_testing.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/cape_rot_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/cape_translation_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/club_penguin_dance.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/custom_pivot_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/disable_tests.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/gun_reload.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/hold_on_last_frame.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/item_pos_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/item_pos_axis_test2_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/item_pos_axis_test_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/item_rot_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/item_rot_axis_test2_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/item_rot_axis_test_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/kazotsky_kick.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/molang_tests.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/running.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_cape_example.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_cape_example_head.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_cape_example_torso_0.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_cape_example_torso_1.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_cape_example_torso_2.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_cape_shit.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_cape_shit2.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/test_test_cape_axes.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/torso_rot_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/torso_translation_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/translation_axis_test.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/translation_axis_test_blender.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/twerk.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/wave.json (100%) rename minecraft/{common => }/src/main/resources/assets/player_animation_library/player_animations/waving.json (100%) rename minecraft/{fabric => }/src/main/resources/icon.png (100%) rename minecraft/{common => }/src/main/resources/player_animation_library.classtweaker (100%) rename minecraft/{common => }/src/main/resources/player_animation_library.mixins.json (100%) rename minecraft/{neoforge/src/main => src/neoforge}/java/com/zigythebird/playeranim/neoforge/PlayerAnimLibModNeo.java (100%) rename minecraft/{neoforge/src/main => src/neoforge}/java/com/zigythebird/playeranim/neoforge/PlayerAnimLibServiceImpl.java (100%) rename minecraft/{neoforge/src/main => src/neoforge}/java/com/zigythebird/playeranim/neoforge/event/MolangEvent.java (100%) rename minecraft/{neoforge/src/main => src/neoforge}/java/com/zigythebird/playeranim/neoforge/event/PlayerAnimationRegisterEvent.java (100%) rename minecraft/{neoforge/src/main => src/neoforge}/resources/META-INF/neoforge.mods.toml (100%) rename minecraft/{neoforge/src/main => src/neoforge}/resources/META-INF/services/com.zigythebird.playeranim.PlayerAnimLibService (100%) diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 76bb5c16..f40d0a6f 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -1,24 +1,187 @@ -subprojects { - apply plugin: "xyz.wagyourtail.unimined" +import org.apache.commons.lang3.StringUtils - unimined.minecraft(sourceSets.main, true) { - version rootProject.minecraft_version +plugins { + id "xyz.wagyourtail.unimined" + id "com.gradleup.shadow" +} + +sourceSets { + fabric + neoforge +} + +unimined.minecraft(sourceSets.main) { + version rootProject.minecraft_version + + fabric { + loader rootProject.fabric_loader_version + accessWidener file("src/main/resources/player_animation_library.classtweaker") } - jar { - if (!rootProject.version.toString().contains("dev") && !project.gradle.startParameter.taskNames.contains("runClient")) - processResources.exclude('assets/player_animation_library/player_animations/*') + defaultRemapJar = false +} + +unimined.minecraft(sourceSets.fabric) { + combineWith(sourceSets.main) + + fabric { + loader project.fabric_loader_version + accessWidener file("src/main/resources/player_animation_library.classtweaker") + } + defaultRemapJar = true +} + +unimined.minecraft(sourceSets.neoforge) { + combineWith(sourceSets.main) + + neoForge { + loader("net.neoforged:neoforge:$rootProject.neoforge_version:universal") + mixinConfig("player_animation_library.mixins.json") + + // accessTransformer aw2at(file("src/main/resources/player_animation_library.classtweaker")) } + defaultRemapJar = true +} + +configurations { + shadow + + fabricCompileClasspath.extendsFrom compileClasspath + neoforgeCompileClasspath.extendsFrom compileClasspath + fabricRuntimeClasspath.extendsFrom runtimeClasspath + neoforgeRuntimeClasspath.extendsFrom runtimeClasspath + + platformInclude + fabricInclude.extendsFrom platformInclude + neoforgeInclude.extendsFrom platformInclude +} + +dependencies { + // Core + api(project(":core")) + shadow(project(path: ":core")) { transitive = false } + + // Common + api(platformInclude("com.zigythebird:mochafloats:$rootProject.molang_version") { + transitive = false + }) + runtimeOnly platformInclude("org.javassist:javassist:$rootProject.javassist_version") - dependencies { - implementation project(":core") + // Fabric + fabricImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" + fabricImplementation fabricApi.fabricModule("fabric-command-api-v2", rootProject.fabric_api_version) + fabricImplementation fabricApi.fabricModule("fabric-resource-loader-v1", rootProject.fabric_api_version) + + // Neoforge +} + +jar { + if (!rootProject.version.toString().contains("dev") && !project.gradle.startParameter.taskNames.contains("runClient")) { + processResources.exclude('assets/player_animation_library/player_animations/*') } + archiveClassifier.set "dev" +} + +processResources { + inputs.property "version", project.version + + filesMatching(["META-INF/neoforge.mods.toml", "fabric.mod.json"]) { + expand version: project.version + } +} + +shadowJar { + configurations = [project.configurations.shadow] + + from(tasks.named("remapFabricJar").map { zipTree(it.archiveFile) }) + from(tasks.named("remapNeoforgeJar").map { zipTree(it.archiveFile) }) + + archiveBaseName.set("${rootProject.archives_base_name}Merged") + archiveClassifier.set null + + // Services + filesMatching('META-INF/services/**') { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + mergeServiceFiles() + + // Fix fabric jij + exclude 'META-INF/jars/**' + filesMatching('fabric.mod.json') { + filter { it.replace('META-INF/jars/', 'META-INF/jarjar/') } + } +} + +shadow { + addShadowVariantIntoJavaComponent = false +} + +[sourceSets.fabric, sourceSets.neoforge].each { ss -> + tasks.register("${ss.name}SourcesJar", Jar) { + from sourceSets.main.allSource + from ss.allSource + + archiveBaseName.set("${rootProject.archives_base_name}${StringUtils.capitalize(ss.name)}") + archiveClassifier.set "sources" + } +} + +publishing { + publications { + mavenMain(MavenPublication) { + artifactId = "PlayerAnimationLibCommon" + + artifact(jar) { + classifier = null + } + artifact sourcesJar + + pom.withXml { + def deps = asNode().appendNode("dependencies") + + configurations.api.dependencies.each { + def d = deps.appendNode("dependency") + + d.appendNode("groupId", it.group) + d.appendNode('artifactId', it instanceof ProjectDependency ? project(it.path).base.archivesName.get() : it.name) + d.appendNode("version", it.version) + d.appendNode("scope", "compile") + } + } + } + mavenFabric(MavenPublication) { + artifactId = "PlayerAnimationLibFabric" + + artifact(tasks.named("remapFabricJar")) { + classifier = null + } + artifact fabricSourcesJar + + pom.withXml { + def deps = asNode().appendNode("dependencies") + def d = deps.appendNode("dependency") + d.appendNode("groupId", project.group) + d.appendNode("artifactId", "PlayerAnimationLibCommon") + d.appendNode("version", project.version) + d.appendNode("scope", "compile") + } + } + mavenNeo(MavenPublication) { + artifactId = "PlayerAnimationLibNeo" - processResources { - inputs.property "version", project.version + artifact(tasks.named("remapNeoforgeJar")) { + classifier = null + } + artifact neoforgeSourcesJar - filesMatching(["META-INF/neoforge.mods.toml", "fabric.mod.json"]) { - expand version: project.version + pom.withXml { + def deps = asNode().appendNode("dependencies") + def d = deps.appendNode("dependency") + d.appendNode("groupId", project.group) + d.appendNode("artifactId", "PlayerAnimationLibCommon") + d.appendNode("version", project.version) + d.appendNode("scope", "compile") + } } } } diff --git a/minecraft/common/build.gradle b/minecraft/common/build.gradle deleted file mode 100644 index 38a7bf48..00000000 --- a/minecraft/common/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -unimined.minecraft { - fabric { - loader rootProject.fabric_loader_version - accessWidener file("src/main/resources/player_animation_library.classtweaker") - } - - defaultRemapJar = false -} - -dependencies { - implementation project(path: ":core") -} - -jar { - from rootProject.file("LICENSE") -} - -publishing { - publications { - mavenCommon(MavenPublication) { - artifactId = "PlayerAnimationLibCommon" - from components.java - } - } -} - diff --git a/minecraft/fabric/build.gradle b/minecraft/fabric/build.gradle deleted file mode 100644 index 009c41d6..00000000 --- a/minecraft/fabric/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -plugins { - id "com.gradleup.shadow" -} - -unimined.minecraft { - // Combine with common, for identifying both together as one mod for dev runs - combineWith(project(":minecraft:common").sourceSets.main) - - fabric { - loader project.fabric_loader_version - accessWidener project(":minecraft:common").file("src/main/resources/player_animation_library.classtweaker") - } -} - -dependencies { - implementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" - - // Fabric API - api fabricApi.fabricModule("fabric-command-api-v2", rootProject.fabric_api_version) - api fabricApi.fabricModule("fabric-resource-loader-v1", rootProject.fabric_api_version) - - api(include("com.zigythebird:mochafloats:$rootProject.molang_version") { - transitive = false - }) - runtimeOnly include("org.javassist:javassist:$rootProject.javassist_version") - - shadow(project(path: ":core")) { transitive = false } -} - -shadowJar { - duplicatesStrategy = DuplicatesStrategy.WARN - configurations = [project.configurations.shadow] - archiveClassifier = "dev-shadow" - mergeServiceFiles() -} - -remapJar { - inputFile.set shadowJar.archiveFile - dependsOn shadowJar - archiveClassifier.set null -} - -jar { - archiveClassifier.set "dev" -} - -/*sourcesJar { - def commonSources = project(":minecraft:common").sourcesJar - dependsOn commonSources - from commonSources.archiveFile.map { zipTree(it) } -}*/ - -shadow { - addShadowVariantIntoJavaComponent = false -} - -publishing { - publications { - mavenFabric(MavenPublication) { - artifactId = "PlayerAnimationLibFabric" - from components.java - } - } -} diff --git a/minecraft/neoforge/build.gradle b/minecraft/neoforge/build.gradle deleted file mode 100644 index 2a6c9448..00000000 --- a/minecraft/neoforge/build.gradle +++ /dev/null @@ -1,66 +0,0 @@ -plugins { - id "com.gradleup.shadow" -} - -unimined.minecraft { - // Combine with common, for identifying both together as one mod for dev runs - combineWith(project(":minecraft::common").sourceSets.main) - - neoForge { - loader("net.neoforged:neoforge:$rootProject.neoforge_version:universal") - mixinConfig("player_animation_library.mixins.json") - - // accessTransformer aw2at(project(":minecraft:common").file("src/main/resources/player_animation_library.classtweaker")) - } -} - -configurations { - shadow - compileClasspath.extendsFrom shadow - runtimeClasspath.extendsFrom shadow -} - -dependencies { - api(include("com.zigythebird:mochafloats:$rootProject.molang_version") { - transitive = false - }) - runtimeOnly include("org.javassist:javassist:$rootProject.javassist_version") - - shadow(project(path: ":core")) { transitive = false } -} - -shadowJar { - duplicatesStrategy = DuplicatesStrategy.WARN - configurations = [project.configurations.shadow] - archiveClassifier = "dev-shadow" - mergeServiceFiles() -} - -remapJar { - inputFile.set shadowJar.archiveFile - dependsOn shadowJar - archiveClassifier.set null -} - -jar { - archiveClassifier.set "dev" -} - -/*sourcesJar { - def commonSources = project(":minecraft:common").sourcesJar - dependsOn commonSources - from commonSources.archiveFile.map { zipTree(it) } -}*/ - -shadow { - addShadowVariantIntoJavaComponent = false -} - -publishing { - publications { - mavenNeoForge(MavenPublication) { - artifactId = "PlayerAnimationLibNeo" - from components.java - } - } -} diff --git a/minecraft/neoforge/src/main/resources/icon.png b/minecraft/neoforge/src/main/resources/icon.png deleted file mode 100644 index 7d97c057d2672f5587e6dc82815989c5b932ef50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14226 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 Date: Sat, 7 Feb 2026 01:53:02 +0700 Subject: [PATCH 09/28] Update release.yml --- .github/workflows/release.yml | 148 +++++----------------------------- 1 file changed, 19 insertions(+), 129 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 30a3ba03..85211da9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,22 +9,11 @@ on: required: true jobs: - build: + publish: runs-on: ubuntu-latest steps: - name: Checkout Branch - uses: actions/checkout@v3 - - - name: Get Artifact Id - uses: actions/github-script@v5 - env: - branch: ${{ github.head_ref || github.ref_name }} - id: artifact_id - with: - result-encoding: string - script: | - // use env branch replace / with _ - return process.env.branch.replace(/\//g, '_') + uses: actions/checkout@v4 - name: Setup Java uses: actions/setup-java@v4 @@ -36,134 +25,46 @@ jobs: run: chmod +x gradlew - name: Build - run: | - ./gradlew build - - - name: Upload To Artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.artifact_id.outputs.result }} - path: | - ./dist/**/* - ./minecraft/fabric/build/libs - ./minecraft/neoforge/build/libs - ./gradle.properties - - deploy: - runs-on: ubuntu-latest - needs: - - build - steps: - - name: Checkout Branch - uses: actions/checkout@v3 - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: 'adopt' - java-version: 25 - - - name: Get Artifact Id - uses: actions/github-script@v5 - env: - branch: ${{ github.head_ref || github.ref_name }} - id: artifact_id - with: - result-encoding: string - script: | - // use env branch replace / with _ - return process.env.branch.replace(/\//g, '_') - - - name: Download Artifacts - uses: actions/download-artifact@v4 - with: - name: ${{ steps.artifact_id.outputs.result }} + run: ./gradlew build - name: Load Gradle Properties uses: christian-draeger/read-properties@1.1.1 id: gradle_properties with: path: './gradle.properties' - properties: 'java_version minecraft_version mod_version' + properties: 'minecraft_version mod_version' - - name: Check For Fabric Jar - uses: actions/github-script@v5 - id: fabric_release - with: - result-encoding: string - script: | - const fs = require("fs") - return fs.readdirSync("./minecraft/fabric/build/libs")[0] || false; - - - name: Check For Forge Jar - uses: actions/github-script@v5 - id: forge_release - with: - result-encoding: string - script: | - const fs = require("fs") - return fs.readdirSync("./minecraft/neoforge/build/libs")[0] || false; - - - name: Run Publish Fabric - if: ${{ steps.fabric_release.outputs.result != 'false' }} - id: publish_fabric + - name: Run Publish + id: publish_merged uses: Kir-Antipov/mc-publish@v3.3 with: modrinth-id: ha1mEyJS modrinth-token: ${{ secrets.MODRINTH_TOKEN }} - modrinth-featured: false + modrinth-featured: true modrinth-unfeature-mode: any - curseforge-id: 1283899 - curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} - - name: ${{ steps.gradle_properties.outputs.mod_version }}+${{ steps.gradle_properties.outputs.minecraft_version }}-Fabric - version: ${{ steps.gradle_properties.outputs.mod_version }} - - files: | - ./minecraft/fabric/build/libs/!(*-@(dev|sources|javadoc|all|dev-shadow)).jar - ./minecraft/fabric/build/libs/*-@(dev|sources|javadoc|all|dev-shadow).jar - version-type: release - - loaders: fabric - game-versions: | - ${{ steps.gradle_properties.outputs.minecraft_version }} - - changelog-file: CHANGELOG.md - - java: ${{ steps.gradle_properties.outputs.java_version }} - retry-attempts: 5 - retry-delay: 60000 - fail-mode: skip - - - name: Run Publish Forge - if: ${{ steps.forge_release.outputs.result != 'false' }} - id: publish_forge - uses: Kir-Antipov/mc-publish@v3.3 - with: - modrinth-id: ha1mEyJS - modrinth-token: ${{ secrets.MODRINTH_TOKEN }} - modrinth-featured: false - modrinth-unfeature-mode: any + github-tag: v${{ steps.gradle_properties.outputs.mod_version }}+${{ steps.gradle_properties.outputs.minecraft_version }} + github-token: ${{ secrets.GITHUB_TOKEN }} curseforge-id: 1283899 curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} - name: ${{ steps.gradle_properties.outputs.mod_version }}+${{ steps.gradle_properties.outputs.minecraft_version }}-NeoForge + name: ${{ steps.gradle_properties.outputs.mod_version }}+${{ steps.gradle_properties.outputs.minecraft_version }} version: ${{ steps.gradle_properties.outputs.mod_version }} files: | - ./minecraft/neoforge/build/libs/!(*-@(dev|sources|javadoc|all|dev-shadow)).jar - ./minecraft/neoforge/build/libs/*-@(dev|sources|javadoc|all|dev-shadow).jar + ./minecraft/build/libs/PlayerAnimationLibMerged-*.jar version-type: release - loaders: neoforge + loaders: | + fabric + neoforge game-versions: | ${{ steps.gradle_properties.outputs.minecraft_version }} changelog-file: CHANGELOG.md - java: ${{ steps.gradle_properties.outputs.java_version }} + java: 25 retry-attempts: 5 retry-delay: 60000 fail-mode: skip @@ -174,22 +75,11 @@ jobs: { echo 'P2D_LINKS< Date: Sat, 7 Feb 2026 01:58:39 +0700 Subject: [PATCH 10/28] Update build.gradle --- minecraft/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/minecraft/build.gradle b/minecraft/build.gradle index f40d0a6f..0eabb5c5 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -82,10 +82,10 @@ jar { archiveClassifier.set "dev" } -processResources { - inputs.property "version", project.version +[tasks.processResources, tasks.processFabricResources, tasks.processNeoforgeResources].each { + it.inputs.property "version", project.version - filesMatching(["META-INF/neoforge.mods.toml", "fabric.mod.json"]) { + it.filesMatching(["META-INF/neoforge.mods.toml", "fabric.mod.json"]) { expand version: project.version } } From b56721e5432731ce1643d3e6d8c260d4526d4233 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 7 Feb 2026 02:20:26 +0700 Subject: [PATCH 11/28] update --- minecraft/src/fabric/resources/fabric.mod.json | 4 ++-- minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/minecraft/src/fabric/resources/fabric.mod.json b/minecraft/src/fabric/resources/fabric.mod.json index fece4e0b..72b20875 100644 --- a/minecraft/src/fabric/resources/fabric.mod.json +++ b/minecraft/src/fabric/resources/fabric.mod.json @@ -25,8 +25,8 @@ "player_animation_library.mixins.json" ], "depends": { - "fabricloader": ">=0.18.3", - "minecraft": ">=1.21.11", + "fabricloader": ">=0.18.4", + "minecraft": ">=26.1-alpha.6", "fabric-resource-loader-v1": "*", "fabric-command-api-v2": "*" }, diff --git a/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml b/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml index bcaf4147..542f6547 100644 --- a/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml +++ b/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml @@ -18,14 +18,14 @@ logoFile = "icon.png" [[dependencies.player_animation_library]] modId = "neoforge" type = "required" -versionRange = "[21.11.0-beta,)" +versionRange = "[26.1.0.0-alpha,)" ordering = "NONE" side = "BOTH" [[dependencies.player_animation_library]] modId = "minecraft" type = "required" -versionRange = "[1.21.11,)" +versionRange = "[26.1,)" ordering = "NONE" side = "BOTH" From 8bf11d780d07ecbdd46e6bb8986a50db027f4ccc Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 7 Feb 2026 02:23:00 +0700 Subject: [PATCH 12/28] Fix AT --- .gitignore | 1 + minecraft/build.gradle | 2 +- .../main/resources/player_animation_library.classtweaker | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index b2d73e72..fab6fecb 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ classes/ *.launch *.log .DS_Store +/minecraft/src/neoforge/resources/META-INF/accesstransformer.cfg diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 0eabb5c5..7fd17e9b 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -38,7 +38,7 @@ unimined.minecraft(sourceSets.neoforge) { loader("net.neoforged:neoforge:$rootProject.neoforge_version:universal") mixinConfig("player_animation_library.mixins.json") - // accessTransformer aw2at(file("src/main/resources/player_animation_library.classtweaker")) + accessTransformer aw2at(file("src/main/resources/player_animation_library.classtweaker")) } defaultRemapJar = true } diff --git a/minecraft/src/main/resources/player_animation_library.classtweaker b/minecraft/src/main/resources/player_animation_library.classtweaker index cd3470de..5af6e581 100644 --- a/minecraft/src/main/resources/player_animation_library.classtweaker +++ b/minecraft/src/main/resources/player_animation_library.classtweaker @@ -1,7 +1,7 @@ -classTweaker v1 named +accessWidener v2 named extendable class net/minecraft/client/model/geom/ModelPart accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; -inject-interface com/zigythebird/playeranim/accessors/IAnimatedAvatar net/minecraft/world/entity/Avatar -inject-interface com/zigythebird/playeranim/accessors/IAvatarAnimationState net/minecraft/client/renderer/entity/state/AvatarRenderState +# inject-interface com/zigythebird/playeranim/accessors/IAnimatedAvatar net/minecraft/world/entity/Avatar +# inject-interface com/zigythebird/playeranim/accessors/IAvatarAnimationState net/minecraft/client/renderer/entity/state/AvatarRenderState From 2304d9562b6fdf9bcb5b18c22b3c4e9388eee1f4 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 7 Feb 2026 02:37:02 +0700 Subject: [PATCH 13/28] Update build.gradle --- minecraft/build.gradle | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 7fd17e9b..a21dfc71 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -106,9 +106,14 @@ shadowJar { mergeServiceFiles() // Fix fabric jij - exclude 'META-INF/jars/**' - filesMatching('fabric.mod.json') { - filter { it.replace('META-INF/jars/', 'META-INF/jarjar/') } + exclude 'META-INF/jarjar/*.jar' + filesMatching('META-INF/jarjar/metadata.json') { + filter { it.replace('META-INF/jarjar/', 'META-INF/jars/') } + } + + // Workaround + filesMatching('player_animation_library.classtweaker') { + filter { it.replace('named', 'official') } } } From ff7f9bdee769ee873719635dd97debf82297581b Mon Sep 17 00:00:00 2001 From: Zigy <105124180+ZigyTheBird@users.noreply.github.com> Date: Sun, 8 Feb 2026 14:26:11 +0330 Subject: [PATCH 14/28] Update .gitignore --- .gitignore | 1 + .../assets/player_animation_library/player_animations/.gitignore | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 minecraft/src/main/resources/assets/player_animation_library/player_animations/.gitignore diff --git a/.gitignore b/.gitignore index fab6fecb..fadb18ce 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ classes/ *.log .DS_Store /minecraft/src/neoforge/resources/META-INF/accesstransformer.cfg +/minecraft/src/main/resources/assets/player_animation_library/player_animations/dont_include diff --git a/minecraft/src/main/resources/assets/player_animation_library/player_animations/.gitignore b/minecraft/src/main/resources/assets/player_animation_library/player_animations/.gitignore deleted file mode 100644 index 22e953a7..00000000 --- a/minecraft/src/main/resources/assets/player_animation_library/player_animations/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dont_include \ No newline at end of file From ff660b8c11c9944ad6ab8fd435b73852616853b1 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 14 Feb 2026 00:58:16 +0700 Subject: [PATCH 15/28] neoforge --- build.gradle | 8 -------- gradle.properties | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 9adb81c7..d1a11b69 100644 --- a/build.gradle +++ b/build.gradle @@ -32,14 +32,6 @@ allprojects { name = "RedlanceMinecraft" url = "https://repo.redlance.org/public" } - maven { - name = "Maven for PR #2879" // https://github.com/neoforged/NeoForge/pull/2879 - url = uri("https://prmaven.neoforged.net/NeoForge/pr2879") - content { - includeModule("net.neoforged", "neoforge") - includeModule("net.neoforged", "testframework") - } - } } tasks.withType(JavaCompile).configureEach { diff --git a/gradle.properties b/gradle.properties index 2bfb2d41..2ddb8514 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.6 +mod_version = 1.1.6+dev maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib @@ -13,6 +13,6 @@ minecraft_version = 26.1-snapshot-6 # Dependencies fabric_loader_version = 0.18.4 fabric_api_version = 0.143.2+26.1 -neoforge_version = 26.1.0.0-alpha.0+snapshot-6.20260203.212009 +neoforge_version = 26.1.0.0-alpha.9+snapshot-6 molang_version = 4.1.5 javassist_version = 3.30.2-GA From 76541a1d14b97aec26edb0555900594fb5703878 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Tue, 17 Feb 2026 23:22:34 +0700 Subject: [PATCH 16/28] update mocha --- core/build.gradle | 1 - gradle.properties | 3 +-- minecraft/build.gradle | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index c18f6af4..ed29f60f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -4,7 +4,6 @@ dependencies { implementation api("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false } - implementation api("org.javassist:javassist:$rootProject.javassist_version") compileOnlyApi("org.jetbrains:annotations:26.0.2") // Minecraft libs diff --git a/gradle.properties b/gradle.properties index 2ddb8514..fa85cb5c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,5 +14,4 @@ minecraft_version = 26.1-snapshot-6 fabric_loader_version = 0.18.4 fabric_api_version = 0.143.2+26.1 neoforge_version = 26.1.0.0-alpha.9+snapshot-6 -molang_version = 4.1.5 -javassist_version = 3.30.2-GA +molang_version = 5.0.0 diff --git a/minecraft/build.gradle b/minecraft/build.gradle index a21dfc71..41c5422a 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -65,7 +65,6 @@ dependencies { api(platformInclude("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false }) - runtimeOnly platformInclude("org.javassist:javassist:$rootProject.javassist_version") // Fabric fabricImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" From d2c387885a9d28c9ac41b2bedf9d5f4122f1ced8 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Wed, 18 Feb 2026 00:52:33 +0700 Subject: [PATCH 17/28] snap7 --- build.gradle | 8 ++++++++ gradle.properties | 6 +++--- .../mixin/firstPerson/HumanoidArmorLayerMixin.java | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index d1a11b69..073414e4 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,14 @@ allprojects { includeModule("org.lwjgl", "lwjgl-freetype") } } + maven { + name = "Maven for PR #2879" // https://github.com/neoforged/NeoForge/pull/2879 + url = uri("https://prmaven.neoforged.net/NeoForge/pr2879") + content { + includeModule("net.neoforged", "neoforge") + includeModule("net.neoforged", "testframework") + } + } maven { name = "NeoForged" url = "https://maven.neoforged.net/releases" diff --git a/gradle.properties b/gradle.properties index fa85cb5c..b0c6d2a3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,10 +8,10 @@ maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib # Minecraft properties -minecraft_version = 26.1-snapshot-6 +minecraft_version = 26.1-snapshot-7 # Dependencies fabric_loader_version = 0.18.4 -fabric_api_version = 0.143.2+26.1 -neoforge_version = 26.1.0.0-alpha.9+snapshot-6 +fabric_api_version = 0.143.4+26.1 +neoforge_version = 26.1.0.0-alpha.0+snapshot-7.20260217.173927 molang_version = 5.0.0 diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/HumanoidArmorLayerMixin.java b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/HumanoidArmorLayerMixin.java index a1e5063e..636d2291 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/HumanoidArmorLayerMixin.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/HumanoidArmorLayerMixin.java @@ -44,7 +44,7 @@ public abstract class HumanoidArmorLayerMixin humanoidModel) { if (humanoidRenderState instanceof IAvatarAnimationState state && state.playerAnimLib$isFirstPersonPass()) { - humanoidModel.setAllVisible(false); + humanoidModel.root().visible = false; AvatarAnimManager emote = state.playerAnimLib$getAnimManager(); if (equipmentSlot == EquipmentSlot.CHEST && emote.getFirstPersonConfiguration().isShowArmor()) { humanoidModel.rightArm.visible = emote.getFirstPersonConfiguration().isShowRightArm(); From dfa000d5d64fc0a87eaf51f48734ad7dc8c5ad7c Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Wed, 18 Feb 2026 00:54:30 +0700 Subject: [PATCH 18/28] neofroge --- build.gradle | 8 -------- gradle.properties | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 073414e4..d1a11b69 100644 --- a/build.gradle +++ b/build.gradle @@ -24,14 +24,6 @@ allprojects { includeModule("org.lwjgl", "lwjgl-freetype") } } - maven { - name = "Maven for PR #2879" // https://github.com/neoforged/NeoForge/pull/2879 - url = uri("https://prmaven.neoforged.net/NeoForge/pr2879") - content { - includeModule("net.neoforged", "neoforge") - includeModule("net.neoforged", "testframework") - } - } maven { name = "NeoForged" url = "https://maven.neoforged.net/releases" diff --git a/gradle.properties b/gradle.properties index b0c6d2a3..37754abe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,5 +13,5 @@ minecraft_version = 26.1-snapshot-7 # Dependencies fabric_loader_version = 0.18.4 fabric_api_version = 0.143.4+26.1 -neoforge_version = 26.1.0.0-alpha.0+snapshot-7.20260217.173927 +neoforge_version = 26.1.0.0-alpha.11+snapshot-7 molang_version = 5.0.0 From b28b22916e7565006bf1d1bd240f38de46f1a7db Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sun, 22 Feb 2026 00:03:50 +0700 Subject: [PATCH 19/28] update to snap9 --- build.gradle | 10 +++++++++- gradle.properties | 6 +++--- minecraft/build.gradle | 5 ----- .../resources/player_animation_library.classtweaker | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index d1a11b69..4fc778b4 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ import org.apache.commons.lang3.StringUtils plugins { id "org.redlance.dima_dencep.gradle.PublishToDiscord" version "1.0.6" - id "xyz.wagyourtail.unimined" version "1.4.2" apply false + id "xyz.wagyourtail.unimined" version "1.4.2+redlance.1" apply false id "com.gradleup.shadow" version "9.3.0" apply false } @@ -24,6 +24,14 @@ allprojects { includeModule("org.lwjgl", "lwjgl-freetype") } } + maven { + name = "Maven for PR #2975" // https://github.com/neoforged/NeoForge/pull/2975 + url = uri("https://prmaven.neoforged.net/NeoForge/pr2975") + content { + includeModule("net.neoforged", "neoforge") + includeModule("net.neoforged", "testframework") + } + } maven { name = "NeoForged" url = "https://maven.neoforged.net/releases" diff --git a/gradle.properties b/gradle.properties index 37754abe..b78f4f99 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,10 +8,10 @@ maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib # Minecraft properties -minecraft_version = 26.1-snapshot-7 +minecraft_version = 26.1-snapshot-9 # Dependencies fabric_loader_version = 0.18.4 -fabric_api_version = 0.143.4+26.1 -neoforge_version = 26.1.0.0-alpha.11+snapshot-7 +fabric_api_version = 0.143.5+26.1 +neoforge_version = 26.1.0.0-alpha.0+snapshot-9.20260220.232516 molang_version = 5.0.0 diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 41c5422a..99417a9b 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -109,11 +109,6 @@ shadowJar { filesMatching('META-INF/jarjar/metadata.json') { filter { it.replace('META-INF/jarjar/', 'META-INF/jars/') } } - - // Workaround - filesMatching('player_animation_library.classtweaker') { - filter { it.replace('named', 'official') } - } } shadow { diff --git a/minecraft/src/main/resources/player_animation_library.classtweaker b/minecraft/src/main/resources/player_animation_library.classtweaker index 5af6e581..b82a5ebb 100644 --- a/minecraft/src/main/resources/player_animation_library.classtweaker +++ b/minecraft/src/main/resources/player_animation_library.classtweaker @@ -1,4 +1,4 @@ -accessWidener v2 named +accessWidener v2 official extendable class net/minecraft/client/model/geom/ModelPart accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; From 2214637ad0132015723dc1213792102e7f4c4350 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Thu, 26 Feb 2026 23:13:43 +0700 Subject: [PATCH 20/28] Network V6 (#102) --- .../network/AnimationBinary.java | 126 +++++----- .../network/AnimationBinaryV6.java | 226 ++++++++++++++++++ .../playeranimcore/network/BoneChannel.java | 40 ++++ .../playeranimcore/network/HeaderFlag.java | 21 ++ .../playeranimcore/network/KeyframeFlag.java | 44 ++++ .../network/LegacyAnimationBinary.java | 3 + .../testing/common/AnimationBinaryTest.java | 21 +- .../emotes/testing/common/BinarySizeTest.java | 8 +- 8 files changed, 429 insertions(+), 60 deletions(-) create mode 100644 core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinaryV6.java create mode 100644 core/src/main/java/com/zigythebird/playeranimcore/network/BoneChannel.java create mode 100644 core/src/main/java/com/zigythebird/playeranimcore/network/HeaderFlag.java create mode 100644 core/src/main/java/com/zigythebird/playeranimcore/network/KeyframeFlag.java diff --git a/core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinary.java b/core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinary.java index 0ca46ca8..45544a35 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinary.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinary.java @@ -11,7 +11,6 @@ import com.zigythebird.playeranimcore.easing.EasingType; import com.zigythebird.playeranimcore.enums.AnimationFormat; import com.zigythebird.playeranimcore.enums.TransformType; -import com.zigythebird.playeranimcore.loading.AnimationLoader; import com.zigythebird.playeranimcore.loading.PlayerAnimatorLoader; import com.zigythebird.playeranimcore.math.Vec3f; import io.netty.buffer.ByteBuf; @@ -36,14 +35,20 @@ public final class AnimationBinary { * Version 3: No change client side, but the server won't send some animations to versions lower than 3 due to the possibility of a crash. * Version 4: Fixed some issues with the body bone. * Version 5: Fixed the Y position axis on items being negated. + * Version 6: Compact binary format - bit-packed header, presence flags for bone axes, compact keyframe encoding. */ - public static final int CURRENT_VERSION = 5; + public static final int CURRENT_VERSION = 6; public static void write(ByteBuf buf, Animation animation) { AnimationBinary.write(buf, CURRENT_VERSION, animation); } public static void write(ByteBuf buf, int version, Animation animation) { + if (version >= 6) { + AnimationBinaryV6.write(buf, version, animation); + return; + } + Map data = animation.data().data(); boolean applyBendToOtherBones = (boolean) data.getOrDefault(ExtraAnimationData.APPLY_BEND_TO_OTHER_BONES_KEY, false); if (version < 3 && applyBendToOtherBones && animation.boneAnimations().containsKey("torso") @@ -75,29 +80,7 @@ public static void write(ByteBuf buf, int version, Animation animation) { writeBoneAnimation(buf, entry.getValue(), version < 4 && entry.getKey().equals("body"), version < 5 && LegacyAnimationBinary.ITEM_BONE.test(entry.getKey())); } - // Sounds - VarIntUtils.writeVarInt(buf, animation.keyFrames().sounds().length); - for (SoundKeyframeData soundKeyframe : animation.keyFrames().sounds()) { - buf.writeFloat(soundKeyframe.getStartTick()); - ProtocolUtils.writeString(buf, soundKeyframe.getSound()); - } - - // Particles - VarIntUtils.writeVarInt(buf, animation.keyFrames().particles().length); - for (ParticleKeyframeData particleKeyframe : animation.keyFrames().particles()) { - buf.writeFloat(particleKeyframe.getStartTick()); - ProtocolUtils.writeString(buf, particleKeyframe.getEffect()); - ProtocolUtils.writeString(buf, particleKeyframe.getLocator()); - ProtocolUtils.writeString(buf, particleKeyframe.script()); - } - - // Instructions - VarIntUtils.writeVarInt(buf, animation.keyFrames().customInstructions().length); - for (CustomInstructionKeyframeData instructionKeyframe : animation.keyFrames().customInstructions()) { - buf.writeFloat(instructionKeyframe.getStartTick()); - ProtocolUtils.writeString(buf, instructionKeyframe.getInstructions()); - } - + writeEventKeyframes(buf, animation.keyFrames()); NetworkUtils.writeMap(buf, animation.bones(), ProtocolUtils::writeString, NetworkUtils::writeVec3f); NetworkUtils.writeMap(buf, animation.parents(), ProtocolUtils::writeString, ProtocolUtils::writeString); } @@ -122,11 +105,40 @@ public static void writeKeyframe(Keyframe keyframe, ByteBuf buf) { ProtocolUtils.writeList(buf, keyframe.easingArgs(), ExprBytesUtils::writeExpressions); } + static void writeEventKeyframes(ByteBuf buf, Animation.Keyframes keyFrames) { + // Sounds + VarIntUtils.writeVarInt(buf, keyFrames.sounds().length); + for (SoundKeyframeData soundKeyframe : keyFrames.sounds()) { + buf.writeFloat(soundKeyframe.getStartTick()); + ProtocolUtils.writeString(buf, soundKeyframe.getSound()); + } + + // Particles + VarIntUtils.writeVarInt(buf, keyFrames.particles().length); + for (ParticleKeyframeData particleKeyframe : keyFrames.particles()) { + buf.writeFloat(particleKeyframe.getStartTick()); + ProtocolUtils.writeString(buf, particleKeyframe.getEffect()); + ProtocolUtils.writeString(buf, particleKeyframe.getLocator()); + ProtocolUtils.writeString(buf, particleKeyframe.script()); + } + + // Instructions + VarIntUtils.writeVarInt(buf, keyFrames.customInstructions().length); + for (CustomInstructionKeyframeData instructionKeyframe : keyFrames.customInstructions()) { + buf.writeFloat(instructionKeyframe.getStartTick()); + ProtocolUtils.writeString(buf, instructionKeyframe.getInstructions()); + } + } + public static Animation read(ByteBuf buf) { return AnimationBinary.read(buf, CURRENT_VERSION); } public static Animation read(ByteBuf buf, int version) { + if (version >= 6) { + return AnimationBinaryV6.read(buf, version); + } + float length = buf.readFloat(); Animation.LoopType loopType = Animation.LoopType.PLAY_ONCE; if (buf.readBoolean()) { @@ -168,36 +180,7 @@ public static Animation read(ByteBuf buf, int version) { boneAnimations.get("left_item").positionKeyFrames().yKeyframes().replaceAll(AnimationBinary::negateKeyframeExpressions); } - // Sounds - int soundCount = VarIntUtils.readVarInt(buf); - SoundKeyframeData[] sounds = new SoundKeyframeData[soundCount]; - for (int i = 0; i < soundCount; i++) { - float startTick = buf.readFloat(); - String sound = ProtocolUtils.readString(buf); - sounds[i] = new SoundKeyframeData(startTick, sound); - } - - // Particles - int particleCount = VarIntUtils.readVarInt(buf); - ParticleKeyframeData[] particles = new ParticleKeyframeData[particleCount]; - for (int i = 0; i < particleCount; i++) { - float startTick = buf.readFloat(); - String effect = ProtocolUtils.readString(buf); - String locator = ProtocolUtils.readString(buf); - String script = ProtocolUtils.readString(buf); - particles[i] = new ParticleKeyframeData(startTick, effect, locator, script); - } - - // Instructions - int customInstructionCount = VarIntUtils.readVarInt(buf); - CustomInstructionKeyframeData[] customInstructions = new CustomInstructionKeyframeData[customInstructionCount]; - for (int i = 0; i < customInstructionCount; i++) { - float startTick = buf.readFloat(); - String instructions = ProtocolUtils.readString(buf); - customInstructions[i] = new CustomInstructionKeyframeData(startTick, instructions); - } - Animation.Keyframes keyFrames = new Animation.Keyframes(sounds, particles, customInstructions); - + Animation.Keyframes keyFrames = readEventKeyframes(buf); Map pivotBones = NetworkUtils.readMap(buf, ProtocolUtils::readString, NetworkUtils::readVec3f); Map parents = NetworkUtils.readMap(buf, ProtocolUtils::readString, ProtocolUtils::readString); @@ -239,6 +222,39 @@ public static List readKeyframeList(ByteBuf buf, boolean shouldStartFr return list; } + static Animation.Keyframes readEventKeyframes(ByteBuf buf) { + // Sounds + int soundCount = VarIntUtils.readVarInt(buf); + SoundKeyframeData[] sounds = new SoundKeyframeData[soundCount]; + for (int i = 0; i < soundCount; i++) { + float startTick = buf.readFloat(); + String sound = ProtocolUtils.readString(buf); + sounds[i] = new SoundKeyframeData(startTick, sound); + } + + // Particles + int particleCount = VarIntUtils.readVarInt(buf); + ParticleKeyframeData[] particles = new ParticleKeyframeData[particleCount]; + for (int i = 0; i < particleCount; i++) { + float startTick = buf.readFloat(); + String effect = ProtocolUtils.readString(buf); + String locator = ProtocolUtils.readString(buf); + String script = ProtocolUtils.readString(buf); + particles[i] = new ParticleKeyframeData(startTick, effect, locator, script); + } + + // Instructions + int customInstructionCount = VarIntUtils.readVarInt(buf); + CustomInstructionKeyframeData[] customInstructions = new CustomInstructionKeyframeData[customInstructionCount]; + for (int i = 0; i < customInstructionCount; i++) { + float startTick = buf.readFloat(); + String instructions = ProtocolUtils.readString(buf); + customInstructions[i] = new CustomInstructionKeyframeData(startTick, instructions); + } + + return new Animation.Keyframes(sounds, particles, customInstructions); + } + private static List negateKeyframes(List keyframes) { keyframes = new ArrayList<>(keyframes); keyframes.replaceAll(AnimationBinary::negateKeyframeExpressions); diff --git a/core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinaryV6.java b/core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinaryV6.java new file mode 100644 index 00000000..e7159fc6 --- /dev/null +++ b/core/src/main/java/com/zigythebird/playeranimcore/network/AnimationBinaryV6.java @@ -0,0 +1,226 @@ +package com.zigythebird.playeranimcore.network; + +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.AnimationFormat; +import com.zigythebird.playeranimcore.loading.PlayerAnimatorLoader; +import com.zigythebird.playeranimcore.math.Vec3f; +import io.netty.buffer.ByteBuf; +import team.unnamed.mocha.parser.ast.Expression; +import team.unnamed.mocha.parser.ast.FloatExpression; +import team.unnamed.mocha.runtime.IsConstantExpression; +import team.unnamed.mocha.util.ExprBytesUtils; +import team.unnamed.mocha.util.network.ProtocolUtils; +import team.unnamed.mocha.util.network.VarIntUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.zigythebird.playeranimcore.molang.MolangLoader.MOCHA_ENGINE; + +final class AnimationBinaryV6 { + + static void write(ByteBuf buf, int version, Animation animation) { + Map data = animation.data().data(); + writeHeader(buf, animation, data); + + VarIntUtils.writeVarInt(buf, animation.boneAnimations().size()); + for (Map.Entry entry : animation.boneAnimations().entrySet()) { + ProtocolUtils.writeString(buf, entry.getKey()); + writeBoneAnimation(buf, entry.getValue(), version); + } + + AnimationBinary.writeEventKeyframes(buf, animation.keyFrames()); + NetworkUtils.writeMap(buf, animation.bones(), ProtocolUtils::writeString, NetworkUtils::writeVec3f); + NetworkUtils.writeMap(buf, animation.parents(), ProtocolUtils::writeString, ProtocolUtils::writeString); + } + + static Animation read(ByteBuf buf, int version) { + ExtraAnimationData data = new ExtraAnimationData(); + + int flags = VarIntUtils.readVarInt(buf); + boolean shouldPlayAgain = HeaderFlag.SHOULD_PLAY_AGAIN.test(flags); + boolean isHoldOnLastFrame = HeaderFlag.HOLD_ON_LAST_FRAME.test(flags); + AnimationFormat format = HeaderFlag.PLAYER_ANIMATOR.test(flags) ? AnimationFormat.PLAYER_ANIMATOR : AnimationFormat.GECKOLIB; + + data.put(ExtraAnimationData.FORMAT_KEY, format); + if (HeaderFlag.APPLY_BEND.test(flags)) data.put(ExtraAnimationData.APPLY_BEND_TO_OTHER_BONES_KEY, true); + if (!HeaderFlag.EASE_BEFORE.test(flags)) data.put(ExtraAnimationData.EASING_BEFORE_KEY, false); + + float length = buf.readFloat(); + + Animation.LoopType loopType; + if (shouldPlayAgain) { + if (isHoldOnLastFrame) { + loopType = Animation.LoopType.HOLD_ON_LAST_FRAME; + } else { + loopType = Animation.LoopType.returnToTickLoop(buf.readFloat()); + } + } else { + loopType = Animation.LoopType.PLAY_ONCE; + } + + if (HeaderFlag.HAS_BEGIN_TICK.test(flags)) data.put(ExtraAnimationData.BEGIN_TICK_KEY, buf.readFloat()); + if (HeaderFlag.HAS_END_TICK.test(flags)) data.put(ExtraAnimationData.END_TICK_KEY, buf.readFloat()); + + data.put(ExtraAnimationData.UUID_KEY, NetworkUtils.readUuid(buf)); + + boolean isPlayerAnimator = format == AnimationFormat.PLAYER_ANIMATOR; + Map boneAnimations = NetworkUtils.readMap(buf, ProtocolUtils::readString, + buf1 -> readBoneAnimation(buf1, isPlayerAnimator, version)); + + Animation.Keyframes keyFrames = AnimationBinary.readEventKeyframes(buf); + Map pivotBones = NetworkUtils.readMap(buf, ProtocolUtils::readString, NetworkUtils::readVec3f); + Map parents = NetworkUtils.readMap(buf, ProtocolUtils::readString, ProtocolUtils::readString); + + return new Animation(data, length, loopType, boneAnimations, keyFrames, pivotBones, parents); + } + + private static void writeHeader(ByteBuf buf, Animation animation, Map data) { + boolean shouldPlayAgain = animation.loopType().shouldPlayAgain(null, animation); + boolean isHoldOnLastFrame = animation.loopType() == Animation.LoopType.HOLD_ON_LAST_FRAME; + AnimationFormat format = (AnimationFormat) data.getOrDefault(ExtraAnimationData.FORMAT_KEY, AnimationFormat.GECKOLIB); + boolean applyBend = (boolean) data.getOrDefault(ExtraAnimationData.APPLY_BEND_TO_OTHER_BONES_KEY, false); + boolean easeBefore = (boolean) data.getOrDefault(ExtraAnimationData.EASING_BEFORE_KEY, true); + float beginTick = (float) data.getOrDefault(ExtraAnimationData.BEGIN_TICK_KEY, Float.NaN); + float endTick = (float) data.getOrDefault(ExtraAnimationData.END_TICK_KEY, Float.NaN); + + int flags = 0; + flags = HeaderFlag.SHOULD_PLAY_AGAIN.set(flags, shouldPlayAgain); + flags = HeaderFlag.HOLD_ON_LAST_FRAME.set(flags, isHoldOnLastFrame); + flags = HeaderFlag.PLAYER_ANIMATOR.set(flags, format == AnimationFormat.PLAYER_ANIMATOR); + flags = HeaderFlag.APPLY_BEND.set(flags, applyBend); + flags = HeaderFlag.EASE_BEFORE.set(flags, easeBefore); + flags = HeaderFlag.HAS_BEGIN_TICK.set(flags, !Float.isNaN(beginTick)); + flags = HeaderFlag.HAS_END_TICK.set(flags, !Float.isNaN(endTick)); + + VarIntUtils.writeVarInt(buf, flags); + buf.writeFloat(animation.length()); + if (shouldPlayAgain && !isHoldOnLastFrame) { + buf.writeFloat(animation.loopType().restartFromTick(null, animation)); + } + if (HeaderFlag.HAS_BEGIN_TICK.test(flags)) buf.writeFloat(beginTick); + if (HeaderFlag.HAS_END_TICK.test(flags)) buf.writeFloat(endTick); + NetworkUtils.writeUuid(buf, animation.uuid()); + } + + private static void writeBoneAnimation(ByteBuf buf, BoneAnimation bone, int version) { + int presenceFlags = 0; + for (BoneChannel ch : BoneChannel.VALUES) { + if (!ch.getKeyframes(bone).isEmpty()) { + presenceFlags |= ch.mask; + } + } + VarIntUtils.writeVarInt(buf, presenceFlags); + for (BoneChannel ch : BoneChannel.VALUES) { + if ((presenceFlags & ch.mask) != 0) { + writeKeyframeList(buf, ch.getKeyframes(bone), version); + } + } + } + + @SuppressWarnings("unchecked") + private static BoneAnimation readBoneAnimation(ByteBuf buf, boolean shouldStartFromDefault, int version) { + int presenceFlags = VarIntUtils.readVarInt(buf); + List[] lists = new List[BoneChannel.VALUES.length]; + for (BoneChannel ch : BoneChannel.VALUES) { + lists[ch.ordinal()] = (presenceFlags & ch.mask) != 0 + ? readKeyframeList(buf, shouldStartFromDefault, ch.isScale, version) + : new ArrayList<>(0); + } + return new BoneAnimation( + new KeyframeStack(lists[0], lists[1], lists[2]), + new KeyframeStack(lists[3], lists[4], lists[5]), + new KeyframeStack(lists[6], lists[7], lists[8]), + lists[9] + ); + } + + private static void writeKeyframeList(ByteBuf buf, List keyframes, int version) { + VarIntUtils.writeVarInt(buf, keyframes.size()); + for (Keyframe keyframe : keyframes) { + writeKeyframe(keyframe, buf, version); + } + } + + private static void writeKeyframe(Keyframe keyframe, ByteBuf buf, int version) { + List endValue = keyframe.endValue(); + boolean isConstant = endValue.size() == 1 && IsConstantExpression.test(endValue.getFirst()); + boolean hasEasingArgs = false; + for (List inner : keyframe.easingArgs()) { + if (!inner.isEmpty()) { + hasEasingArgs = true; + break; + } + } + + int flags = 0; + if (isConstant) flags |= KeyframeFlag.IS_CONSTANT.mask; + if (hasEasingArgs) flags |= KeyframeFlag.HAS_EASING_ARGS.mask; + if (keyframe.length() == 0.0f) flags |= KeyframeFlag.LENGTH_ZERO.mask; + else if (keyframe.length() == 1.0f) flags |= KeyframeFlag.LENGTH_ONE.mask; + VarIntUtils.writeVarInt(buf, KeyframeFlag.pack(keyframe.easingType().id, flags, version)); + + if (isConstant) { + buf.writeFloat(MOCHA_ENGINE.eval(endValue)); + } else { + ExprBytesUtils.writeExpressions(endValue, buf); + } + + if ((flags & (KeyframeFlag.LENGTH_ZERO.mask | KeyframeFlag.LENGTH_ONE.mask)) == 0) { + buf.writeFloat(keyframe.length()); + } + + if (hasEasingArgs) { + ProtocolUtils.writeList(buf, keyframe.easingArgs(), ExprBytesUtils::writeExpressions); + } + } + + private static List readKeyframeList(ByteBuf buf, boolean shouldStartFromDefault, boolean isScale, int version) { + int count = VarIntUtils.readVarInt(buf); + List list = new ArrayList<>(count); + + for (int i = 0; i < count; i++) { + int combined = VarIntUtils.readVarInt(buf); + int easingId = KeyframeFlag.unpackEasing(combined, version); + int flags = KeyframeFlag.unpackFlags(combined, version); + boolean isConstant = (flags & KeyframeFlag.IS_CONSTANT.mask) != 0; + boolean hasEasingArgs = (flags & KeyframeFlag.HAS_EASING_ARGS.mask) != 0; + + List endValue; + if (isConstant) { + endValue = List.of(FloatExpression.of(buf.readFloat())); + } else { + endValue = ExprBytesUtils.readExpressions(buf); + } + + float length; + if ((flags & KeyframeFlag.LENGTH_ZERO.mask) != 0) length = 0.0f; + else if ((flags & KeyframeFlag.LENGTH_ONE.mask) != 0) length = 1.0f; + else length = buf.readFloat(); + + List startValue = list.isEmpty() + ? (shouldStartFromDefault ? (isScale ? PlayerAnimatorLoader.ONE : PlayerAnimatorLoader.ZERO) : endValue) + : list.getLast().endValue(); + EasingType easingType = EasingType.fromId((byte) easingId); + List> easingArgs; + if (hasEasingArgs) { + easingArgs = ProtocolUtils.readList(buf, ExprBytesUtils::readExpressions); + } else if (shouldStartFromDefault && i > 0) { + easingArgs = Collections.singletonList(new ArrayList<>(0)); + } else { + easingArgs = new ArrayList<>(0); + } + + list.add(new Keyframe(length, startValue, endValue, easingType, easingArgs)); + } + + return list; + } +} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/network/BoneChannel.java b/core/src/main/java/com/zigythebird/playeranimcore/network/BoneChannel.java new file mode 100644 index 00000000..f22faf58 --- /dev/null +++ b/core/src/main/java/com/zigythebird/playeranimcore/network/BoneChannel.java @@ -0,0 +1,40 @@ +package com.zigythebird.playeranimcore.network; + +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.enums.Axis; + +import java.util.List; +import java.util.function.Function; + +enum BoneChannel { + ROTATION_X(BoneAnimation::rotationKeyFrames, Axis.X, false), + ROTATION_Y(BoneAnimation::rotationKeyFrames, Axis.Y, false), + ROTATION_Z(BoneAnimation::rotationKeyFrames, Axis.Z, false), + POSITION_X(BoneAnimation::positionKeyFrames, Axis.X, false), + POSITION_Y(BoneAnimation::positionKeyFrames, Axis.Y, false), + POSITION_Z(BoneAnimation::positionKeyFrames, Axis.Z, false), + SCALE_X(BoneAnimation::scaleKeyFrames, Axis.X, true), + SCALE_Y(BoneAnimation::scaleKeyFrames, Axis.Y, true), + SCALE_Z(BoneAnimation::scaleKeyFrames, Axis.Z, true), + BEND(null, null, false); + + static final BoneChannel[] VALUES = values(); + + final int mask = 1 << ordinal(); + final Function stackAccessor; + final Axis axis; + final boolean isScale; + + BoneChannel(Function stackAccessor, Axis axis, boolean isScale) { + this.stackAccessor = stackAccessor; + this.axis = axis; + this.isScale = isScale; + } + + List getKeyframes(BoneAnimation bone) { + if (this == BEND) return bone.bendKeyFrames(); + return stackAccessor.apply(bone).getKeyFramesForAxis(axis); + } +} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/network/HeaderFlag.java b/core/src/main/java/com/zigythebird/playeranimcore/network/HeaderFlag.java new file mode 100644 index 00000000..c60c8851 --- /dev/null +++ b/core/src/main/java/com/zigythebird/playeranimcore/network/HeaderFlag.java @@ -0,0 +1,21 @@ +package com.zigythebird.playeranimcore.network; + +enum HeaderFlag { + SHOULD_PLAY_AGAIN, + HOLD_ON_LAST_FRAME, + PLAYER_ANIMATOR, + APPLY_BEND, + EASE_BEFORE, + HAS_BEGIN_TICK, + HAS_END_TICK; + + final int mask = 1 << ordinal(); + + boolean test(int flags) { + return (flags & mask) != 0; + } + + int set(int flags, boolean condition) { + return condition ? flags | mask : flags; + } +} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/network/KeyframeFlag.java b/core/src/main/java/com/zigythebird/playeranimcore/network/KeyframeFlag.java new file mode 100644 index 00000000..35f01a14 --- /dev/null +++ b/core/src/main/java/com/zigythebird/playeranimcore/network/KeyframeFlag.java @@ -0,0 +1,44 @@ +package com.zigythebird.playeranimcore.network; + +enum KeyframeFlag { + IS_CONSTANT(6), + HAS_EASING_ARGS(6), + LENGTH_ZERO(6), + LENGTH_ONE(6); + + final int sinceVersion; + final int mask = 1 << ordinal(); + + KeyframeFlag(int sinceVersion) { + this.sinceVersion = sinceVersion; + } + + static int flagBitsForVersion(int version) { + int bits = 0; + for (KeyframeFlag flag : values()) { + if (flag.sinceVersion <= version) bits = flag.ordinal() + 1; + } + return bits; + } + + static int pack(int easingId, int flags, int version) { + return (easingId << flagBitsForVersion(version)) | flags; + } + + static int unpackEasing(int combined, int version) { + return combined >>> flagBitsForVersion(version); + } + + static int unpackFlags(int combined, int version) { + return combined & ((1 << flagBitsForVersion(version)) - 1); + } + + static { + int lastVersion = 0; + for (KeyframeFlag flag : values()) { + if (flag.sinceVersion < lastVersion) + throw new AssertionError("KeyframeFlag." + flag.name() + " sinceVersion " + flag.sinceVersion + " is less than previous " + lastVersion + ". Flags must be ordered by version."); + lastVersion = flag.sinceVersion; + } + } +} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/network/LegacyAnimationBinary.java b/core/src/main/java/com/zigythebird/playeranimcore/network/LegacyAnimationBinary.java index 7cea525b..29cb7d40 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/network/LegacyAnimationBinary.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/network/LegacyAnimationBinary.java @@ -256,6 +256,9 @@ public static Animation read(ByteBuf buf, int version) throws IOException { boneAnimations.put("right_leg", readPart(buf, "right_leg", new BoneAnimation(), version, keyframeSize, easeBefore)); boneAnimations.put("left_leg", readPart(buf, "left_leg", new BoneAnimation(), version, keyframeSize, easeBefore)); } + // Remove empty phantom bones (v1 always creates 6 bones even if they have no data) + boneAnimations.values().removeIf(bone -> !bone.hasKeyframes()); + BoneAnimation body = boneAnimations.get("body"); if (body != null && !body.bendKeyFrames().isEmpty()) { BoneAnimation torso = boneAnimations.computeIfAbsent("torso", name -> new BoneAnimation()); diff --git a/core/src/test/java/io/github/kosmx/emotes/testing/common/AnimationBinaryTest.java b/core/src/test/java/io/github/kosmx/emotes/testing/common/AnimationBinaryTest.java index f3055c72..b6508e1d 100644 --- a/core/src/test/java/io/github/kosmx/emotes/testing/common/AnimationBinaryTest.java +++ b/core/src/test/java/io/github/kosmx/emotes/testing/common/AnimationBinaryTest.java @@ -1,6 +1,7 @@ package io.github.kosmx.emotes.testing.common; import com.zigythebird.playeranimcore.animation.Animation; +import com.zigythebird.playeranimcore.animation.keyframe.BoneAnimation; import com.zigythebird.playeranimcore.network.AnimationBinary; import com.zigythebird.playeranimcore.network.LegacyAnimationBinary; import io.netty.buffer.ByteBuf; @@ -10,11 +11,14 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.util.List; /** * Test network data sending and receiving */ public class AnimationBinaryTest { + private static final List V1_BONES = List.of("head", "body", "right_arm", "left_arm", "right_leg", "left_leg"); + @Test @DisplayName("New binary format") public void newBinaryTest() throws IOException { @@ -38,13 +42,24 @@ public void legacyBinaryTest() throws IOException { int len = LegacyAnimationBinary.calculateSize(animation, version); ByteBuf byteBuf = Unpooled.buffer(len); LegacyAnimationBinary.write(animation, byteBuf, version); - Assertions.assertEquals(len, byteBuf.writerIndex(), "Incorrect size calculator!"); + Assertions.assertEquals(len, byteBuf.writerIndex(), "Incorrect size calculator at version " + version); Assertions.assertTrue(byteBuf.readableBytes() > 0, "animation reads incorrectly at version " + version); Animation readed = LegacyAnimationBinary.read(byteBuf, version); - // Assertions.assertEquals(animation.boneAnimations(), readed.boneAnimations(), "animation reads incorrectly at version " + version); - Assertions.assertNotNull(readed, "animation reads incorrectly at version " + version); // TODO Not working correctly (zigy, please fix) + + if (version < 2) { + // V1 only supports 6 hardcoded bones — compare only those + for (String bone : V1_BONES) { + BoneAnimation orig = animation.boneAnimations().get(bone); + BoneAnimation read = readed.boneAnimations().get(bone); + if (orig != null) { + Assertions.assertEquals(orig, read, "bone '" + bone + "' reads incorrectly at version " + version); + } + } + } else { + Assertions.assertEquals(animation.boneAnimations(), readed.boneAnimations(), "animation reads incorrectly at version " + version); + } byteBuf.release(); } } diff --git a/core/src/test/java/io/github/kosmx/emotes/testing/common/BinarySizeTest.java b/core/src/test/java/io/github/kosmx/emotes/testing/common/BinarySizeTest.java index d15cc955..43f60c98 100644 --- a/core/src/test/java/io/github/kosmx/emotes/testing/common/BinarySizeTest.java +++ b/core/src/test/java/io/github/kosmx/emotes/testing/common/BinarySizeTest.java @@ -25,10 +25,12 @@ public void newBinarySizeTest() throws IOException { for (int version = 1; version <= AnimationBinary.CURRENT_VERSION; version++) { ByteBuf byteBuf = Unpooled.buffer(); + long start = System.nanoTime(); AnimationBinary.write(byteBuf, version, animation); + long elapsed = System.nanoTime() - start; int size = byteBuf.readableBytes(); - System.out.println("[NEW] in version " + version + " size " + size); + System.out.println("[NEW] in version " + version + " size " + size + " time " + (elapsed / 1_000_000.0) + "ms"); Assertions.assertTrue(size < MAX_PACKET_SIZE, "size exceeds"); } } @@ -40,10 +42,12 @@ public void legacyBinarySizeTest() throws IOException { for (int version = 1; version <= LegacyAnimationBinary.getCurrentVersion(); version++) { ByteBuf byteBuf = Unpooled.buffer(LegacyAnimationBinary.calculateSize(animation, version)); + long start = System.nanoTime(); LegacyAnimationBinary.write(animation, byteBuf, version); + long elapsed = System.nanoTime() - start; int size = byteBuf.readableBytes(); - System.out.println("[LEGACY] in version " + version + " size " + size); + System.out.println("[LEGACY] in version " + version + " size " + size + " time " + (elapsed / 1_000_000.0) + "ms"); Assertions.assertTrue(size < MAX_PACKET_SIZE, "size exceeds"); byteBuf.release(); } From 8ccd8d4045c2b6fdb2b773100929a7b148567080 Mon Sep 17 00:00:00 2001 From: Zigy <105124180+ZigyTheBird@users.noreply.github.com> Date: Thu, 26 Feb 2026 19:46:49 +0330 Subject: [PATCH 21/28] Bone refactor (#99) Co-authored-by: dima_dencep --- .../animation/AnimationController.java | 79 ++- .../HumanoidAnimationController.java | 9 +- .../animation/keyframe/AnimationPoint.java | 55 --- .../animation/keyframe/KeyframeLocation.java | 2 +- .../animation/layered/AnimationSnapshot.java | 6 +- .../layered/PlayerAnimationFrame.java | 30 +- .../layered/modifier/AdjustmentModifier.java | 55 +-- .../layered/modifier/MirrorModifier.java | 8 +- .../bones/AdvancedBoneSnapshot.java | 37 -- .../bones/AdvancedPlayerAnimBone.java | 88 +--- .../playeranimcore/bones/BoneSnapshot.java | 224 --------- .../playeranimcore/bones/IBoneEnabled.java | 17 - .../playeranimcore/bones/PlayerAnimBone.java | 450 +++--------------- .../bones/ToggleablePlayerAnimBone.java | 99 ++++ .../playeranimcore/easing/BezierEasing.java | 21 +- .../easing/CatmullRomEasing.java | 15 +- .../playeranimcore/easing/EasingType.java | 23 +- .../easing/EasingTypeTransformer.java | 27 +- .../playeranimcore/util/MatrixUtil.java | 19 +- .../playeranim/mixin/ElytraLayerMixin.java | 2 +- .../mixin/ItemInHandLayerMixin.java | 16 +- .../mixin/LivingEntityRendererMixin.java | 8 +- .../mixin/PlayerCapeModelMixin.java | 16 +- .../playeranim/util/RenderUtil.java | 58 +-- 24 files changed, 318 insertions(+), 1046 deletions(-) delete mode 100644 core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/AnimationPoint.java delete mode 100644 core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedBoneSnapshot.java delete mode 100644 core/src/main/java/com/zigythebird/playeranimcore/bones/BoneSnapshot.java delete mode 100644 core/src/main/java/com/zigythebird/playeranimcore/bones/IBoneEnabled.java create mode 100644 core/src/main/java/com/zigythebird/playeranimcore/bones/ToggleablePlayerAnimBone.java diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java index 8faeed05..9dce5f1c 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/AnimationController.java @@ -68,8 +68,8 @@ * one to control attacks, one to control size, etc. */ public abstract class AnimationController implements IAnimation { - public static KeyframeLocation EMPTY_KEYFRAME_LOCATION = new KeyframeLocation<>(new Keyframe(0), 0); - public static KeyframeLocation EMPTY_SCALE_KEYFRAME_LOCATION = new KeyframeLocation<>(new Keyframe(0, Collections.singletonList(FloatExpression.ONE), Collections.singletonList(FloatExpression.ONE)), 0); + public static KeyframeLocation EMPTY_KEYFRAME_LOCATION = new KeyframeLocation(new Keyframe(0), 0); + public static KeyframeLocation EMPTY_SCALE_KEYFRAME_LOCATION = new KeyframeLocation(new Keyframe(0, Collections.singletonList(FloatExpression.ONE), Collections.singletonList(FloatExpression.ONE)), 0); protected final AnimationStateHandler stateHandler; protected final Map bonePositions; @@ -408,9 +408,9 @@ public void triggerAnimation(Animation newAnimation) { public void replaceAnimationWithFade(@NotNull AbstractFadeModifier fadeModifier, @Nullable RawAnimation newAnimation, boolean fadeFromNothing) { if (fadeFromNothing || this.isActive()) { if (this.isActive()) { - Map snapshots = new HashMap<>(); + Map snapshots = new HashMap<>(); for (PlayerAnimBone bone : activeBones.values()) { - snapshots.put(bone.getName(), new AdvancedBoneSnapshot(bone)); + snapshots.put(bone.getName(), new ToggleablePlayerAnimBone(bone)); } fadeModifier.setTransitionAnimation(new AnimationSnapshot(snapshots)); } @@ -577,33 +577,19 @@ private void processCurrentAnimation(float adjustedTick, AnimationData animation KeyframeStack rotationKeyFrames = boneAnimation.rotationKeyFrames(); KeyframeStack positionKeyFrames = boneAnimation.positionKeyFrames(); KeyframeStack scaleKeyFrames = boneAnimation.scaleKeyFrames(); - List bendKeyFrames = boneAnimation.bendKeyFrames(); - - AnimationPoint rotXPoint = getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, TransformType.ROTATION, isAdvancedBone ? advancedBone::setRotXTransitionLength : null); - AnimationPoint rotYPoint = getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, TransformType.ROTATION, isAdvancedBone ? advancedBone::setRotYTransitionLength : null); - AnimationPoint rotZPoint = getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, TransformType.ROTATION, isAdvancedBone ? advancedBone::setRotZTransitionLength : null); - AnimationPoint posXPoint = getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, TransformType.POSITION, isAdvancedBone ? advancedBone::setPositionXTransitionLength : null); - AnimationPoint posYPoint = getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, TransformType.POSITION, isAdvancedBone ? advancedBone::setPositionYTransitionLength : null); - AnimationPoint posZPoint = getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, TransformType.POSITION, isAdvancedBone ? advancedBone::setPositionZTransitionLength : null); - AnimationPoint scaleXPoint = getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, TransformType.SCALE, isAdvancedBone ? advancedBone::setScaleXTransitionLength : null); - AnimationPoint scaleYPoint = getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, TransformType.SCALE, isAdvancedBone ? advancedBone::setScaleYTransitionLength : null); - AnimationPoint scaleZPoint = getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, TransformType.SCALE, isAdvancedBone ? advancedBone::setScaleZTransitionLength : null); - AnimationPoint bendPoint = getAnimationPointAtTick(bendKeyFrames, adjustedTick, TransformType.BEND, isAdvancedBone ? advancedBone::setBendTransitionLength : null); - EasingType easingType = this.overrideEasingTypeFunction.apply(this); - - bone.setRotX(EasingType.lerpWithOverride(this.molangRuntime, rotXPoint, easingType)); - bone.setRotY(EasingType.lerpWithOverride(this.molangRuntime, rotYPoint, easingType)); - bone.setRotZ(EasingType.lerpWithOverride(this.molangRuntime, rotZPoint, easingType)); - - bone.setPosX(EasingType.lerpWithOverride(this.molangRuntime, posXPoint, easingType)); - bone.setPosY(EasingType.lerpWithOverride(this.molangRuntime, posYPoint, easingType)); - bone.setPosZ(EasingType.lerpWithOverride(this.molangRuntime, posZPoint, easingType)); - - bone.setScaleX(EasingType.lerpWithOverride(this.molangRuntime, scaleXPoint, easingType)); - bone.setScaleY(EasingType.lerpWithOverride(this.molangRuntime, scaleYPoint, easingType)); - bone.setScaleZ(EasingType.lerpWithOverride(this.molangRuntime, scaleZPoint, easingType)); - - bone.setBend(EasingType.lerpWithOverride(this.molangRuntime, bendPoint, easingType)); + EasingType easingOverride = this.overrideEasingTypeFunction.apply(this); + + bone.rotation.x = computeAnimValue(rotationKeyFrames.xKeyframes(), adjustedTick, TransformType.ROTATION, easingOverride, isAdvancedBone ? advancedBone::setRotXTransitionLength : null); + bone.rotation.y = computeAnimValue(rotationKeyFrames.yKeyframes(), adjustedTick, TransformType.ROTATION, easingOverride, isAdvancedBone ? advancedBone::setRotYTransitionLength : null); + bone.rotation.z = computeAnimValue(rotationKeyFrames.zKeyframes(), adjustedTick, TransformType.ROTATION, easingOverride, isAdvancedBone ? advancedBone::setRotZTransitionLength : null); + + bone.position.x = computeAnimValue(positionKeyFrames.xKeyframes(), adjustedTick, TransformType.POSITION, easingOverride, isAdvancedBone ? advancedBone::setPositionXTransitionLength : null); + bone.position.y = computeAnimValue(positionKeyFrames.yKeyframes(), adjustedTick, TransformType.POSITION, easingOverride, isAdvancedBone ? advancedBone::setPositionYTransitionLength : null); + bone.position.z = computeAnimValue(positionKeyFrames.zKeyframes(), adjustedTick, TransformType.POSITION, easingOverride, isAdvancedBone ? advancedBone::setPositionZTransitionLength : null); + + bone.scale.x = computeAnimValue(scaleKeyFrames.xKeyframes(), adjustedTick, TransformType.SCALE, easingOverride, isAdvancedBone ? advancedBone::setScaleXTransitionLength : null); + bone.scale.y = computeAnimValue(scaleKeyFrames.yKeyframes(), adjustedTick, TransformType.SCALE, easingOverride, isAdvancedBone ? advancedBone::setScaleYTransitionLength : null); + bone.scale.z = computeAnimValue(scaleKeyFrames.zKeyframes(), adjustedTick, TransformType.SCALE, easingOverride, isAdvancedBone ? advancedBone::setScaleZTransitionLength : null); } applyCustomPivotPoints(); @@ -761,23 +747,22 @@ else if (pivotBones.containsKey(entry.getKey())) } /** - * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} + * Compute animation value for the given keyframes at the specified tick */ - private AnimationPoint getAnimationPointAtTick(List frames, float tick, TransformType type, Consumer transitionLengthSetter) { + private float computeAnimValue(List frames, float tick, TransformType type, @Nullable EasingType easingOverride, Consumer transitionLengthSetter) { Animation animation = this.currentAnimation.animation(); float endTick = animation.data().get(ExtraAnimationData.END_TICK_KEY).orElse(animation.length()-1); - KeyframeLocation location = getCurrentKeyFrameLocation(frames, tick, type, this.isAnimationPlayerAnimatorFormat() && this.currentAnimation.loopType().shouldPlayAgain(null, animation), animation.length(), this.currentAnimation.loopType().restartFromTick(null, animation)); + KeyframeLocation location = getCurrentKeyFrameLocation(frames, tick, type, this.isAnimationPlayerAnimatorFormat() && this.currentAnimation.loopType().shouldPlayAgain(null, animation), animation.length(), this.currentAnimation.loopType().restartFromTick(null, animation)); Keyframe currentFrame = location.keyframe(); float startValue = this.molangRuntime.eval(currentFrame.startValue()); float endValue = this.molangRuntime.eval(currentFrame.endValue()); if (type == TransformType.ROTATION || type == TransformType.BEND) { - if (!(MolangLoader.isConstant(currentFrame.startValue()))) { + if (!MolangLoader.isConstant(currentFrame.startValue())) { startValue = (float) Math.toRadians(startValue); } - - if (!(MolangLoader.isConstant(currentFrame.endValue()))) { + if (!MolangLoader.isConstant(currentFrame.endValue())) { endValue = (float) Math.toRadians(endValue); } } @@ -792,7 +777,9 @@ private AnimationPoint getAnimationPointAtTick(List frames, float tick } else transitionLengthSetter.accept(null); } - return new AnimationPoint(currentFrame.easingType(), currentFrame.easingArgs(), location.startTick(), currentFrame.length(), startValue, endValue); + + float lerpValue = currentFrame.length() > 0 ? location.startTick() / currentFrame.length() : 0; + return EasingType.lerpWithOverride(this.molangRuntime, startValue, endValue, currentFrame.length(), lerpValue, currentFrame.easingArgs(), currentFrame.easingType(), easingOverride); } /** @@ -802,9 +789,8 @@ private AnimationPoint getAnimationPointAtTick(List frames, float tick * @param ageInTicks The current tick time * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it */ - private KeyframeLocation getCurrentKeyFrameLocation(List frames, float ageInTicks, TransformType type, boolean isPlayerAnimatorLoop, float animTime, float returnToTick) { - if (frames.isEmpty()) - return type == TransformType.SCALE ? EMPTY_SCALE_KEYFRAME_LOCATION : EMPTY_KEYFRAME_LOCATION; + private KeyframeLocation getCurrentKeyFrameLocation(List frames, float ageInTicks, TransformType type, boolean isPlayerAnimatorLoop, float animTime, float returnToTick) { + if (frames.isEmpty()) return type == TransformType.SCALE ? EMPTY_SCALE_KEYFRAME_LOCATION : EMPTY_KEYFRAME_LOCATION; Keyframe firstFrame = returnToTick == 0 ? frames.getFirst() : Keyframe.getKeyframeAtTime(frames, returnToTick); float totalFrameTime = 0; @@ -815,16 +801,17 @@ private KeyframeLocation getCurrentKeyFrameLocation(List fra if (totalFrameTime > ageInTicks) { if (isPlayerAnimatorLoop && isLoopStarted() && frame == firstFrame) { float stopTickMinusLastKeyframe = animTime - Keyframe.getLastKeyframeTime(frames); - return new KeyframeLocation<>(new Keyframe(frame.length() + stopTickMinusLastKeyframe, frames.getLast().endValue(), frame.endValue(), frame.easingType(), frame.easingArgs()), ageInTicks + stopTickMinusLastKeyframe); + return new KeyframeLocation(new Keyframe(frame.length() + stopTickMinusLastKeyframe, frames.getLast().endValue(), frame.endValue(), frame.easingType(), frame.easingArgs()), ageInTicks + stopTickMinusLastKeyframe); } - return new KeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); + return new KeyframeLocation(frame, ageInTicks - (totalFrameTime - frame.length())); } } - if (isPlayerAnimatorLoop) - return new KeyframeLocation<>(new Keyframe(firstFrame.length() + animTime - totalFrameTime, frames.getLast().endValue(), firstFrame.endValue(), firstFrame.easingType(), firstFrame.easingArgs()), ageInTicks - totalFrameTime); + if (isPlayerAnimatorLoop) { + return new KeyframeLocation(new Keyframe(firstFrame.length() + animTime - totalFrameTime, frames.getLast().endValue(), firstFrame.endValue(), firstFrame.easingType(), firstFrame.easingArgs()), ageInTicks - totalFrameTime); + } - return new KeyframeLocation<>(frames.getLast(), ageInTicks); + return new KeyframeLocation(frames.getLast(), ageInTicks); } /** diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/HumanoidAnimationController.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/HumanoidAnimationController.java index 4af219e0..52d2b92a 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/HumanoidAnimationController.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/HumanoidAnimationController.java @@ -28,7 +28,6 @@ import com.zigythebird.playeranimcore.math.Vec3f; import org.jetbrains.annotations.NotNull; import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.standard.MochaMath; import java.util.ArrayList; import java.util.List; @@ -107,6 +106,7 @@ public void registerTopPlayerAnimBone(String name) { @Override public void process(AnimationData state) { super.process(state); + /* TODO Commented out until we decide what we want to do with bends this.torsoBend = bones.get("torso").getBend(); float absBend = Math.abs(this.torsoBend); if (absBend > 0.001 && (this.currentAnimation != null && this.currentAnimation.animation().data().getNullable(ExtraAnimationData.APPLY_BEND_TO_OTHER_BONES_KEY) == Boolean.TRUE)) { @@ -114,6 +114,7 @@ public void process(AnimationData state) { this.torsoBendYPosMultiplier = (float) -(1 - Math.cos(absBend)); this.torsoBendZPosMultiplier = (float) (1 - Math.sin(absBend)); } else this.torsoBendSign = 0; + */ } @Override @@ -122,9 +123,9 @@ public PlayerAnimBone get3DTransformRaw(@NotNull PlayerAnimBone bone) { String name = bone.getName(); if (this.torsoBendSign != 0 && this.top_bones.contains(name)) { float offset = getBonePosition(name).y() - 18; - bone.rotX += this.torsoBend; - bone.positionZ += (offset * this.torsoBendZPosMultiplier - offset) * this.torsoBendSign; - bone.positionY += offset * this.torsoBendYPosMultiplier; + bone.rotation.x += this.torsoBend; + bone.position.x += (offset * this.torsoBendZPosMultiplier - offset) * this.torsoBendSign; + bone.position.y += offset * this.torsoBendYPosMultiplier; } return bone; } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/AnimationPoint.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/AnimationPoint.java deleted file mode 100644 index 75748b40..00000000 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/AnimationPoint.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 GeckoLib - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package com.zigythebird.playeranimcore.animation.keyframe; - -import com.zigythebird.playeranimcore.easing.EasingType; -import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.ast.Expression; - -import java.util.List; - -/** - * Animation state record that holds the state of an animation at a given point - * - * @param easingType The easing type - * @param easingArgs The easing arguments - * @param currentTick The lerped tick time (current tick + partial tick) of the point - * @param transitionLength The length of time (in ticks) that the point should take to transition - * @param animationStartValue The start value to provide to the animation handling system - * @param animationEndValue The end value to provide to the animation handling system - */ -public record AnimationPoint(EasingType easingType, @Nullable List> easingArgs, float currentTick, float transitionLength, float animationStartValue, float animationEndValue) { - public AnimationPoint(Keyframe keyframe, float currentTick, float transitionLength, float animationStartValue, float animationEndValue) { - this(keyframe == null ? EasingType.LINEAR : keyframe.easingType(), keyframe == null ? null : keyframe.easingArgs(), currentTick, transitionLength, animationStartValue, animationEndValue); - } - - @Override - public String toString() { - return "Tick: " + this.currentTick + - " | Transition Length: " + this.transitionLength + - " | Start Value: " + this.animationStartValue + - " | End Value: " + this.animationEndValue; - } -} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/KeyframeLocation.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/KeyframeLocation.java index ea4ff529..aeb4a8e4 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/KeyframeLocation.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/keyframe/KeyframeLocation.java @@ -30,4 +30,4 @@ * @param keyframe The {@code Keyframe} at the tick time * @param startTick The animation tick time at the start of this {@code Keyframe} */ -public record KeyframeLocation(T keyframe, float startTick) { } +public record KeyframeLocation(Keyframe keyframe, float startTick) {} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java index 5256a1d1..afc51c9d 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/AnimationSnapshot.java @@ -1,12 +1,12 @@ package com.zigythebird.playeranimcore.animation.layered; -import com.zigythebird.playeranimcore.bones.AdvancedBoneSnapshot; import com.zigythebird.playeranimcore.bones.PlayerAnimBone; +import com.zigythebird.playeranimcore.bones.ToggleablePlayerAnimBone; import org.jetbrains.annotations.NotNull; import java.util.Map; -public record AnimationSnapshot(Map snapshots) implements IAnimation { +public record AnimationSnapshot(Map snapshots) implements IAnimation { @Override public boolean isActive() { return true; @@ -15,7 +15,7 @@ public boolean isActive() { @Override public void get3DTransform(@NotNull PlayerAnimBone bone) { if (snapshots.containsKey(bone.getName())) { - bone.copySnapshotSafe(snapshots.get(bone.getName())); + bone.copyOtherBoneIfNotDisabled(snapshots.get(bone.getName())); } } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java index be55a37b..cf9d8d56 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/PlayerAnimationFrame.java @@ -96,7 +96,8 @@ public void get3DTransform(@NotNull PlayerAnimBone bone) { PlayerBone part = parts.get(bone.getName()); if (part != null) part.applyToBone(bone); } - + + //TODO Maybe replace this with smth better public static class PlayerBone { public Float offsetPosX = null; public Float offsetPosY = null; @@ -109,8 +110,6 @@ public static class PlayerBone { public Float scaleX = null; public Float scaleY = null; public Float scaleZ = null; - - public Float bend = null; public PlayerBone() { super(); @@ -132,8 +131,6 @@ public void setToInitialPose() { this.scaleX = null; this.scaleY = null; this.scaleZ = null; - - this.bend = null; } /** @@ -151,34 +148,29 @@ public void enableAll() { this.scaleX = 1F; this.scaleY = 1F; this.scaleZ = 1F; - - this.bend = 0F; } public PlayerAnimBone applyToBone(PlayerAnimBone bone) { if (offsetPosX != null) - bone.setPosX(offsetPosX); + bone.position.x = offsetPosX; if (offsetPosY != null) - bone.setPosY(offsetPosY); + bone.position.y = offsetPosY; if (offsetPosZ != null) - bone.setPosZ(offsetPosZ); + bone.position.z = offsetPosZ; if (rotX != null) - bone.setRotX(rotX); + bone.rotation.x = rotX; if (rotY != null) - bone.setRotY(rotY); + bone.rotation.y = rotY; if (rotZ != null) - bone.setRotZ(rotZ); + bone.rotation.z = rotZ; if (scaleX != null) - bone.setScaleX(scaleX); + bone.scale.x = scaleX; if (scaleY != null) - bone.setScaleY(scaleY); + bone.scale.y = scaleY; if (scaleZ != null) - bone.setScaleZ(scaleZ); - - if (bend != null) - bone.setBend(bend); + bone.scale.z = scaleZ; return bone; } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java index a0c55a3a..08b7385c 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/AdjustmentModifier.java @@ -30,7 +30,6 @@ import com.zigythebird.playeranimcore.math.Vec3f; import org.jetbrains.annotations.NotNull; -import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; @@ -77,55 +76,11 @@ * */ public class AdjustmentModifier extends AbstractModifier { - public static final class PartModifier { - private final Vec3f rotation; - private final Vec3f scale; - private final Vec3f offset; - + //TODO Maybe we can replace this with something that uses Vector3f + public record PartModifier(Vec3f rotation, Vec3f scale, Vec3f offset) { public PartModifier(Vec3f rotation, Vec3f offset) { this(rotation, Vec3f.ZERO, offset); } - - public PartModifier(Vec3f rotation, Vec3f scale, Vec3f offset) { - this.rotation = rotation; - this.scale = scale; - this.offset = offset; - } - - public Vec3f rotation() { - return rotation; - } - - public Vec3f scale() { - return scale; - } - - public Vec3f offset() { - return offset; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - PartModifier that = (PartModifier) obj; - return Objects.equals(this.rotation, that.rotation) && - Objects.equals(this.scale, that.scale) && - Objects.equals(this.offset, that.offset); - } - - @Override - public int hashCode() { - return Objects.hash(rotation, scale, offset); - } - - @Override - public String toString() { - return "PartModifier[" + - "rotation=" + rotation + ", " + - "scale=" + scale + ", " + - "offset=" + offset + ']'; - } } /// Whether the adjustment should be increasingly applied @@ -228,9 +183,9 @@ protected void transformBone(PlayerAnimBone bone, PartModifier partModifier, flo Vec3f pos = partModifier.offset().mul(fade); Vec3f rot = partModifier.rotation().mul(fade); Vec3f scale = partModifier.scale().mul(fade); - bone.updatePosition(pos.x() + bone.getPosX(), pos.y() + bone.getPosY(), pos.z() + bone.getPosZ()); - bone.updateRotation(rot.x() + bone.getRotX(), rot.y() + bone.getRotY(), rot.z() + bone.getRotZ()); - bone.updateScale(scale.x() + bone.getScaleX(), scale.y() + bone.getScaleY(), scale.z() + bone.getScaleZ()); + bone.position.add(pos.x(), pos.y(), pos.z()); + bone.rotation.add(rot.x(), rot.y(), rot.z()); + bone.scale.add(scale.x(), scale.y(), scale.z()); } @Override diff --git a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java index 20502393..4f18e9be 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/animation/layered/modifier/MirrorModifier.java @@ -67,10 +67,10 @@ public void get3DTransform(@NotNull PlayerAnimBone bone) { } protected void transformBone(PlayerAnimBone bone) { - bone.positionX *= -1; - bone.rotY *= -1; - bone.rotZ *= -1; - bone.bend *= -1; + bone.position.x *= -1; + bone.rotation.y *= -1; + bone.rotation.z *= -1; + //bone.bend *= -1; Why was this a thing in the first place? } static { diff --git a/core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedBoneSnapshot.java b/core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedBoneSnapshot.java deleted file mode 100644 index aec409f9..00000000 --- a/core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedBoneSnapshot.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.zigythebird.playeranimcore.bones; - -public class AdvancedBoneSnapshot extends BoneSnapshot { - public boolean scaleXEnabled; - public boolean scaleYEnabled; - public boolean scaleZEnabled; - - public boolean positionXEnabled; - public boolean positionYEnabled; - public boolean positionZEnabled; - - public boolean rotXEnabled; - public boolean rotYEnabled; - public boolean rotZEnabled; - - public boolean bendEnabled; - - public AdvancedBoneSnapshot(PlayerAnimBone bone) { - super(bone); - - if (bone instanceof IBoneEnabled boneEnabled) { - scaleXEnabled = boneEnabled.isScaleXEnabled(); - scaleYEnabled = boneEnabled.isScaleYEnabled(); - scaleZEnabled = boneEnabled.isScaleZEnabled(); - - positionXEnabled = boneEnabled.isPositionXEnabled(); - positionYEnabled = boneEnabled.isPositionYEnabled(); - positionZEnabled = boneEnabled.isPositionZEnabled(); - - rotXEnabled = boneEnabled.isRotXEnabled(); - rotYEnabled = boneEnabled.isRotYEnabled(); - rotZEnabled = boneEnabled.isRotZEnabled(); - - bendEnabled = boneEnabled.isBendEnabled(); - } - } -} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedPlayerAnimBone.java b/core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedPlayerAnimBone.java index a0b1f8a6..6300fca2 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedPlayerAnimBone.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/bones/AdvancedPlayerAnimBone.java @@ -1,6 +1,6 @@ package com.zigythebird.playeranimcore.bones; -public class AdvancedPlayerAnimBone extends PlayerAnimBone implements IBoneEnabled { +public class AdvancedPlayerAnimBone extends ToggleablePlayerAnimBone { public Float scaleXTransitionLength = null; public Float scaleYTransitionLength = null; public Float scaleZTransitionLength = null; @@ -15,24 +15,14 @@ public class AdvancedPlayerAnimBone extends PlayerAnimBone implements IBoneEnabl public Float bendTransitionLength = null; - public boolean scaleXEnabled = true; - public boolean scaleYEnabled = true; - public boolean scaleZEnabled = true; - - public boolean positionXEnabled = true; - public boolean positionYEnabled = true; - public boolean positionZEnabled = true; - - public boolean rotXEnabled = true; - public boolean rotYEnabled = true; - public boolean rotZEnabled = true; - - public boolean bendEnabled = true; - public AdvancedPlayerAnimBone(String name) { super(name); } + public AdvancedPlayerAnimBone(PlayerAnimBone bone) { + super(bone); + } + public void setEnabled(boolean enabled) { scaleXEnabled = enabled; scaleYEnabled = enabled; @@ -88,72 +78,4 @@ public void setScaleYTransitionLength(Float scaleYTransitionLength) { public void setScaleXTransitionLength(Float scaleXTransitionLength) { this.scaleXTransitionLength = scaleXTransitionLength; } - - public void setPositionEnabled(boolean enabled) { - this.positionXEnabled = enabled; - this.positionYEnabled = enabled; - this.positionZEnabled = enabled; - } - - public void setRotEnabled(boolean enabled) { - this.rotXEnabled = enabled; - this.rotYEnabled = enabled; - this.rotZEnabled = enabled; - } - - public void setScaleEnabled(boolean enabled) { - this.scaleXEnabled = enabled; - this.scaleYEnabled = enabled; - this.scaleZEnabled = enabled; - } - - @Override - public boolean isScaleXEnabled() { - return scaleXEnabled; - } - - @Override - public boolean isScaleYEnabled() { - return scaleYEnabled; - } - - @Override - public boolean isScaleZEnabled() { - return scaleZEnabled; - } - - @Override - public boolean isPositionXEnabled() { - return positionXEnabled; - } - - @Override - public boolean isPositionYEnabled() { - return positionYEnabled; - } - - @Override - public boolean isPositionZEnabled() { - return positionZEnabled; - } - - @Override - public boolean isRotXEnabled() { - return rotXEnabled; - } - - @Override - public boolean isRotYEnabled() { - return rotYEnabled; - } - - @Override - public boolean isRotZEnabled() { - return rotZEnabled; - } - - @Override - public boolean isBendEnabled() { - return bendEnabled; - } } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/bones/BoneSnapshot.java b/core/src/main/java/com/zigythebird/playeranimcore/bones/BoneSnapshot.java deleted file mode 100644 index a2ddf275..00000000 --- a/core/src/main/java/com/zigythebird/playeranimcore/bones/BoneSnapshot.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.zigythebird.playeranimcore.bones; - -import com.zigythebird.playeranimcore.animation.AnimationController; -import com.zigythebird.playeranimcore.enums.TransformType; -import com.zigythebird.playeranimcore.math.Vec3f; -import it.unimi.dsi.fastutil.Pair; - -/** - * Transformations applied to the bone are monitored by the {@link AnimationController} - * in the course of animations, and stored here for monitoring. - */ -public class BoneSnapshot { - public final PlayerAnimBone bone; - - private float scaleX; - private float scaleY; - private float scaleZ; - - private float offsetPosX; - private float offsetPosY; - private float offsetPosZ; - - private float rotX; - private float rotY; - private float rotZ; - - private float bendAxis; - private float bend; - - public BoneSnapshot() { - this.bone = null; - setToInitialPose(); - } - - public BoneSnapshot(PlayerAnimBone bone) { - this.rotX = bone.getRotX(); - this.rotY = bone.getRotY(); - this.rotZ = bone.getRotZ(); - - this.offsetPosX = bone.getPosX(); - this.offsetPosY = bone.getPosY(); - this.offsetPosZ = bone.getPosZ(); - - this.scaleX = bone.getScaleX(); - this.scaleY = bone.getScaleY(); - this.scaleZ = bone.getScaleZ(); - - this.bend = bone.getBend(); - - this.bone = bone; - } - - public BoneSnapshot(BoneSnapshot bone) { - this.bone = bone.getBone(); - - this.rotX = bone.getRotX(); - this.rotY = bone.getRotY(); - this.rotZ = bone.getRotZ(); - - this.offsetPosX = bone.getOffsetX(); - this.offsetPosY = bone.getOffsetY(); - this.offsetPosZ = bone.getOffsetZ(); - - this.scaleX = bone.getScaleX(); - this.scaleY = bone.getScaleY(); - this.scaleZ = bone.getScaleZ(); - - this.bendAxis = bone.getBendAxis(); - this.bend = bone.getBend(); - } - - public BoneSnapshot(PlayerAnimBone bone, boolean isInitial) { - this.bone = bone; - if (!isInitial) { - this.rotX = bone.getRotX(); - this.rotY = bone.getRotY(); - this.rotZ = bone.getRotZ(); - - this.offsetPosX = bone.getPosX(); - this.offsetPosY = bone.getPosY(); - this.offsetPosZ = bone.getPosZ(); - - this.scaleX = bone.getScaleX(); - this.scaleY = bone.getScaleY(); - this.scaleZ = bone.getScaleZ(); - - this.bend = bone.getBend(); - } - else setToInitialPose(); - } - - public PlayerAnimBone getBone() {return this.bone;} - - public float getScaleX() { - return this.scaleX; - } - - public float getScaleY() { - return this.scaleY; - } - - public float getScaleZ() { - return this.scaleZ; - } - - public float getOffsetX() { - return this.offsetPosX; - } - - public float getOffsetY() { - return this.offsetPosY; - } - - public float getOffsetZ() { - return this.offsetPosZ; - } - - public float getRotX() { - return this.rotX; - } - - public float getRotY() { - return this.rotY; - } - - public float getRotZ() { - return this.rotZ; - } - - public float getBendAxis() { - return this.bendAxis; - } - - public float getBend() { - return this.bend; - } - - /** - * Update the scale state of this snapshot - */ - public void updateScale(float scaleX, float scaleY, float scaleZ) { - this.scaleX = scaleX; - this.scaleY = scaleY; - this.scaleZ = scaleZ; - } - - /** - * Update the offset state of this snapshot - */ - public void updateOffset(float offsetX, float offsetY, float offsetZ) { - this.offsetPosX = offsetX; - this.offsetPosY = offsetY; - this.offsetPosZ = offsetZ; - } - - /** - * Update the rotation state of this snapshot - */ - public void updateRotation(float rotX, float rotY, float rotZ) { - this.rotX = rotX; - this.rotY = rotY; - this.rotZ = rotZ; - } - - public void updateBend(float bendAxis, float bend) { - this.bendAxis = bendAxis; - this.bend = bend; - } - - public void updateBend(Pair bend) { - updateBend(bend.left(), bend.right()); - } - - public Vec3f getTransformFromType(TransformType type) { - switch (type) { - case POSITION -> { - return new Vec3f(offsetPosX, offsetPosY, offsetPosZ); - } - case ROTATION -> { - return new Vec3f(rotX, rotY, rotZ); - } - case SCALE -> { - return new Vec3f(scaleX, scaleY, scaleZ); - } - case BEND -> { - return new Vec3f(bendAxis, bend, 0); - } - } - return null; - } - - public void setToInitialPose() { - this.rotX = 0; - this.rotY = 0; - this.rotZ = 0; - - this.offsetPosX = 0; - this.offsetPosY = 0; - this.offsetPosZ = 0; - - this.scaleX = 1; - this.scaleY = 1; - this.scaleZ = 1; - - this.bendAxis = 0; - this.bend = 0; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - - if (obj == null || getClass() != obj.getClass()) - return false; - - return hashCode() == obj.hashCode(); - } - - @Override - public int hashCode() { - return this.bone.getName().hashCode(); - } -} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/bones/IBoneEnabled.java b/core/src/main/java/com/zigythebird/playeranimcore/bones/IBoneEnabled.java deleted file mode 100644 index 92f4d3f2..00000000 --- a/core/src/main/java/com/zigythebird/playeranimcore/bones/IBoneEnabled.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.zigythebird.playeranimcore.bones; - -public interface IBoneEnabled { - boolean isScaleXEnabled(); - boolean isScaleYEnabled(); - boolean isScaleZEnabled(); - - boolean isPositionXEnabled(); - boolean isPositionYEnabled(); - boolean isPositionZEnabled(); - - boolean isRotXEnabled(); - boolean isRotYEnabled(); - boolean isRotZEnabled(); - - boolean isBendEnabled(); -} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/bones/PlayerAnimBone.java b/core/src/main/java/com/zigythebird/playeranimcore/bones/PlayerAnimBone.java index 042e21c7..f1a3dcaf 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/bones/PlayerAnimBone.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/bones/PlayerAnimBone.java @@ -8,8 +8,10 @@ import com.zigythebird.playeranimcore.easing.EasingType; import com.zigythebird.playeranimcore.enums.Axis; import com.zigythebird.playeranimcore.enums.TransformType; +import com.zigythebird.playeranimcore.math.MathHelper; import com.zigythebird.playeranimcore.math.Vec3f; import org.jetbrains.annotations.ApiStatus; +import org.joml.Vector3f; import java.util.List; @@ -17,360 +19,89 @@ * This is the object that is directly modified by animations to handle movement */ public class PlayerAnimBone { - private final String name; - - public float scaleX = 1; - public float scaleY = 1; - public float scaleZ = 1; - - public float positionX; - public float positionY; - public float positionZ; - - public float rotX; - public float rotY; - public float rotZ; - - public float bend; + public final String name; + public final Vector3f position; + public final Vector3f rotation; + public final Vector3f scale; public PlayerAnimBone(String name) { this.name = name; + this.position = new Vector3f(); + this.rotation = new Vector3f(); + this.scale = new Vector3f(1); } - public String getName() { - return this.name; - } - - public float getRotX() { - return this.rotX; - } - - public float getRotY() { - return this.rotY; - } - - public float getRotZ() { - return this.rotZ; - } - - public float getPosX() { - return this.positionX; - } - - public float getPosY() { - return this.positionY; - } - - public float getPosZ() { - return this.positionZ; - } - - public float getScaleX() { - return this.scaleX; - } - - public float getScaleY() { - return this.scaleY; - } - - public float getScaleZ() { - return this.scaleZ; - } - - public float getBend() { - return this.bend; - } - - public void setRotX(float value) { - this.rotX = value; - } - - public void setRotY(float value) { - this.rotY = value; - } - - public void setRotZ(float value) { - this.rotZ = value; - } - - public void updateRotation(float xRot, float yRot, float zRot) { - setRotX(xRot); - setRotY(yRot); - setRotZ(zRot); - } - - public void setPosX(float value) { - this.positionX = value; + public PlayerAnimBone(PlayerAnimBone bone) { + this.name = bone.getName(); + this.position = new Vector3f(bone.position); + this.rotation = new Vector3f(bone.rotation); + this.scale = new Vector3f(bone.scale); } - public void setPosY(float value) { - this.positionY = value; - } - - public void setPosZ(float value) { - this.positionZ = value; - } - - public void updatePosition(float posX, float posY, float posZ) { - setPosX(posX); - setPosY(posY); - setPosZ(posZ); - } - - public void setScaleX(float value) { - this.scaleX = value; - } - - public void setScaleY(float value) { - this.scaleY = value; - } - - public void setScaleZ(float value) { - this.scaleZ = value; - } - - public void updateScale(float scaleX, float scaleY, float scaleZ) { - setScaleX(scaleX); - setScaleY(scaleY); - setScaleZ(scaleZ); - } - - public void setBend(float value) { - this.bend = value; + public String getName() { + return this.name; } public void setToInitialPose() { - this.positionX = 0; - this.positionY = 0; - this.positionZ = 0; - - this.rotX = 0; - this.rotY = 0; - this.rotZ = 0; - - this.scaleX = 1; - this.scaleY = 1; - this.scaleZ = 1; - - this.bend = 0; - } - - public Vec3f getPositionVector() { - return new Vec3f(getPosX(), getPosY(), getPosZ()); - } - - public Vec3f getRotationVector() { - return new Vec3f(getRotX(), getRotY(), getRotZ()); - } - - public Vec3f getScaleVector() { - return new Vec3f(getScaleX(), getScaleY(), getScaleZ()); - } - - public void addRotationOffsetFromBone(PlayerAnimBone source) { - setRotX(getRotX() + source.getRotX()); - setRotY(getRotY() + source.getRotY()); - setRotZ(getRotZ() + source.getRotZ()); + this.position.set(0, 0, 0); + this.rotation.set(0, 0, 0); + this.scale.set(1, 1, 1); } public PlayerAnimBone scale(float value) { - this.positionX *= value; - this.positionY *= value; - this.positionZ *= value; - - this.rotX *= value; - this.rotY *= value; - this.rotZ *= value; - - this.scaleX *= value; - this.scaleY *= value; - this.scaleZ *= value; - - this.bend *= value; + this.position.mul(value); + this.rotation.mul(value); + this.scale.mul(value); return this; } public PlayerAnimBone add(PlayerAnimBone bone) { - this.positionX += bone.positionX; - this.positionY += bone.positionY; - this.positionZ += bone.positionZ; - - this.rotX += bone.rotX; - this.rotY += bone.rotY; - this.rotZ += bone.rotZ; - - this.scaleX += bone.scaleX; - this.scaleY += bone.scaleY; - this.scaleZ += bone.scaleZ; - - this.bend += bone.bend; + this.position.add(bone.position); + this.rotation.add(bone.rotation); + this.scale.add(bone.scale); return this; } public PlayerAnimBone applyOtherBone(PlayerAnimBone bone) { - this.positionX += bone.positionX; - this.positionY += bone.positionY; - this.positionZ += bone.positionZ; - - this.rotX += bone.rotX; - this.rotY += bone.rotY; - this.rotZ += bone.rotZ; - - this.scaleX *= bone.scaleX; - this.scaleY *= bone.scaleY; - this.scaleZ *= bone.scaleZ; - - this.bend += bone.bend; - - return this; - } - - public PlayerAnimBone addPos(float value) { - return addPos(value, value, value); - } - - public PlayerAnimBone mulPos(float value) { - return mulPos(value, value, value); - } - - public PlayerAnimBone divPos(float value) { - return divPos(value, value, value); - } - - public PlayerAnimBone addRot(float value) { - return addRot(value, value, value); - } - - public PlayerAnimBone mulRot(float value) { - return mulRot(value, value, value); - } - - public PlayerAnimBone divRot(float value) { - return divRot(value, value, value); - } - - public PlayerAnimBone addScale(float value) { - return addScale(value, value, value); - } - - public PlayerAnimBone mulScale(float value) { - return mulScale(value, value, value); - } - - public PlayerAnimBone divScale(float value) { - return divScale(value, value, value); - } - - public PlayerAnimBone addPos(float x, float y, float z) { - this.positionX += x; - this.positionY += y; - this.positionZ += z; - - return this; - } - - public PlayerAnimBone addRot(float x, float y, float z) { - this.rotX += x; - this.rotY += y; - this.rotZ += z; + this.position.add(bone.position); + this.rotation.add(bone.rotation); + this.scale.mul(bone.scale); return this; } - public PlayerAnimBone addScale(float x, float y, float z) { - this.scaleX += x; - this.scaleY += y; - this.scaleZ += z; - - return this; - } - - public PlayerAnimBone mulPos(float x, float y, float z) { - this.positionX *= x; - this.positionY *= y; - this.positionZ *= z; - return this; - } - - public PlayerAnimBone mulRot(float x, float y, float z) { - this.rotX *= x; - this.rotY *= y; - this.rotZ *= z; - return this; - } - - public PlayerAnimBone mulScale(float x, float y, float z) { - this.scaleX *= x; - this.scaleY *= y; - this.scaleZ *= z; - return this; - } - - public PlayerAnimBone divPos(float x, float y, float z) { - this.positionX /= x; - this.positionY /= y; - this.positionZ /= z; - return this; - } - - public PlayerAnimBone divRot(float x, float y, float z) { - this.rotX /= x; - this.rotY /= y; - this.rotZ /= z; - return this; - } - - public PlayerAnimBone divScale(float x, float y, float z) { - this.scaleX /= x; - this.scaleY /= y; - this.scaleZ /= z; - return this; - } - public PlayerAnimBone copyOtherBone(PlayerAnimBone bone) { - this.positionX = bone.positionX; - this.positionY = bone.positionY; - this.positionZ = bone.positionZ; - - this.rotX = bone.rotX; - this.rotY = bone.rotY; - this.rotZ = bone.rotZ; + this.position.set(bone.position); + this.rotation.set(bone.rotation); + this.scale.set(bone.scale); - this.scaleX = bone.scaleX; - this.scaleY = bone.scaleY; - this.scaleZ = bone.scaleZ; - - this.bend = bone.bend; return this; } public PlayerAnimBone copyOtherBoneIfNotDisabled(PlayerAnimBone bone) { - if (bone instanceof IBoneEnabled advancedBone) { - if (advancedBone.isPositionXEnabled()) - this.positionX = bone.positionX; - if (advancedBone.isPositionYEnabled()) - this.positionY = bone.positionY; - if (advancedBone.isPositionZEnabled()) - this.positionZ = bone.positionZ; - - if (advancedBone.isRotXEnabled()) - this.rotX = bone.rotX; - if (advancedBone.isRotYEnabled()) - this.rotY = bone.rotY; - if (advancedBone.isRotZEnabled()) - this.rotZ = bone.rotZ; - - if (advancedBone.isScaleXEnabled()) - this.scaleX = bone.scaleX; - if (advancedBone.isScaleYEnabled()) - this.scaleY = bone.scaleY; - if (advancedBone.isScaleZEnabled()) - this.scaleZ = bone.scaleZ; - - if (advancedBone.isBendEnabled()) - this.bend = bone.bend; + if (bone instanceof ToggleablePlayerAnimBone toggleableBone) { + if (toggleableBone.isPositionXEnabled()) + this.position.x = bone.position.x; + if (toggleableBone.isPositionYEnabled()) + this.position.y = bone.position.y; + if (toggleableBone.isPositionZEnabled()) + this.position.z = bone.position.z; + + if (toggleableBone.isRotXEnabled()) + this.rotation.x = bone.rotation.x; + if (toggleableBone.isRotYEnabled()) + this.rotation.y = bone.rotation.y; + if (toggleableBone.isRotZEnabled()) + this.rotation.z = bone.rotation.z; + + if (toggleableBone.isScaleXEnabled()) + this.scale.x = bone.scale.x; + if (toggleableBone.isScaleYEnabled()) + this.scale.y = bone.scale.y; + if (toggleableBone.isScaleZEnabled()) + this.scale.z = bone.scale.z; return this; } @@ -378,34 +109,29 @@ public PlayerAnimBone copyOtherBoneIfNotDisabled(PlayerAnimBone bone) { } @ApiStatus.Internal - public PlayerAnimBone beginOrEndTickLerp(AdvancedPlayerAnimBone bone, float animTime, Animation animation) { + public void beginOrEndTickLerp(AdvancedPlayerAnimBone bone, float animTime, Animation animation) { if (bone.positionXEnabled) - this.positionX = beginOrEndTickLerp(positionX, bone.positionX, bone.positionXTransitionLength, animTime, animation, TransformType.POSITION, Axis.X); + this.position.x = beginOrEndTickLerp(position.x, bone.position.x, bone.positionXTransitionLength, animTime, animation, TransformType.POSITION, Axis.X); if (bone.positionYEnabled) - this.positionY = beginOrEndTickLerp(positionY, bone.positionY, bone.positionYTransitionLength, animTime, animation, TransformType.POSITION, Axis.Y); + this.position.y = beginOrEndTickLerp(position.y, bone.position.y, bone.positionYTransitionLength, animTime, animation, TransformType.POSITION, Axis.Y); if (bone.positionZEnabled) - this.positionZ = beginOrEndTickLerp(positionZ, bone.positionZ, bone.positionZTransitionLength, animTime, animation, TransformType.POSITION, Axis.Z); + this.position.z = beginOrEndTickLerp(position.z, bone.position.z, bone.positionZTransitionLength, animTime, animation, TransformType.POSITION, Axis.Z); if (bone.rotXEnabled) - this.rotX = beginOrEndTickLerp(rotX, bone.rotX, bone.rotXTransitionLength, animTime, animation, TransformType.ROTATION, Axis.X); + this.rotation.z = beginOrEndTickLerp(rotation.x, bone.rotation.x, bone.rotXTransitionLength, animTime, animation, TransformType.ROTATION, Axis.X); if (bone.rotYEnabled) - this.rotY = beginOrEndTickLerp(rotY, bone.rotY, bone.rotYTransitionLength, animTime, animation, TransformType.ROTATION, Axis.Y); + this.rotation.y = beginOrEndTickLerp(rotation.y, bone.rotation.y, bone.rotYTransitionLength, animTime, animation, TransformType.ROTATION, Axis.Y); if (bone.rotZEnabled) - this.rotZ = beginOrEndTickLerp(rotZ, bone.rotZ, bone.rotZTransitionLength, animTime, animation, TransformType.ROTATION, Axis.Z); + this.rotation.z = beginOrEndTickLerp(rotation.z, bone.rotation.z, bone.rotZTransitionLength, animTime, animation, TransformType.ROTATION, Axis.Z); if (bone.scaleXEnabled) - this.scaleX = beginOrEndTickLerp(scaleX, bone.scaleX, bone.scaleXTransitionLength, animTime, animation, TransformType.SCALE, Axis.X); + this.scale.x = beginOrEndTickLerp(scale.x, bone.scale.x, bone.scaleXTransitionLength, animTime, animation, TransformType.SCALE, Axis.X); if (bone.scaleYEnabled) - this.scaleY = beginOrEndTickLerp(scaleY, bone.scaleY, bone.scaleYTransitionLength, animTime, animation, TransformType.SCALE, Axis.Y); + this.scale.y = beginOrEndTickLerp(scale.y, bone.scale.y, bone.scaleYTransitionLength, animTime, animation, TransformType.SCALE, Axis.Y); if (bone.scaleZEnabled) - this.scaleZ = beginOrEndTickLerp(scaleZ, bone.scaleZ, bone.scaleZTransitionLength, animTime, animation, TransformType.SCALE, Axis.Z); - - if (bone.bendEnabled) - this.bend = beginOrEndTickLerp(bend, bone.bend, bone.bendTransitionLength, animTime, animation, TransformType.BEND, Axis.Y); - - return this; + this.scale.z = beginOrEndTickLerp(scale.z, bone.scale.z, bone.scaleZTransitionLength, animTime, animation, TransformType.SCALE, Axis.Z); } - + private float beginOrEndTickLerp(float startValue, float endValue, Float transitionLength, float animTime, Animation animation, TransformType type, Axis axis) { EasingType easingType = EasingType.EASE_IN_OUT_SINE; if (animation != null) { @@ -439,54 +165,7 @@ private float beginOrEndTickLerp(float startValue, float endValue, Float transit return easingType.apply(startValue, endValue, animTime / transitionLength); } - public void copySnapshot(BoneSnapshot snapshot) { - this.positionX = snapshot.getOffsetX(); - this.positionY = snapshot.getOffsetY(); - this.positionZ = snapshot.getOffsetZ(); - - this.rotX = snapshot.getRotX(); - this.rotY = snapshot.getRotY(); - this.rotZ = snapshot.getRotZ(); - - this.scaleX = snapshot.getScaleX(); - this.scaleY = snapshot.getScaleY(); - this.scaleZ = snapshot.getScaleZ(); - - this.bend = snapshot.getBend(); - } - - public PlayerAnimBone copySnapshotSafe(AdvancedBoneSnapshot snapshot) { - if (snapshot.positionXEnabled) - this.positionX = snapshot.getOffsetX(); - if (snapshot.positionYEnabled) - this.positionY = snapshot.getOffsetY(); - if (snapshot.positionZEnabled) - this.positionZ = snapshot.getOffsetZ(); - - if (snapshot.rotXEnabled) - this.rotX = snapshot.getRotX(); - if (snapshot.rotYEnabled) - this.rotY = snapshot.getRotY(); - if (snapshot.rotZEnabled) - this.rotZ = snapshot.getRotZ(); - - if (snapshot.scaleXEnabled) - this.scaleX = snapshot.getScaleX(); - if (snapshot.scaleYEnabled) - this.scaleY = snapshot.getScaleY(); - if (snapshot.scaleZEnabled) - this.scaleZ = snapshot.getScaleZ(); - - if (snapshot.bendEnabled) - this.bend = snapshot.getBend(); - - return this; - } - - public BoneSnapshot saveSnapshot() { - return new BoneSnapshot(this); - } - + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -497,6 +176,7 @@ public boolean equals(Object obj) { return hashCode() == obj.hashCode(); } + @Override public int hashCode() { return getName().hashCode(); } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/bones/ToggleablePlayerAnimBone.java b/core/src/main/java/com/zigythebird/playeranimcore/bones/ToggleablePlayerAnimBone.java new file mode 100644 index 00000000..e10b03bc --- /dev/null +++ b/core/src/main/java/com/zigythebird/playeranimcore/bones/ToggleablePlayerAnimBone.java @@ -0,0 +1,99 @@ +package com.zigythebird.playeranimcore.bones; + +public class ToggleablePlayerAnimBone extends PlayerAnimBone { + public boolean scaleXEnabled = true; + public boolean scaleYEnabled = true; + public boolean scaleZEnabled = true; + + public boolean positionXEnabled = true; + public boolean positionYEnabled = true; + public boolean positionZEnabled = true; + + public boolean rotXEnabled = true; + public boolean rotYEnabled = true; + public boolean rotZEnabled = true; + + public boolean bendEnabled = true; + + public ToggleablePlayerAnimBone(String name) { + super(name); + } + + public ToggleablePlayerAnimBone(PlayerAnimBone bone) { + super(bone); + + if (bone instanceof ToggleablePlayerAnimBone boneEnabled) { + scaleXEnabled = boneEnabled.isScaleXEnabled(); + scaleYEnabled = boneEnabled.isScaleYEnabled(); + scaleZEnabled = boneEnabled.isScaleZEnabled(); + + positionXEnabled = boneEnabled.isPositionXEnabled(); + positionYEnabled = boneEnabled.isPositionYEnabled(); + positionZEnabled = boneEnabled.isPositionZEnabled(); + + rotXEnabled = boneEnabled.isRotXEnabled(); + rotYEnabled = boneEnabled.isRotYEnabled(); + rotZEnabled = boneEnabled.isRotZEnabled(); + + bendEnabled = boneEnabled.isBendEnabled(); + } + } + + public void setPositionEnabled(boolean enabled) { + this.positionXEnabled = enabled; + this.positionYEnabled = enabled; + this.positionZEnabled = enabled; + } + + public void setRotEnabled(boolean enabled) { + this.rotXEnabled = enabled; + this.rotYEnabled = enabled; + this.rotZEnabled = enabled; + } + + public void setScaleEnabled(boolean enabled) { + this.scaleXEnabled = enabled; + this.scaleYEnabled = enabled; + this.scaleZEnabled = enabled; + } + + public boolean isScaleXEnabled() { + return scaleXEnabled; + } + + public boolean isScaleYEnabled() { + return scaleYEnabled; + } + + public boolean isScaleZEnabled() { + return scaleZEnabled; + } + + public boolean isPositionXEnabled() { + return positionXEnabled; + } + + public boolean isPositionYEnabled() { + return positionYEnabled; + } + + public boolean isPositionZEnabled() { + return positionZEnabled; + } + + public boolean isRotXEnabled() { + return rotXEnabled; + } + + public boolean isRotYEnabled() { + return rotYEnabled; + } + + public boolean isRotZEnabled() { + return rotZEnabled; + } + + public boolean isBendEnabled() { + return bendEnabled; + } +} diff --git a/core/src/main/java/com/zigythebird/playeranimcore/easing/BezierEasing.java b/core/src/main/java/com/zigythebird/playeranimcore/easing/BezierEasing.java index c013bb6f..53baed14 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/easing/BezierEasing.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/easing/BezierEasing.java @@ -1,6 +1,5 @@ package com.zigythebird.playeranimcore.easing; -import com.zigythebird.playeranimcore.animation.keyframe.AnimationPoint; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; @@ -20,10 +19,12 @@ public Float2FloatFunction buildTransformer(@Nullable Float value) { abstract boolean isEasingBefore(); @Override - public float apply(MochaEngine env, AnimationPoint animationPoint, @Nullable Float easingValue, float lerpValue) { - List> easingArgs = animationPoint.easingArgs(); - if (easingArgs.isEmpty()) - return MochaMath.lerp(animationPoint.animationStartValue(), animationPoint.animationEndValue(), buildTransformer(easingValue).apply(lerpValue)); + public float apply(MochaEngine env, float startValue, float endValue, float transitionLength, float lerpValue, @Nullable List> easingArgs) { + if (lerpValue >= 1) return endValue; + if (Float.isNaN(lerpValue)) return startValue; + + if (easingArgs == null || easingArgs.isEmpty()) + return MochaMath.lerp(startValue, endValue, buildTransformer(null).apply(lerpValue)); float rightValue = isEasingBefore() ? 0 : env.eval(easingArgs.getFirst()); float rightTime = isEasingBefore() ? 0.1f : env.eval(easingArgs.get(1)); @@ -38,16 +39,16 @@ public float apply(MochaEngine env, AnimationPoint animationPoint, @Nullable leftValue = (float) Math.toRadians(leftValue); rightValue = (float) Math.toRadians(rightValue); - float gapTime = animationPoint.transitionLength()/20; + float gapTime = transitionLength / 20; float time_handle_before = Math.clamp(rightTime, 0, gapTime); float time_handle_after = Math.clamp(leftTime, -gapTime, 0); CubicBezierCurve curve = new CubicBezierCurve( - new Vector2f(0, animationPoint.animationStartValue()), - new Vector2f(time_handle_before, animationPoint.animationStartValue() + rightValue), - new Vector2f(time_handle_after + gapTime, animationPoint.animationEndValue() + leftValue), - new Vector2f(gapTime, animationPoint.animationEndValue())); + new Vector2f(0, startValue), + new Vector2f(time_handle_before, startValue + rightValue), + new Vector2f(time_handle_after + gapTime, endValue + leftValue), + new Vector2f(gapTime, endValue)); float time = gapTime * lerpValue; List points = curve.getPoints(200); diff --git a/core/src/main/java/com/zigythebird/playeranimcore/easing/CatmullRomEasing.java b/core/src/main/java/com/zigythebird/playeranimcore/easing/CatmullRomEasing.java index 12e5ba72..5fb5b1f5 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/easing/CatmullRomEasing.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/easing/CatmullRomEasing.java @@ -1,6 +1,5 @@ package com.zigythebird.playeranimcore.easing; -import com.zigythebird.playeranimcore.animation.keyframe.AnimationPoint; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import org.jetbrains.annotations.Nullable; import team.unnamed.mocha.MochaEngine; @@ -34,15 +33,13 @@ public Float2FloatFunction buildTransformer(Float value) { } @Override - public float apply(MochaEngine env, AnimationPoint animationPoint, @Nullable Float easingValue, float lerpValue) { - if (animationPoint.currentTick() >= animationPoint.transitionLength()) - return animationPoint.animationEndValue(); + public float apply(MochaEngine env, float startValue, float endValue, float transitionLength, float lerpValue, @Nullable List> easingArgs) { + if (lerpValue >= 1) return endValue; + if (Float.isNaN(lerpValue)) return startValue; - List> easingArgs = animationPoint.easingArgs(); + if (easingArgs == null || easingArgs.size() < 2) + return MochaMath.lerp(startValue, endValue, buildTransformer(null).apply(lerpValue)); - if (easingArgs.size() < 2) - return MochaMath.lerp(animationPoint.animationStartValue(), animationPoint.animationEndValue(), buildTransformer(easingValue).apply(lerpValue)); - - return getPointOnSpline(lerpValue, env.eval(easingArgs.get(0)), animationPoint.animationStartValue(), animationPoint.animationEndValue(), env.eval(easingArgs.get(1))); + return getPointOnSpline(lerpValue, env.eval(easingArgs.get(0)), startValue, endValue, env.eval(easingArgs.get(1))); } } diff --git a/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingType.java b/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingType.java index 0998ad52..ba422400 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingType.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingType.java @@ -2,14 +2,15 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; -import com.zigythebird.playeranimcore.animation.keyframe.AnimationPoint; import com.zigythebird.playeranimcore.animation.keyframe.Keyframe; import com.zigythebird.playeranimcore.math.MathHelper; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import org.jetbrains.annotations.Nullable; import team.unnamed.mocha.MochaEngine; +import team.unnamed.mocha.parser.ast.Expression; import team.unnamed.mocha.runtime.standard.MochaMath; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -98,23 +99,13 @@ public Float2FloatFunction buildTransformer(@Nullable Float value) { return this.transformer.buildTransformer(value); } - public static float lerpWithOverride(MochaEngine env, AnimationPoint animationPoint, @Nullable EasingType override) { - EasingType easingType = override; - - if (override == null) - easingType = animationPoint.easingType(); - - return easingType.apply(env, animationPoint); - } - - @Override - public float apply(MochaEngine env, AnimationPoint animationPoint) { - return this.transformer.apply(env, animationPoint); + public float apply(MochaEngine env, float startValue, float endValue, float transitionLength, float lerpValue, @Nullable List> easingArgs) { + return this.transformer.apply(env, startValue, endValue, transitionLength, lerpValue, easingArgs); } - @Override - public float apply(MochaEngine env, AnimationPoint animationPoint, @Nullable Float easingValue, float lerpValue) { - return this.transformer.apply(env, animationPoint, easingValue, lerpValue); + public static float lerpWithOverride(MochaEngine env, float startValue, float endValue, float transitionLength, float lerpValue, @Nullable List> easingArgs, EasingType easingType, @Nullable EasingType override) { + EasingType easing = override != null ? override : easingType; + return easing.apply(env, startValue, endValue, transitionLength, lerpValue, easingArgs); } @Override diff --git a/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingTypeTransformer.java b/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingTypeTransformer.java index 9dbeb659..29390b60 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingTypeTransformer.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/easing/EasingTypeTransformer.java @@ -1,32 +1,27 @@ package com.zigythebird.playeranimcore.easing; -import com.zigythebird.playeranimcore.animation.keyframe.AnimationPoint; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import org.jetbrains.annotations.Nullable; import team.unnamed.mocha.MochaEngine; +import team.unnamed.mocha.parser.ast.Expression; import team.unnamed.mocha.runtime.standard.MochaMath; import team.unnamed.mocha.runtime.value.ObjectValue; +import java.util.List; + @FunctionalInterface public interface EasingTypeTransformer extends ObjectValue.FloatFunction3 { Float2FloatFunction buildTransformer(@Nullable Float value); - default float apply(MochaEngine env, AnimationPoint animationPoint) { - Float easingVariable = null; - - if (animationPoint.easingArgs() != null && !animationPoint.easingArgs().isEmpty()) - easingVariable = env.eval(animationPoint.easingArgs().getFirst()); + default float apply(MochaEngine env, float startValue, float endValue, float transitionLength, float lerpValue, @Nullable List> easingArgs) { + if (lerpValue >= 1) return endValue; + if (Float.isNaN(lerpValue)) return startValue; - return apply(env, animationPoint, easingVariable, animationPoint.currentTick() / animationPoint.transitionLength()); - } - - default float apply(MochaEngine env, AnimationPoint animationPoint, @Nullable Float easingValue, float lerpValue) { - if (lerpValue >= 1) - return animationPoint.animationEndValue(); - if (Float.isNaN(lerpValue)) - return animationPoint.animationStartValue(); - - return apply(animationPoint.animationStartValue(), animationPoint.animationEndValue(), easingValue, lerpValue); + Float easingVariable = null; + if (easingArgs != null && !easingArgs.isEmpty()) { + easingVariable = env.eval(easingArgs.getFirst()); + } + return apply(startValue, endValue, easingVariable, lerpValue); } @Override diff --git a/core/src/main/java/com/zigythebird/playeranimcore/util/MatrixUtil.java b/core/src/main/java/com/zigythebird/playeranimcore/util/MatrixUtil.java index 561cf152..fd9bff48 100644 --- a/core/src/main/java/com/zigythebird/playeranimcore/util/MatrixUtil.java +++ b/core/src/main/java/com/zigythebird/playeranimcore/util/MatrixUtil.java @@ -14,16 +14,16 @@ */ public class MatrixUtil { public static void translateMatrixForBone(Matrix4f matrix, PlayerAnimBone bone) { - matrix.translate(-bone.getPosX(), bone.getPosY(), -bone.getPosZ()); + matrix.translate(-bone.position.x, bone.position.y, -bone.position.z); } public static void rotateMatrixAroundBone(Matrix4f matrix, PlayerAnimBone bone) { - if (bone.getRotZ() != 0 || bone.getRotY() != 0 || bone.getRotX() != 0) - matrix.rotateZ(bone.getRotZ()).rotateY(bone.getRotY()).rotateX(bone.getRotX()); + if (bone.rotation.z != 0 || bone.rotation.y != 0 || bone.rotation.x != 0) + matrix.rotateZYX(bone.rotation); } public static void scaleMatrixForBone(Matrix4f matrix, PlayerAnimBone bone) { - matrix.scale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + matrix.scale(bone.scale.x, bone.scale.y, bone.scale.z); } public static void translateToPivotPoint(Matrix4f matrix, Vec3f pivot) { @@ -53,14 +53,9 @@ public static void applyParentsToChild(PlayerAnimBone child, Iterable Date: Thu, 26 Feb 2026 23:45:54 +0700 Subject: [PATCH 22/28] snap10 --- build.gradle | 4 ++-- gradle.properties | 6 +++--- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 4fc778b4..36e81dd6 100644 --- a/build.gradle +++ b/build.gradle @@ -3,8 +3,8 @@ import org.apache.commons.lang3.StringUtils plugins { id "org.redlance.dima_dencep.gradle.PublishToDiscord" version "1.0.6" - id "xyz.wagyourtail.unimined" version "1.4.2+redlance.1" apply false - id "com.gradleup.shadow" version "9.3.0" apply false + id "xyz.wagyourtail.unimined" version "1.4.2+redlance.2" apply false + id "com.gradleup.shadow" version "9.3.1" apply false } allprojects { diff --git a/gradle.properties b/gradle.properties index b78f4f99..13f4da82 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,10 +8,10 @@ maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib # Minecraft properties -minecraft_version = 26.1-snapshot-9 +minecraft_version = 26.1-snapshot-10 # Dependencies fabric_loader_version = 0.18.4 -fabric_api_version = 0.143.5+26.1 -neoforge_version = 26.1.0.0-alpha.0+snapshot-9.20260220.232516 +fabric_api_version = 0.143.7+26.1 +neoforge_version = 26.1.0.0-alpha.0+snapshot-10.20260225.011214 molang_version = 5.0.0 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 23449a2b..37f78a6a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From e994acaa5ba1cfa61aa632ee8640a63492a984fe Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Fri, 27 Feb 2026 00:46:13 +0700 Subject: [PATCH 23/28] Update PlayerAnimLibMod.java --- .../java/com/zigythebird/playeranim/PlayerAnimLibMod.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibMod.java b/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibMod.java index 7adaf238..ec4ce1d3 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibMod.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibMod.java @@ -19,11 +19,9 @@ public static Identifier id(String name) { protected void init() { PlayerAnimationFactory.ANIMATION_DATA_FACTORY.registerFactory(ANIMATION_LAYER_ID, 1000, - player -> new PlayerAnimationController(player, - (controller, state, animSetter) -> PlayState.STOP - ) + player -> new PlayerAnimationController(player, (_, _, _) -> PlayState.STOP) ); - MolangEvent.MOLANG_EVENT.register((controller, engine, queryBinding) -> + MolangEvent.MOLANG_EVENT.register((_, _, queryBinding) -> MolangQueries.setDefaultQueryValues(queryBinding) ); CustomKeyFrameEvents.SOUND_KEYFRAME_EVENT.register(new AutoPlayingSoundKeyframeHandler()); From 57346af1fdd2b770555513fcfc95e00eafaebb78 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Fri, 27 Feb 2026 01:35:36 +0700 Subject: [PATCH 24/28] wtf --- .../main/java/com/zigythebird/playeranim/util/RenderUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/util/RenderUtil.java b/minecraft/src/main/java/com/zigythebird/playeranim/util/RenderUtil.java index b07a1b19..913c4456 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/util/RenderUtil.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/util/RenderUtil.java @@ -35,7 +35,7 @@ public static void translatePartToCape(ModelPart part, PlayerAnimBone bone, Part */ public static void translatePartToBone(ModelPart part, PlayerAnimBone bone, PartPose initialPose) { part.x = bone.position.x + initialPose.x(); - part.y = -(bone.position.y + initialPose.y()); + part.y = -bone.position.y + initialPose.y(); part.z = bone.position.z + initialPose.z(); part.xRot = bone.rotation.x; From 24b15b0679713e3764ca096719f7c54f97d24f2a Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Tue, 3 Mar 2026 00:37:30 +0700 Subject: [PATCH 25/28] ct --- .gitignore | 1 - minecraft/build.gradle | 2 +- .../main/resources/player_animation_library.classtweaker | 6 +++--- .../src/neoforge/resources/META-INF/accesstransformer.cfg | 6 ++++++ 4 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 minecraft/src/neoforge/resources/META-INF/accesstransformer.cfg diff --git a/.gitignore b/.gitignore index fadb18ce..9fe93e04 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,4 @@ classes/ *.launch *.log .DS_Store -/minecraft/src/neoforge/resources/META-INF/accesstransformer.cfg /minecraft/src/main/resources/assets/player_animation_library/player_animations/dont_include diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 99417a9b..67888aff 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -38,7 +38,7 @@ unimined.minecraft(sourceSets.neoforge) { loader("net.neoforged:neoforge:$rootProject.neoforge_version:universal") mixinConfig("player_animation_library.mixins.json") - accessTransformer aw2at(file("src/main/resources/player_animation_library.classtweaker")) + // accessTransformer aw2at(file("src/main/resources/player_animation_library.classtweaker")) } defaultRemapJar = true } diff --git a/minecraft/src/main/resources/player_animation_library.classtweaker b/minecraft/src/main/resources/player_animation_library.classtweaker index b82a5ebb..ae46acf1 100644 --- a/minecraft/src/main/resources/player_animation_library.classtweaker +++ b/minecraft/src/main/resources/player_animation_library.classtweaker @@ -1,7 +1,7 @@ -accessWidener v2 official +classTweaker v1 official extendable class net/minecraft/client/model/geom/ModelPart accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; -# inject-interface com/zigythebird/playeranim/accessors/IAnimatedAvatar net/minecraft/world/entity/Avatar -# inject-interface com/zigythebird/playeranim/accessors/IAvatarAnimationState net/minecraft/client/renderer/entity/state/AvatarRenderState +inject-interface net/minecraft/world/entity/Avatar com/zigythebird/playeranim/accessors/IAnimatedAvatar +inject-interface net/minecraft/client/renderer/entity/state/AvatarRenderState com/zigythebird/playeranim/accessors/IAvatarAnimationState diff --git a/minecraft/src/neoforge/resources/META-INF/accesstransformer.cfg b/minecraft/src/neoforge/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..d3da0041 --- /dev/null +++ b/minecraft/src/neoforge/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,6 @@ +public-f net.minecraft.client.model.geom.ModelPart +public net.minecraft.client.renderer.LevelRenderer levelRenderState +public net.minecraft.client.renderer.entity.layers.RenderLayer renderer +public net.minecraft.client.renderer.entity.LivingEntityRenderer layers +public net.minecraft.client.renderer.block.model.BlockModel GSON +public net.minecraft.client.renderer.texture.TextureAtlasSprite (Lnet/minecraft/resources/Identifier;Lnet/minecraft/client/renderer/texture/SpriteContents;IIIII)V \ No newline at end of file From fe607a34c1f2fa1b024a429368900601395d3b4b Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Tue, 3 Mar 2026 21:08:58 +0700 Subject: [PATCH 26/28] Update player_animation_library.classtweaker --- .../src/main/resources/player_animation_library.classtweaker | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/minecraft/src/main/resources/player_animation_library.classtweaker b/minecraft/src/main/resources/player_animation_library.classtweaker index ae46acf1..ecd9e71f 100644 --- a/minecraft/src/main/resources/player_animation_library.classtweaker +++ b/minecraft/src/main/resources/player_animation_library.classtweaker @@ -3,5 +3,5 @@ extendable class net/minecraft/client/model/geom/ModelPart accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; -inject-interface net/minecraft/world/entity/Avatar com/zigythebird/playeranim/accessors/IAnimatedAvatar -inject-interface net/minecraft/client/renderer/entity/state/AvatarRenderState com/zigythebird/playeranim/accessors/IAvatarAnimationState +transitive-inject-interface net/minecraft/world/entity/Avatar com/zigythebird/playeranim/accessors/IAnimatedAvatar +transitive-inject-interface net/minecraft/client/renderer/entity/state/AvatarRenderState com/zigythebird/playeranim/accessors/IAvatarAnimationState From bd7158c4370d8601e6c5cf74f2096af63c9ae785 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sat, 7 Mar 2026 21:14:27 +0700 Subject: [PATCH 27/28] port to 26.1 snap 11 --- build.gradle | 4 ++-- gradle.properties | 6 +++--- gradle/wrapper/gradle-wrapper.jar | Bin 45633 -> 46175 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- .../playeranim/mixin/AvatarRendererMixin.java | 1 - .../mixin/LivingEntityRendererMixin.java | 8 ++++---- .../mixin/firstPerson/LevelRendererMixin.java | 2 +- .../LivingEntityRendererMixin.java | 2 +- .../player_animation_library.classtweaker | 2 +- 9 files changed, 13 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 36e81dd6..6ee88b91 100644 --- a/build.gradle +++ b/build.gradle @@ -25,8 +25,8 @@ allprojects { } } maven { - name = "Maven for PR #2975" // https://github.com/neoforged/NeoForge/pull/2975 - url = uri("https://prmaven.neoforged.net/NeoForge/pr2975") + name = "Maven for PR #2988" // https://github.com/neoforged/NeoForge/pull/2988 + url = uri("https://prmaven.neoforged.net/NeoForge/pr2988") content { includeModule("net.neoforged", "neoforge") includeModule("net.neoforged", "testframework") diff --git a/gradle.properties b/gradle.properties index 13f4da82..f703cfd2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,10 +8,10 @@ maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib # Minecraft properties -minecraft_version = 26.1-snapshot-10 +minecraft_version = 26.1-snapshot-11 # Dependencies fabric_loader_version = 0.18.4 -fabric_api_version = 0.143.7+26.1 -neoforge_version = 26.1.0.0-alpha.0+snapshot-10.20260225.011214 +fabric_api_version = 0.143.11+26.1 +neoforge_version = 26.1.0.0-alpha.0+snapshot-11.20260304.010323 molang_version = 5.0.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f8e1ee3125fe0768e9a76ee977ac089eb657005e..61285a659d17295f1de7c53e24fdf13ad755c379 100644 GIT binary patch delta 37058 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 NNswbwE82Y!{{uvZmpcFe delta 36446 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 JWd7DQ`9Hc?h(rJY diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f78a6a..dbc3ce4a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/AvatarRendererMixin.java b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/AvatarRendererMixin.java index cd799c28..759c796a 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/AvatarRendererMixin.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/AvatarRendererMixin.java @@ -27,7 +27,6 @@ import com.zigythebird.playeranim.accessors.IAnimatedAvatar; import com.zigythebird.playeranim.accessors.IAvatarAnimationState; import com.zigythebird.playeranim.animation.AvatarAnimManager; -import net.minecraft.client.Minecraft; import net.minecraft.client.model.player.PlayerModel; import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.renderer.entity.EntityRendererProvider; diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java index 950f5cae..a8001577 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/LivingEntityRendererMixin.java @@ -31,7 +31,7 @@ import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; -import net.minecraft.client.renderer.state.CameraRenderState; +import net.minecraft.client.renderer.state.level.CameraRenderState; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -39,9 +39,9 @@ @Mixin(LivingEntityRenderer.class) public class LivingEntityRendererMixin { - @Inject(method = "submit(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/LivingEntityRenderer;scale(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;)V")) - private void doTranslations(S livingEntityRenderState, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState cameraRenderState, CallbackInfo ci) { - if (livingEntityRenderState instanceof IAvatarAnimationState avatarRenderState) { + @Inject(method = "submit(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/level/CameraRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/LivingEntityRenderer;scale(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;)V")) + private void doTranslations(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera, CallbackInfo ci) { + if (state instanceof IAvatarAnimationState avatarRenderState) { var animationPlayer = avatarRenderState.playerAnimLib$getAnimManager(); if (animationPlayer != null && animationPlayer.isActive()) { avatarRenderState.playerAnimLib$getAnimManager().handleAnimations(animationPlayer.getTickDelta(), false, avatarRenderState.playerAnimLib$isFirstPersonPass()); diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LevelRendererMixin.java b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LevelRendererMixin.java index caa415af..1046b232 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LevelRendererMixin.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LevelRendererMixin.java @@ -35,7 +35,7 @@ import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.entity.state.EntityRenderState; -import net.minecraft.client.renderer.state.LevelRenderState; +import net.minecraft.client.renderer.state.level.LevelRenderState; import net.minecraft.world.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LivingEntityRendererMixin.java b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LivingEntityRendererMixin.java index 2fa6463e..b47c5ad4 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LivingEntityRendererMixin.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/mixin/firstPerson/LivingEntityRendererMixin.java @@ -39,7 +39,7 @@ @Mixin(value = LivingEntityRenderer.class, priority = 2000) public class LivingEntityRendererMixin { @WrapWithCondition( - method = "submit(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V", + method = "submit(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/level/CameraRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/RenderLayer;submit(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/client/renderer/entity/state/EntityRenderState;FF)V")) private boolean filterLayers(RenderLayer layer, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int i, EntityRenderState renderState, float v, float vq) { if (renderState instanceof IAvatarAnimationState state && state.playerAnimLib$isFirstPersonPass()) { diff --git a/minecraft/src/main/resources/player_animation_library.classtweaker b/minecraft/src/main/resources/player_animation_library.classtweaker index ecd9e71f..5b4c1de9 100644 --- a/minecraft/src/main/resources/player_animation_library.classtweaker +++ b/minecraft/src/main/resources/player_animation_library.classtweaker @@ -1,6 +1,6 @@ classTweaker v1 official extendable class net/minecraft/client/model/geom/ModelPart -accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/LevelRenderState; +accessible field net/minecraft/client/renderer/LevelRenderer levelRenderState Lnet/minecraft/client/renderer/state/level/LevelRenderState; accessible field net/minecraft/client/renderer/entity/layers/RenderLayer renderer Lnet/minecraft/client/renderer/entity/RenderLayerParent; accessible field net/minecraft/client/renderer/entity/LivingEntityRenderer layers Ljava/util/List; transitive-inject-interface net/minecraft/world/entity/Avatar com/zigythebird/playeranim/accessors/IAnimatedAvatar From 3ff28ca3d28b49511324cc34603fb9c66f2b359d Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Sun, 8 Mar 2026 03:11:55 +0700 Subject: [PATCH 28/28] Fix deps --- minecraft/build.gradle | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 67888aff..966051bc 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -62,12 +62,11 @@ dependencies { shadow(project(path: ":core")) { transitive = false } // Common - api(platformInclude("com.zigythebird:mochafloats:$rootProject.molang_version") { + platformInclude("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false - }) + } // Fabric - fabricImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" fabricImplementation fabricApi.fabricModule("fabric-command-api-v2", rootProject.fabric_api_version) fabricImplementation fabricApi.fabricModule("fabric-resource-loader-v1", rootProject.fabric_api_version) @@ -158,6 +157,17 @@ publishing { pom.withXml { def deps = asNode().appendNode("dependencies") + + // Adds fabric api to deps + configurations.fabricImplementation.dependencies.each { + def d = deps.appendNode("dependency") + + d.appendNode("groupId", it.group) + d.appendNode('artifactId', it instanceof ProjectDependency ? project(it.path).base.archivesName.get() : it.name) + d.appendNode("version", it.version) + d.appendNode("scope", "compile") + } + def d = deps.appendNode("dependency") d.appendNode("groupId", project.group) d.appendNode("artifactId", "PlayerAnimationLibCommon")