From 23105ebf060c26166669f601dddd14bef38f27e2 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Fri, 6 Feb 2026 22:53:41 +0700 Subject: [PATCH 01/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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 zcmX6^V`C&-vs}csZQHhO+qRPlC+5U9H`>^?ZJQfwgS*drznnkN)qSd~s&`I*^d0`F zvqc0b{9s1P{qci@fbDj_o)SGZcGOth)FdL8OL)J_BV5J0Bg-Q#0m~a{rympvN!T0C zf*?`EI!3lL^X~80-SxBgn+G;u?F#5HaR;_dDD93ojdlBorJ;?Za5f{_E|uh#06r>^ zY+5|x5bua2nd4?pEqL{ATr-RDb>V^WUGMavPGn{?6EUfrVFqeUqtZa!Iee#Qll5`Z7ED@F=0&DnLuUlzG z21;z=*DT?UdaTs!;LD}w3u8Q@*l2p|?=Gf$}v71vIS2OcFN#*+Vg$V%{n^RTp1=nrWz$&^+rv-HGl8O`D z&J4~UF)9^WbknNUst(V88s$JJ4ml^5)M%*=S|VJ)5>*dFE(T}iZa!8{)oEK3L+=g9 zVWg@xdP($nI8`RO^*DoB{F;oy{7ebsF$cER5_M?n>N7-I;z_2)iD&P=!&C#UjcxQw z$^t-|@b3_qG~-qrv_`%GI=(%JE{aZ=kV*WmC8X4r&vt3GNE=A=vBMf!a%cJ0N>eZ{ zxUrh3%oD>7wP8%?cK3LQmQ^jJ^joB9(6SOcajnlHwx(^-h zm?aY2KWq7tXvqs#bSAfwPiy%a6{FjVKO(V06@kCl1bq zEgQX9a(z|bm-rAH?Y+I@q}ijgG?b*kS>9Btgz@Q(j(qbTyj^id40Bt@x39wW`4sSr zt5Zxdv7qO8&erf~%H0r*Oo}ivAe_m&nALj{lc|p7ZH&SXd+bTc0!h@3L8&p^Aaqn9 zciN$gum8rgxH*o=C!&6))g$8K>i~Bo-K1QBkaXq-;XwP&0z1IO;SqM&#qieXeqij6 z;&B@7N0epS&mQZ%5d#>?J)7VbxpuAT3R?Ze#k zs6$;!M3+;Qh>u8oz0c-U)*8hpUbrBJ^BuwE%_A*qD6uAmxWy%%H&DeVT%#|7{8z=p0SQ3PQj``SJ zCOR{SfrbsZfsB*2D>64ScPlJK6S!M038ub;r&nWnC2pGY+z?|P)vXhHgNIhPC|%_a z%aluo0WYGjzN@FcM`HuJTNl~(?=$Sc=~kA6M;(IE-JDLbWu_^jw(^4JrW4&_Fy zaZC}&GxUK=dKp?Ubk*=bT!{<13hMm$_N^I|PlgZrBqj$*SC9dk)a?~FG|&PV%&=m- z9j#m3b)Be#$SCZM*pP-HemT<6t1pm*$y7UJ%kJ-|jd~a@G=9cEx&nk~>zQM_FE@%m z%H2miDn$y?8Rg9=1Fl`C`DeIK2)_RA7}kE5JAfEipj5oZ2vDZg+d=bC&ryAZXRkVs zTVj&C#*M4iR!|2ZUBjq4DbAYY_+}blzLl;t^0_;NWaW-l#%5aF0xd!XO3UtF-|3vU z`g#AxmRh6iF12|?5`^iq+7asw)F8K$>%~8jbTVr}t zj~4ipd4oOt1lg|RP3M+3?*^rE1E0jwJv>_PEa9Etlv}u8dSSrHUE-u9h365> zh~HpnZz?6X`x;klw<=+pnf)@xCX-{0X>>`lt5}h9Nr-7D$!Om#q2Oh9?S0WV#5nbu zkEr8X@_&MQMT~O{!;tO6i(;{0o^g7EVoW>*$5ws$Br7^OmW1gXy`c*L;&J(mq)_hr z7XnZiC$#$G;Udj(Uf6Q13&2kohN4d#D#cHU|3i%J686=Ow0XaY*Cr*73Mg>xzRMgd-Ra^;(#gGxi+9Osx$W+ zdtcw1K*BTjTDq}oNUpU+j1<<9IVKcM1{?mnUYTvo!|X+LV`D*@8eCEzRH6!+eQr5x zW4i(#292HQ->?5VZou%CUFGMuZy-oe0husJ5r-ZCkqSo#5*vk2vf{|XrRy+)Qvbn* z&SYa2#D;V_tcLG_$Yktc$;t{VY-{4UUfH!qyS!{rSix>zbd)q&Tb=h-u(JWk|5z35 zU8eD$zGSd7QWfc$%)ZZkzUy3Z{k$9d3jmu976-4@@AfNwT-%Kx$U~|StE0yvga?K= z(`EoTA)4kyHTooMn5-RY+fzWwlB{`XEc{pEcJo=mOwV z7ciKK8^uBme0PDg^)yyd+a7!q!L*qgVkqS z1sZ>xko}h4nuL<)Ct(#(H77D05dZ-!LDBpcTPUDQUG{BhpPldA$D z;Iocs%8g;0$CrdPN>k1oM_8m2UC`Z@%t@`zE9y)2pw2ln<9dCVRh3747F{(U%NFE( z)PwdMR6Vmj;ECDP@(GN=bu|#e=|}+ug^9vAF*yPidjVsMp+zv)+VJ{A%*Wei@$Cl& zXaqN|W_+Vvxl(mzF#OkqZAAMHz8~E1BXbm@>(}5B1jX{iw)day@IcXlGUxso zC4hwRKo0pmHJ3LvgA4O{=Ts3L8~PRu50C2iM7fTIAU~*|s_m#!8_UIsNRfcva&t(R zEllPL-UR#2-bB&q#9^0gGr7^E#f(1(;&&fniGjb4=5MG7K#6=!G{D!&+wtEc@eE?< zco*G2bA|d*6o|~*zH8wL{JkafaJ|HUqA6!cZ7D05sKGJDK0RY|lm$;L zv`)Clv4ak|Nx0LX^N%Ig>i7j#vF+85h_2~OQn zn8m(~zvErL&)v97SB(HMj}of;JZYW4eeV}GK$8Y~f=W(>oTlv%W#=x@TtU>v(H#V)f+n%pHFfSQ zCIOzuwv!DmG?HZ_wR?orW2Zgaj6?(s*z}5-ku!!b}wM&Ofo8TDWxNO(Qv== z&{tJ>DBa$Ce&A9Ie&x6G`%>oot;wsc;C3R_xVGT-$1vJfDL>%s1ES~g!1z6`zD0aK z(~N5;#dD6=Yo_X(w9LZ^h%-z6G@I{4|LEeFHYM`VFG{h_4Du2Ab$65IqKXlOhukbF zjLt}w;&{SR^8!%Xt&|Z!?Gz-0-p*45`!hosHZlffg4@H{W?Slp{S_`+e}5v2S?7w( zUY`qo2|cy94dlLroiPTOAwb&ryK+4+>{|20kaEAKQR(-8wawB!&5+y?WbTN`4)Ez% zDxpVBsf_XQ08egbW5wNuMw@C!o+0`0qEmqom4w!K|{KmKAOdrm30Ay*3VA#BVy#L9p|)sbtW@nJ=ZtF~rJ za&>-VXNK-0=jPLu@@gkL*AK%S?@|d({l@+gPI#O z3q}q}boAWP*R*y_YbIru2#DzEL(Dvtd*A(U!BUj9oTU@C0{LF^`{$ly=el0c814YR zl@A!b)b)H7-YVESyK0U$Hy38$R~KgFZZzN%tmm@n)zXjtft9=wnjK+4glnLk+{*t0 z0a%v_=M5^i;-7Hxo~bj9_36^6+9Lh6gLTL2KSC@ydo)bX17p3W0=1Kh;r$#+s6=M8PmMFu&o%(Y}V4*?HEPbOp0~w)vey-x9uUeQS=03H?rq3d^z_Z;YP_nsh4R31ET_^tqS17VZ^=sT%BYl;!p7bB=T6q@E&b)qRYUj?;s7kP z*rPi#1=K%=5y9HQt$f9~5H!b1qx*Ez%yQm$jITM!ccedZe`z%xG@$7fzuu4u1AOD4 ztOXp-zmPwi^w87l6Nbq3l${AM3rTF@xD_3|TwXS8izrA+1io%$h zxt6R{IC80fM!j2#&A@eqfi(&xC_)t{!&*Y5e_>syTgijW>p9R#zt4b7qAu0WVDEnF z(Q87qK2gu<4XXUel4oN@{>2w45Q?V!_A{~(6^goxXEbK$&Q$6H;y;v`i2tkvWs$i9 zFj7-ps5!qYJA>O>r@5$(i%XGPN!1|{CB22qwG8~O>mYB?4gIIW<@FKTw321Md=p5% zwSyfmk@f_w<^1tG;Z5Vd|2q?J_>H2z_vZD`jQ>M<%GKYH3*22|$#b!|67%Zk!hWu{ z8(W7KQmCvk^fe62wTtG0XIS^2R6ETaz}j9aZPIyA!P>hJ>jVx6bZ~I6Fqm>i`<0Vq zj=X#AVjt7o&nzbiWz7Ro5H8Y=7Jc(DIw++>8zK6rN{S`wRiu^F?q#nNY+Okdn@sH8 zheEx@q8cr}ajak*mb~2R7KW$Cf8#psw|j@OcGF6U28Nx)p5y4n#>95^MGbcj7^e?n z>2i{{NG<5wVBhMSqq*eW^LxrZOW)=j$kMX+xw^UaL=K%p6XDmv3a&RNjL4^l1D}J! zLB5m6hqLDpoQ9=Q^GN|RyA5ePy$~yEZ!)Xk<^mWRZlB>~?D}GDNh2jTNqaWXz`Mli z+a&LIC7cMij2{Z}bTr+5i=W5<-qqP}GtmtN5p9-*s^8Gzm>MHU74Kr$WSX7$(qO7W z8N5qV#-+yMHRV>aVugl4NCc({1w}BzeX783jA#z-7VJHgZt*;*!f>}txyCOJ7M?W9 z3B^oRwpkNZYgcy1SMyIg7Ot+={1daj^!(It&SLJ~xd{j*T)}EkI1-Kkw(g{$U}vC& zs8=+GXT^A&*1Jxsc>);4Enf_Dr_rnp2XBL@GA-mWjT9@~R>s&lDrTP?)zH4x=Q z$}Xqyk$1Rxnz`u_b)n6eMc?T9La;<&zOw8K>6HT{LP@?NIx561k*}w)%lIF>u>}r? zmj6ixGT{Ff7(5Upl@ee9iOOEF>lYUp`h>_RF}PYqtXh*wvKrV?@6=k3om}U3%2jMa z<(=pYW;V@ZFXCx@C67YLJZ>doK<=|euI2H{pFG5Gvq39x*A9-1?K_>&h$rPFe->fO zwu3NBr76f-NYn$8B&0eeA~%U5SsmV;fP0&Vk+%wEdN_PHzgGc@UdPcTl4T1HEj!9J z*8>c8W>ISid+_fq7 zcUvl1H4n3|hE@Y;)bhvkSKsGxGz$*5AJr1$n}2rJ6S__Amam-)t_=&qXV1Y^6wdPr zn`8UgJ*{lT{L<}R1Mn`JHs-Zycg#a+PQ;h9fUK;whY09%`$txgu?hTk;-%f0Z&!hbrq|BwF_EEkm=#79E_a6}PC@w2 zT3$aB8g_rTDjdGqJ3JJ>s9xS1PIT&6FSU4RthDfob6n$Va z&tVP&l$o4<*f)$^38}H~EaG2ZX#AS9U3&@M>XQ$VMvTmcO z9}$62i+<6#60R=s9IAg}fFDj+dxn@tQl!^qI?ZLfC_U8IU4-ALbo7lI*t$lb=09OU za4@wCvmSqRFl+wR%lLm$9+BswSBlyEi9%Va zDF$Qstq*L03y&J^SnG7Wao63Y-O<1M5Jo+&z?(OhYhX#fg^BB&1=6o|y< zi&A0+l6wAeBuJ=Zu2L*e5S*+^Ja|4fBYN<0g-ylGTr(a-JGHrNHeEu3ftTGK{v)BpoLI z){J6JSrpB!7V0ec?Cju6NkGMum#7iHIlT7fP379_eNQICLE%L{B_mutHQM z5#<8IMMy&0ITA6k31l9AP#uYGxjr}OC?yjnZT`xfG$O|jnaNszvSew+HxCpzjmj%U1IniG zoeF&>D%;2EYZJMx^qecg+Ixt1mkN9cRvmoX$88(O&BOo*fTTv_n~F=mNammbKW>P3 z78k*wKqg=_O^S4Cq5M+wn+2uh1&lbX8TQ)yFzFF zLPT-w@%)?aQqt8k8iy2dpY=r)6dWn&_l1Pz?F_JdE!XCotC!jB?ow*M6`Oe&d&og^P8Wz_(~g%ABiPj2dy^w zI*lfi8ewt9-v}-PzK0n8cF+TCppcP%D{0d$)PbwH`@DnUd6I^?YxiGQKQ*=ddHvJ% z=tK5F){K0oRGer=y!=`}Ku~RSD#&m!l@l#VEk_?yl!b&dr7XcMxH_d(xr!I4%9VD6G20A(9X)m$%>Q7V2OfnWE<>^EFIO zvjbw1xtVX0;Xg?v-R9_bwO*xD4DOE38TO`~>~prF;+Lo((GapvVO`VG;LAM)waxx@ zhpClgW_rvwI3GG<;VY$+K@OAD;p{meS#99uv*p^k2!ddt0hmVatrbavej@HS=w)C6 zaR_5*U2m^jO*ASqr}3xQRM1t?&00bkTIsFoC$ExKFvdIet5$FOxN9~Fc@5}GXgV|J z`Qko5x3{+&LYp8so@SQZa^O5N$`lsVu*j#7`sZU%v@t`?7qra?PtPu}r7BE_KbgRW zkr>k1Wsx=60s2g%rRp+ibT#KB)u%cN+S{0!Me?LWMJ3`I|s0Q)viU!(=*$s zQKZI#qOJiZHe`8OW9Gx*mJ}?isskWy;A%Q#4R>a4vzRnp31#a6)C5)`ep#!0b`8`M z`qXhlyAt-QJy6tQslmX2f$JI`sw4IUr)A=x^PI&ApwEfvh;-IqoJA7`gT$Q+G=(d0b#u?#on4l1;Nhkv9(IyLZ?=GD zZ`kwe+f$f&itE7d^Rz2t85lo7%H}gHHR#okzpWX(2c*j%e7ZC z-Ayn*9XP-~K!830C)vV#WI32nB?iM^(`p@MO%uBCC5`vR2JN35)I2~x(p|!Rgs+Fo zfV?vDLM8|94je3Z3a=b6Io*hxN^Mg|dbaHcD2d@q4}Zv$jcLQRC&4Yv`Qel8y&p4s zfMIS08uXF_UzVLo+Zkl^X0%Fl#IdGtl1TWR$@DDJr(Fh^@H46^FQe%_8#nM-TFf2n zw9q`QPABf#Q(0E3%oVhS*{eoj^uuY<#ItNvuBF_)YBS<;k!qBnPUNEBO}TU>YtDE8 zbE~mYyEFpsb~&B zWKksvM&?v?Q!N%c7XwNp_3#2lV}m9jv%pR5jO0oEBwq3kl>85y?pkQ^j=(kCmU`YGw{|xGGwk2+~sPMn*J0iT9%i9YX_NRcBmrKnI=k|TN zoM@T(e41ti_L;6Ok9^jMt=7s6^CKf=!v}M8f=~fR-%S%#CB`Oia4Uzge*iP$kL1a#ZnY#- zOAJSOMAFstC#HrKhi}$I}Eet0?VQ3fSVxaZT_4nDZ|r?<(!6jsD3)@Pj~0#mTo9(G9iKNxurA?c!6%8(kLp zBW01MP|KCz%Bm-KplgvmN&J?nQ*7MU{XUu>3)u^{A3Ya&cFG)L4*-+E&9eygME4g} zdMGRl0}L%TfB!i=W2gF=d}S3pAM|(Zv@l7=x6mzghN;tX~6wT*R>-}-8L%YetL?v!ExrO`cYyicx8oFA*{YxP%r=W!j`8nAGFe^>XFAhbtW1f3&^BrvbR^}=cR}|Fa`g$9^TEF? z8sbZzD;Nq{9&DL8h(2``KC8&kUQW^Jm1xn8Xjp|s)!I6!D}W>=c4#v3TzCkM{XYBs z1pCFZnzorHBZEz0nbyrm6Kq-*=J;cyN{-*ILB_NwR=Ks6HQrER(;@NDUeiplFz#l} z@HdcO+exTm&$mLuB+b-%=#T><8@?}qn4;#^2%EuK4m#_J$e98tg-a$d+;;Jt8CsnW z0u4e7uh`keGC+_`W$$PmJIX9PZ^9Axj|BW@BFfP%h^_`J4|At-wkX=hDr_HBjt~6V z%r;uD?}YB6g!n`JF0hfC5YD|<>jUH&nw<_~44 zBV3rD2tUpB(C)~SAaM^1SQucrrS6tUV<`F=nWt~)F#yu(W?o@uEEe-)rk$>#-YlyT z8t^ndVTJ6`L)_2A5DcxPl3MFNI#>k%6JuD71|agSEPK zwGdypG$Z1cENa6xJ|9?|o3M<|AY$wa8 z^85Lrh+VDk31Q<%!NQzdKCU0D(1%@}JL6QRJ6Ws{ICT6xHHJ(50Z&}3&JuKpKx zPJyNQO`~q8wr7~?r(eW-eEstR^r=A|%=@7{5e9xqYd%8j=l|42Bf4R<5U_9GRG|L1 z%@6X50G1k?YzW)k6T`}}LYksqgpm4T!NrB0xG7rBP7nL!RFLWk_YGSUf`bWnB_mgY zc{$VWGhHo@FaCa@3L(<|U_7{0zd76bL@GC(+Wwrj!^Yi4V3D%g>`^ ziCT9#N$rKuqh1ie6*o6t9oMIgZmKTC8PslE0j^z_!2lDmYciqvdQC z?qb7t49g)oT{*qcR)+$b#9-$u+SVdGs+nNRtf+tM6B8)}7sq>&hgIA%$s^^81fKN| zdo(?mXlFaqNY89DhChe4_`||Nyn|j77s<7QmOd95VM{(xO%F{C*Y*>BO46tg)eD)M zYTTCw@nD=g%_5z?gFNfhMp$s*)s(A@5$J=~R09}wW)Z5@_7o&K+gf#7Kl z+TwmUrkdFcx1!bW$|%(VCe-Oqqjn3Skvc3>*T)Ty+vH%Tjci}iP^B9oyh~|A11qKDpyte94^g`x+6c>Lg)2t z9)17q(U6`t66zS;qgCC-m47LQu_gFs23O!L5=t^9D@@W~>YC?{ev=bCisM8C@9D}N z!tEr+{q?>wt}GD+(7$OI_Z$d{D9;ojNLufmScAYtWXj4PlOnM*sZM2FuA=aS6Ob#oM#)U<|t;(yP-s(ft7s)Se$UC6Cp56Fcw6vF!0BV zFmSN{X^GugA_q~6ZT^p4K>A~?{?baGa{`tmBJoI*di|#2r@fNb@z^0a`6xTb}x;%a`_4f zbM>64HQuyO-Ar}g8-)EOFmeQt?t`kC_eDDzD?)`Mlh=s{akvnzd4)EnI^mj!f@{#+ z$$owRk0rI;!xN(X3$(QUZ}&5j{;y#WKngX?0CVL&hXo-d{|z#C&~Rgc(zQU7vVIk@ zNP)Oic`zz^aG}e#9mO=qMN^Zlq*_D(lwfZgB^YEJ-V2qH9lEm-Vgv7=E^pS%kJpP0 z&u^xDNH1>w9~O7SnKDgeywP!_?C}UBDVAXzzZctL8~h|NL7>eN>GQ)$r9yk@X&KODhKyWIs$B{npjPhav69-W6wMnz zQ7tzHZUt*+IG!RGV|G+^Mqa_v+ur*IK(%*&Rm*Q`0nCj+wDW_VLc_6mvzMrXe0}t- zX{J(oueT?L#ZII}M=J_IAFvo-kdUpUv&!!4BOL8ntNlVoCp$=d4Cs%kKQEyg6}{De z?0Jv%I8#KoG(kh0-mpDthm?mOc;z*G-wFOReFMwkh$D>YAKLOzr0Zk*@^kNop7t8X zPvY+ue26_pSnEiwK1Qh4->L6N-%a6~Gc~FO|0~|qGcj@YziCJD|JpFFxGn&3IjvA% z!RsYe}l`1P~1J3n{)W+T1nj_9>RAVfbB3Cf&~RsHa5~kegw=D55rq0Vc!}nS_G^X z-7w)kusRmex=Wxl#=dvU`2*Oem8;aNmdYmCA6fl9^VxrDE55~Z7jvmFCn`G+o+ii* zH(}M*3ToH>#mDg>v>*nHnldvI@hM@0UPMI&PfWy@@9U+(FJDcHEJ4`D&L}lAsGP)E zA~=lwgWZ)en4Lk50P`an(uL|L{Q;HNf{k1dOT5utr>?CTmPGJ{vq9I_p zI7GiWE$s;gljYa-<6c*Og3(I1)X`iQ710+5;V$0aI5n-8Kh7XOkb1jIb+Sok15we* zI<$mQi$}cTF`uQs33U^1@7npu>zDq~*N;I@jD|^LLhek<*1(GY{b(2S%D(IWYCQ7) zHMW%$0Ps7a3M2W;3QS{(?uU}i5}JI6$-I|9$z}Ax3;Z4?W3q( ziQge`a1y9qzQ0oqzWn$>mWe-=^}OA=_3?Rd!TC*eQ}e~i{n5t_IWJMbk~cEmlt0$D zo*{bt5KYb+RG3}28|O+f!;+n-_z?5hW{4&r0LWFjZo|~nR#8exUpM8#gM)|zhBUmK(iav|2lF0vVJxWBq;66 z>;d8;0}6pTG>5KJ#1R+w4bF;)CgRDd4pEJ&kn^nJ*K%tAY5%)Nq<%Dy3#p*D`wes< zO#}JtxTRD5X#~QP;R1|d-`~5sx>`o!su})q9I25NTHQNRWkb)s@)7}yvqW9T6qc%o zs-4cwtxlz%;|#z9`*(;DfS11i`v3-*Nw|v6yPHZ&qx=2OqnJ|Lp`&-rOtop6Sk{Qc zgU_e@?nV&Q01#E8A2le7P1Gag*?Z_HS6^Fu2g#z?B+$6`(H@`+1_z350ka~DW(NvK z>locfpm2Y2?1x*3NaA0D7yfy1eqoeUN;DYkJx`wD9&s(4!H&b&1}Qnm601|yoMB05 zghVOhhm4x#8_9(OtxXlO=u)-76lal?R zQr&=4sYO<83F)jbLX5X8MKsUbCFU4r9Pz-+S$nt5-WF+GEUb8R0fLhw0L;?Gvk~`d zRXkpqUJBO7IycAutgx5klOZEak?tfB9QgLptN1#(1^H6*0E@sUOj~7MU9s`H@ySKO z`KQ?7vVV2RO~cjEO$T7@_vPScLuBd z4!5#;-gNPERB@{-oLG7Xpq1OYVqUkL(vv`aROWFrL|W;JGBVd6j7DB>>BL<>p(Sqz zlCXZ>BO&Jxde}*LPOs4N3W|Xt&mr(u=z2-&H9lWOrg6<&#XVfOlJ`k@`=1M`L+zRf z`Y!JX5Qm|GGMGho*R`sO&{0Az_as7M7#@aXwF~z!?$EVtA!5E0^}Cs~WY;Mq8>W>1 zXE$myl+u&U7k99p_?=|`$$qr}e0;va_YzTHZ`;{TmKvNzZ|Wf{Xb>(>k#`w#Zi&qO zZgXr?=-jmcUn{8te+J{e-;B=kHm>n12`)nfF#fwg`0!!IWV|uiT%Ts<;$mWA64T09 zk2a)Pq~Gl zXUG8Y*+w5`9u5^IjCEXRns)GQ@RDw&U6_&!GUDy9wEd9*e}u!I@Jpe@-=nnki-ki5 zIBwmG2a!;N9HHY2++A=D@925ChoU*LaU8Ydj^ddbaoM|1QGp4_{)NI}r6R)7K&H&h z*+30oP4q&JRi>`9!x*3~?b{@COYodaa&!ot)59NO zT-w0adcmd7%Z^($GGI56xZoJ0GMrh{E;P18F!5yvuMvFOPYQ?{rbe|fkv?@m68NKt z>91eBU9EI-J(brr(gW;zj-`LSLM${UWcrW>67g|-WuQYAg;hGHX735Hsar)sk6UiJ z6U@}FJfdC5{;A7MKxgy;sRc4bteJ*~xSBr|SVR8s_Ev}p*Ti9EXCkT#t^)q7Heq^4N9bv|5 zzZFns^NMma_Zb=!`_I+%|whQ!T#BNEc1w(HvuB_fylfDDKj=uxd^puqK zkc5TAovWy1Z0GU}?&!XlSng21kKMo@{f16q4$n76M+6yIrsOPjY>y0n_{~ z@m+3TA>TAunKrvEXHrwEE+8Kk9UMw8bT3px9;Y6uY106lzuRrKEZ8hdxNq%qkJ<;U zU8Fn1yHBXUdxHye;IVS9F4O#E;~?9AY%O1HsKQWd9WjC z%V3t9wjY>8@=V`AxDtO)U9HrTWt$4Ws8#O6`T<>KRQ4i4I)Sawa4E-UdT~Y<|#)bY^?iZ||K@YjmBbZ15FF*CwcY=g1EwrS9y7_d+JQ(2fVtI(Y2wB5|Y z;hD`a;M_(HHeE}hwC%j+BT$a{+acpRhnPW)$Mhkm2ph!>{+cO!mE4}LRf1!?`owz9 z57a@L+SM^L>Rh#}qQ--zprB3RJtRM=GP|f%uy+a&+qi>yve?4DOJ12Wp@B-2oo1CA z=n5<-b$(qYQs^)IhGD`yAid;9%M~VkRB9Vf&V{YDqSc07zaGqmUIvaddU~@qPmq10;bIjOeoDDW%Ab=VTXu}UhEasG``&tO%H0{&jw0B;E_$2P#{OjY<~-aB%G)7L=Y(;8D3zoe{ZEs^e>3t!GH zxN?vLt;}FJD6fi4ZDFsGh^M8-XwU}9e-s8hpupkzCp>QeH5B372 zwCFq|Iavp7fE6T<$gxh69!u!X9G(&h!}<92t9CncWXFXs-1bCzcXJLNca%eEypb_m zw7;DK=g?+gIcY~(vVGM0Qh$gOjnE#;%M`})s2?;Q>*yG?;MXJ)pnC&H>*JR=&2&lM zgi_Pse*df!0=NH6xHvZTMt%qg-=G1&EZ9WQX_KOb#Zd8EYDi~STC)JFj*ZbYRfo{u za>n6nj3e-2uUNlRozK{oGq6vWZ*6lM;Py6o;j1@Ok4z)^|I{}{@Ra2iLoN@zYAjLN z!@Vv2Rx^+#U689#yMRy1&X0+eI@9Y|!LD3e7k;KEY&TIC|O={*lXTlxe?A>6? z`4mN_%8OTDfOVj?#>i}eWNHVyH+Da>99@J$m`{iNxFOnHI=9~ib(>yoQ|@(pHQ+Mr z4>GJHy5Nad1)1F+Cdg`{?TeE6zgX`qtu)s}SuZKz=i*ox>H|<)n1q8l-y8Qt;a2Q* zJ4(umEJ4eEW=q$PySokKeRQ$_*EUmyyjlzLQ%v}|h4aNFrJb}lc?`r7q{Q|hxAN4| zOe@@<;Pn)xkK;Ac5!?{?a

x=@At#P@*q_%W~j^q>HM5SPsO{wLhFU(R&U23Q_zP zi1K$GWGI}eCOB%6ELCo)?@~N<(Eox3|3OjsgfkzXlV5KDg93k6@ku%XkS~ctqRT6L zt=nrci!0Nb@CE*Ct#$i5Bvv_S#TamHgZ{iATnY2<@=4udPioA}>V>g9X~L=l@>b~^ z;;yj_({GoMj6ws@?gx17w5KZ%hw(!p&3g09yhg>&afr5y(dL2>E`PA(P#XesHp{)< zL}~K}3U{<@VeKMMxmS!aVEV}&rducJSE*s&3N;Ck+wQ8A!c!jo!9j4k@EP8ZHE`sX zemwfKJ9Z8OUC~E#p`BUtAuhV=)t$HL`%a&yxDB7WL*ij@)bB5U2zj}fVF}l@)j;D? z(+hV^&yl;%EnBs)p8-PE#<|Juxt7b=r4I2GFUab|l>l8T!M1}`!1_2dup#aO2aW5C zIRK@X|Al%0{fLBqzFcOQdp%+g0iU!8UXu0S=^D%{pZ>L5EV5(FHrD!(ZU;3fK%%+y z!LCxMmXHBvdL0g0^&`=kur$+hP8gtVLvKmGu!%^VatV zHL@xQ@Ic|t%U-+>m?^AED8p91)%5xCOX-%gof;?GE2M~>gUkNT(R-*Y3V>t-LC;&( z!K$PRexRp9eW$-#qEGxRzX=8g#lH{)x{ebKP zZipia@uYH{QbBVbM;uiItyLD8t{*`f)!WZpN{q+n)^f957#1z8R=T9kdQ&{xEQI{7 z*KZthMykIX0M>Yzk_h>>W8WXpoX-Lx0Iv1mkx36zV$dymTtT13vr2>JIlrnRuC~N4 zJM$xgGz^hDmkbA$Z0(CHyrow$pTccN>U|AQzr=E8s>Nw?n=4^3dq0|62XGRTTZn$i-s(~sfZ`h(9Hub%S{sAk0WJvO?lm~a0_ z(m4ia+BI7^p4iUBwr$(CZ97kriEZ1qGqG*kwteRP&X2pgs%!t+Rd-eQ>R#8*kMk{2 zN=X)>i$j(k2k|Dyw~t{FaO=UC&jolBW=B>!@@^5!Czjg9A5^yq$GGp?abA=6 zgxx7t>^NKaBvjO3<_a-6{64Ym`Xuum^K(B9)O#s=X)2M}zHbmGOC$l&2kZ8U@%#2n8@-iHOe z7^^ShjbE9VHmk%66>C@UoocMU_Yst4j0y0h4){7zIqU?AHhT?SWT=kyqSyh}2v)KK zCH3EGe-J6$22?bg4!lU}u&G8|lA3s#^r^8#izc@wuZD`Ag>u&oIiw1CO2Cg1jx;iI zV1GOR?8a4*#A*fA}%|ZcS*}Gat5cuS?{JYoQ1cgVhSwh$U>t$6Ww5?YEDQXS>uc(3Qasr@yRF>L* zy16I1+Ob-ofJ0ni2?9)z1x&EOrXaw`0+7)|McdLhNr;)94`>8BG@6T>o83G$sF&^B zB(1Ak(8=ah>T%ZjDyp}veYa9q%&WI9ONxG+uVoS>$s_==`j6Y*(=Wa!8>#;^*4t5I zktV73oU>~j`_1-eSF|g!LqJ&i>A#vtgp0a@nn>+0IX3gWA~jN&HZIw6qS+*i5*b@( zvfxx8Qcfq^1LQ$aOr)e)Ubhj8xe0Dcn{vtiV?;EP1u9uWC{vDxRE4pSp(c`N zFf258x`zl@puf3fNH(VP6uPTqOdLvSce=C13R^?0`)K7Y@Z4h*uvV({sRS}_>=HYM zG4jT8X>H(XiA1_;Nu&-?Wi!->C4;Lq?x|=EAF|nx_Ku{D1E__Kr#k%3_z+Z;1xl$Z z0;+A~3e>9eG&=_*+y}xY(tjI3ek*HIi0GBf-5S`E>gF#%YYiRZ_SDW>)g`sq#Qt7} z5g3H7Tbb`r(h?SQP#&C8>7crSb825o$XT{#r*8n0`2Z*A~Jq|N=V7XZ$u+EWXpIbEACgO_C%M|f0(m*cGsbyMJBC+$LHmqm~ zJPJ%bi8;lKZS3)~@=C(QC&y$^M(crgCz#1kA|j>B2o_sMW@!f{8sW`~bq1}uG1IoQ z5GiGK1&&!?S=0|9LEq2vX_31yc!Z5a14P6j-yk3eF0p-1jB=xl&fQi3`B#MjUG0B9eegK=pO8UHebj?gSv3K(^F=PjA3gYx25< zRa0i@386Tf=0Zg4$cuxq*GG;U2v-Ir@`yE1ql7}cJw5kgl?D$V(#Kuq<4BDbkfikp z5@Sxf0))w|N?5rflEtE91_sNwRo0_^1?97P(Jq)sk|o9rTM5shDxF*qs$`}=Z}@*_ zi9fzq%KE23s){us136mHO>S#D`#vSp_WgT-~$C-jSEui zfW6HW%bBanN5PV*WDG|w9PclUFvsz!y9dK;J`wyea}~?ZMo=EAinf7;G@-^lV)__VAND25Kb+lCfE@w0 ziF)cPoz$S932OR)R3W;Y68rNS|f0PXr+~d2eGFUl^+BM;w z;u|PkU;S672a)s7e4sZZE*)ycROthmry-sb{-fuS$E@9FfC2$YYoO*oGj4nrdOls4 z6TG`sREfx^tHt)1?Oo$E_2X?i{^S)wpf)|T0u z_mO)pI=kq{ID=Cy>0O3pnehDPM$rcm2rzpFK9|uZ`j8_K0EdbO0AY%Ilz%iA+@~MK zx1891oRuz!_YC-kFwPej(3-4V5&p^h6=e2J*$mJ6JUGeX6`E@M&Ar z5OrDg;y~%`vh10lK!NJJRO~U*X2USAcdMcTo-^$7R=iiH6B2}otsLhJ{tQn?zjww% zyyJ=iQpO`~o;$j<5II%?xc}YO3lV)H8%HaOdIys41B+S27y>OWZ)P))EfrZ2w-4 zdIOa+5#d?WL6cr~+}JcuYs02A>sIYp>}dA$zk*n!0d24Pf54<4keK9?PNxP1KARN;FSl6y{9%k%7PlXi7MzoKP+SvXO&2k znXf}Z9^udfad|{^jv!z)LX6ZD3mxYj%C5&$O`a2!8}PR#1`0HEYbwjI^tt;9#OGjE@^BZLn$SgSD=yZC`-DbfEI>I{uar4=qF z%~@W{iKQRQJ7hA;yu-#mwh^AY(BSWmrV#kr<_UROtgI=+*jNsPctX76^5 zhg4ZLBFPgCdJ38A#t8Nw3qoqNKQ>Z3gj`hJU?Jps`~l&}1h^c#PM_6+{>uE^kjeC_(0`AM6t;s+sC9WEMU@rkPe zVD>8lHU1mgV}9a0iC?Vf@+RqmtcH9wf^g*ui`ytpaXm>gKbly$9)@o$W>v>j55I;j zl0e2Yy+eGn{)y{p^({wzhGF#r1NzE3+{Os5v(j8zr9o!9p7K@xSLHDG>@(|>yD2EX zPDCvQ?pY1tCjmfe^-!xz@-185Gc5QC$R2r6{`z< zsUek7-1n{U_TmXV5)jl|HxB3p%Hb)w!*})5Lv_)$*nlwZsB&6tc3^y;{nmf21$iRn zaO7H}4vTPMLCRVEHNW$Q&(+h5$+!H&|EY15IyXAX9U79B%%o3T^I+6Pyarkdn1Ewk zA9H&KK{)%25CVS~t+7jM7FIG_(@fLAgg?1P!Z*v*SZ+r0d#oOc}qqjzdi$iK_ z5uZCFY^zj)rakn-y{AZI_`HoA|A+NKw_QmpKZT4466i85j;D>nyNiteJ;OLuqkvXh zlN8>hj4aHA)IbcBf*xYj9|ltmC=xAR<3GOFrBpZT-APJ++hcyw4vES@9LIPpeI4Yj z=YQD{8!enf>jBWH43aRBP2Xd}#Oa21wkdM&=h*2utZVNcF%=7`e~t?wux{8#2Ge}N z0Q}N{w9P6giO{J3SbXdV8!*dgMHAfZz;Fr@iS+6|B zV&!P36MN%z8nQL&F<9v$ML1s_TkkO5mg7=}ga*e-i~H(lYtE9=n#DSlk9ArD0_1>L z3&w>lbg+&R$bhc{$SAUO7Ve>Ji)vZmrWH!TY^mfYaCY=yg^C7XNu~@AD_lVkEp?N) ztXHdc0}ACDwVJu)Xy_0CiMq&OhPb8w&VWX=j4W|EGntCWp5oNlgSH@-=>$fUw|6KSL%;vyr!wq3Lj;|8-{>T52E z-}tAkfU*B%tUDkOoS^5bel(t>od>2m)idZ3&NLnN&rN0~uX^<=yT zVDjE5ojUt6N24!aNSF(pkaMpNI9QvsQ7$g`&>ES+S>x87xR9hPR|2>(6dOa1S9;m zxFR3$43SwWR6&F1{;O*%XWv9C?P$M*C3U3EtiemB_HwN5Re#S_kNn&X?7z*Plg|z} zy8&_5;xNl8(HaU`dd92irO&^$C6A9;gb@6v#(!o_{)JB_*95x5_d4{fQKs}YYld`N zo|zYZUXT?a4O;qoz_;`fhL~6aH;>^@tuXTpmp$^1(fF9GdK`70yK?^hi{9Xm8b?tk`HxYmIWB{SKAbv~$u!l^&Tl(^u()?)F`^z_&`I6%J0Mxo$ z<*Y&{1VhyBf8Z?a2c2~H47|^o_ody37Da5O5==<9+ zK(L!~GjJ5=P+MSLb!mni5>NOv6*9io#t5 zTpEOLN}Y%T94vp~^Ob>?qm%?98`_Gr^lf44SBrl zUvrmpT#Io3<}mt8(s$ab?D32Spl!D25E+&T+I|~<-zB zUBP{sO%e3tqdB;cU)tTB(frPIDFOs*=jOeIxt#d-zh;Wb=U^%r$opo>+g=?w6_u&2 zx}P>~ykpL}$8_r_tMWMDTL`8DKwusJ_Qxvgj-oeL$fT2jAq&w|rwFO2AW)g^rTCe8 zxvHh3*>Q?1SK>SSr9E1WjHmE9IZ8iqTH&aeg(3t2F_KqK+B@<|J@m(%w*Z?ess z*W}6rbGVOSI*O=jfaomViyP?7ua?n_JgThAGcwe~IjHorSF?Q2QpnT+Y#*0_tR9IrxZf4<@eW^o1~7_|p|r5`>+XBK{JT2ge zI=n}dvY1XSk|Ku#L~_H+1xg6pq5i@EQq(hd&8SqI|1918P;-Lhl`Lv!Gv%Z28S2>- zYquq9&%b}5>e*F!8~U{4Pz`h*s*#SnEVuR8tFF z=uA+aT9rK2T)8Au%i-vVTNYNP*0^nnuC(D5alN>(SGd>aL%d`!o_1$uZ1NY$o|COt zb^mE8lUHthr?FN2fz_>d5I!Bhv;S`#(aP&c;)f0dq)Yoh56OWuBLK!n+Z62wAi3e4 zX;zzJH-TB01lLhx*;=2BWWc}$v7}_MMPc~ID|NHQour+#eJun*WpEGXXwNzf;g(TF zrI)T+B_wPE3{6B3T=6b|UIa-IDgK>bKY{gXT?o+gxcT6F!hLg-^}zdh&ieserE~?& zuJ5`u%xYi0V>U$B3Q)d#m+-A>?Jnm#Ci|5Ybi`>#mF054wzA;X|8L)e{i9ljW7&R$ zZpI`r{avCqd306w3DkG5h!xR|CH8;nwI{UYf_21+cVjph2Gf_C2e=~l(n*mG_f^q* zTgQN$IYs1!b%wl^9!ksx_xX;Q5G7d0rVW>wy#sPfzYsfMYh^yQWgn{3)O;Nqvu=U* zsyxb^6gg5IlR`PIYir%GnWRcZf8uSUWrJ}>Ah@5=i}ivtJS8nN!gRrs`>46;F0Gl? z5Qo9jAv9Sd%fVP}AK9FM-qtLX@3@UNFtl&usc6rtFr z*7RZ64KD*gY?8Eo@o2iRUI;DCO~zQnjj$ml>Dk?X;m#D9y6`#%k5+}zv5=K?P^~J# z9<}1lR8_X^LZjarBTWx&1Ybd|7_&|QQkGEbDG2tUpHEG4}M*-Ccgb4OD zrs?DvYj13jBeE-nV}YoX8N@MJu_V0;$37ezqlq#zTo#g#L{M@Jb{L2c63?LxBZ@@R zpq!U0xSP5@B2%MI%gHQ--Zw$2gSAGD$z=&VD6&`)6(JmxCLf3@D%^ZbUawCDbL3hc zzs3Tntc*dX5-cC3PAjE}8n4(+w1roh>l=7}30BQ$ySMZQmMi!7a{i4|qcJm2i=RkO z^o3h6o3++toZ1@#UnL6;>9!uh0pY-~SK+vG#ba{7Yo0>Mxgb09e;_5~cI<0onsYTB zZcKz=n|F50c=A9>=}kzQEIfNY{#hDHD$k)Yq!Uvq z((RXGgc1hTPIm!qh%*o^%ce=jJe-(C=`Hp^8Nf6Lezq8D@xe5f!3(LUH8f>HWu&uw zB2ulJqi(IVcPf>2ONZl7DQT*3ebS~@Z*?Yu&8|{)=T#Y#B&Rlp~k9Q0Fo+m~rR!SNO0iG1a6$C%_#|xLmVV zx|H_crcfv7Dy`_C{m=o5k!G2J6X_1%&kOX{N1DI^8p|y(#KN7;aIY!EG_JXjw_*0U zFCubs*ti1lLHQ~aJ-<8+$cXFa)uf9 z&1N~;Wjg3DqW;y;RRWa0NkuZ5F`|BoS_7_o9k9oBM@`G~v(eXQMG^yse&G*?97mUW zjk|jZat)e2^&}N^C3(APZRz56aHnWyEpvWjIXgEfE)%&-@@(kTZlCYySRY}^QoVn? zAWUdfqx;Zhz-RV{SohDN^qmA?JLVrkhqI7AH~dRvo(<+1UM=&zd_(Sz3H*+BlU}D= z)*iK)i+W?jy7cN*Y-7IqhC52jv6h!Lj#i~)|GCd-g9cMY$Y{4SF-Z2MC=|p4aYvbA z=dY!(M|3zo1xpN4%57RhB`;irPs`kt|8GV}*O^e&L!B#bcK9XvcBUXX{5j@v(1 z!G>nftnHpTof>{Od_Q{0NQ&qC!4W6(ec^iglj0SIt9WXPY~Ph~rSc+qTy=zdNqtMkdWK``BF)S;6d@57A5$OMFJ4RYjukNc4q`Nk$Wod=x)l9{R@7alzr|^GjVfnhVMLvV$o}E-cSBvm&0`^YXAT zQsbHHCinAt?d%eAOjob^UlwOLjg&Kz>!dANNDAgs#JnXM(w82(mKT*5r0i0=i7VbH z*j^A7(KEJGb4PcgfE?C3NtPo9;@}46%uTaIFdrg7;VaFKKvnz+H6#YBSgRde^3}km z=?6oPB|du4i=kne4?a5FURx&tz*!;o;NfJlI7#yQ`vOP2j%0m~BkYZn2Dh)l!ua1N zBTENQsOnPnXX*f@Fo!K7j1z}5f*SoqzAZwArx_gprhwB1Q%wBvub>X*6;D`1*SF@x zwHP}f-Da$BoN#*!Gun=nmGamf-pH^hYJ}+Mj|OVA3d_;#4sV#r;B9LLT6MDF)K(Si z3&AWZeDYBoT=GfXg_#Q6K}A?Q##Nv`Zgg5Gh4o{59B1IxoP+`7%C&vlb9KhB+Cv9(4ii{o1yr08EbqIG>-F&n?K_E4 zj-b#C7F8A_3%3vsj!^HR&KERJK14?Gro}ic=pdMU$P>!cR0Sq@mr+P~k=F5W;W;D# zj|5!k?bmr|=r7)fe%HauS z;B{rogLLFjwL7a~bzpVR(bn0sO)MS2BI6oUCeXC6r-Kw7GVWdQjg59mRjJ6_Ij&9Z zWF==SD!&rPMOAvtZ0lq-hi5W~l)WDkhP1Eb`!vA&xK>E`Ck9h7Qj)zWWj33iv`>&F zh{|d)9I5eA4|7hUnBT-@ZY!CyIjYa6!kOOep;Z8r_GD!9w$5sb68ndTk@???13ri& z!Q&BjR5#^{rE;TDCBvqi%`Mvcc^rMg*?ZjLi|LB(aKctwzW3R&w$WA#=07Th({x~| z9~$8}uX=5mFT06Zf5Er=9JO`{#8m=zh6&;D`vp|H42wQZx*zPtT3t zzwimXBluqs+@WWoQ@Abl1`4nV>`D!(4UR^m8( z&VQ$DSu4Kq>zEjX2TZ3jIwv{n_X@P@aj5^eKmA-mgyMilHAKiu_F~6C4`7-`=OzsI zvKD!vHNsu0S?y7Hi!LpGN{}#pE!;6TX&t+euv;c5m#lmugT6%VuTzHWAS>pViYcT(rdGm+*BUa(PbU+{tbU7)od@(A!n1602M|(S6ZQxP ztF}!k(AM_KQ#l@E!nH!H#Pz1wHAUGbCEJBfJmAppwJExtGCiMx5Q2YlR9?HRA~`gIwbYLG=EPptl*FE^!$1I1{3-QrX8srf&ck`o2j~Vdg4&xj=wHo zLJE`-HRMO5Sxely%XTw5ur=nN?cJ*{ngBW?kDx7TVZoBcnJ|4hc=gvEtqy8mFv6~I zxOoK;(J!azw})(gLeC!$Ur>dSz+UBA_c;#-dlLt7$AvA|KPlR-e@LW~Q_`i3=%q6L z-}!FeQv4Li2JYU1qUqjB+FV?b2?)_6QI?0}Ie*fsZW*Yu{G4p%(rPr=nBUk>*;g16 z5gQ_`)MZMUG3u&s?^?UfSaii7Apny~l^g+cDPn=DA|ZPeCeFSyuQ0)XJ!EP_HxP-f-B^Eegs8<(vMnAtz7hnsJIa|w7#rw@%1{9DXMC8IUN{Og^)~t8Drv)KvKa=rHxi<2J8v@ zk*c&&-p{}~4xy?iXYJ8&{Fb@rn%N?P{w?77_5KdNfa5!<@{#5Z0byZip!f>*U$5x0 z)68V`Z`bMM-}gUeZen|&D8NU1$@53yc&Kx`5}O>8=LTkr2BHdj9N>?1%qQs2|@u2d_&nJ+C}Sx^&mb0GIb1Z-~~dHJ+;C z*t0ho=K@aN`OUd3HfM0+%C&zilatA)n74wQC06N?{WPoeS` z;5iRD>OnZlgZl|~`)wa^kI0RR4{@nA8nP-z+HR<#9DLUM4n3Cp!Zh9*4BD*VH{0w~ zSG!2_$Ac;NUlNee0J!vGBdwn4(epq$rpQ9wLQ&eprOx3Na$ENBy{WyN>n3!`>!OFykOZoAkt3VJeXP#Wv=BT{L6XVT2x<5}u zUm{%E4N(V5wK*pZ)-pBZJ=0Ih``Td7Ml(hA1f-qAFi?YuInvsx{IR1`YiRYFq^VSfE}HqzLa#|+h_ z%ZSah#f`hir$q{xd1Rd04be90x#?3N!2&JC3MvW;GiaCLBt=kGW#@#Pp72&K3Opi= z=U~?8%vB)M)%Mo>JR8`C>k^q7kyC*w)0)bNtBV}OfR0j)#lv)HTR25_?~ds@H%w6r zGj#HPmtg07FuF2R|L>BP!%dF$X^ftPn*A?<6nw8ElJ-0O-#A)wpW3c&cT4rBhZ<0@u^DEp&C7Qs%w-_$;T)ebA=3dOR`F|ISwn?P8HFw@J92l-kJpw^iXr1&<& zfnI0fc<-jPTOce@i$xkVygF1^F2ifKMlB`&a7QU-5A+Fy^=%^4zOj6ES>`b7@=wx( z0!lc=))2SEW<5-+-M-$0#zG)Y zoc7X;du=L_lNXK{y?`55p+s1?HmlpG1mKVCio7<9zAleQY+d75V;N~SoKAiblH;=0 z@=Ei|svPI=MRj7j7vg}@tYVjWS&*-b1LRieRSuJMkrHR_Y27andilqz@DI$z29jJ% z&h)mlc>eM0Uvma7DkXkDIW;DH*L?T11Dds6H8%X`Wgiv%hLT}Sxo>;TXz7M=?~D)_ zrJtp5pvy%?)n5&Ux#St*mM?r=HB((VvVEv{mwv=L_6@S0x*~m4HuQ>0wB`O{0^lHK zr^03WEsrhq1STOkJi%(4wU}J!tPDI>(&Pt|4H5ka4tK?;Ol4ZdOkxn8he4E?EH@u( zKTtlZKinTSLAlCs*HjL4AeRGbemAreR0 zHB1t0`@<=;}tA9y zma)wQ%1L34=N4J$!Y`H^+{#jFq)W>}Z0nn2aexS%c5CzHv-{Q!DD81LadETsc736J z?c|DcRcrl-MdasB=0Z4jg?aLUNMb11t+#Ov4KR59aY(HN^Wt(uGOW>3G1h?oGe8=3SA(xbwjUqM%NlhIdaczd@o`Os``9yip-1t@QXi&w0l+n8$FI#N`mCe}xWlmu6fbFF;w;GLl*84ovNdiEbbee zK7g+=h~bD#^jZbBlrCl zZI1;l4;uB4?WP!E)CyysQ?5pkWmB&Q$%UJjP5$fHh1*I1pwADBKa$WCzrkwTZF^~A zef@;Rte+m$Ll12AtGA%G(Vvf=;M~6+m$jUO0KE|F-M_VrCEHNunR3FrA{=hrwDK{L@$1{Ury zYGp+%?~98lU^n2raSHU$7Zu6f> zY!cSUlsFCYWn%K(p`}Vqv5wN9d4JR^)Z%oq4y*LwAVQbHVk6KESo;|WAU56c0()+Q zv!NVC3D`&qgTNz9gZ@TGPF%!0E3poNGNKNG@%bx3fD7^I)^j`QZ~H=U?-Nc^5u1OA zB%{JM*ph%x$3_nu{_$8%p#sz|!+KF0IH6KI6|}4aJl?52+XFvk9YSOp(3=-hB`n$l zr=TI#>G`E4>=E}i;AW3$-Wpf0V!@Rs-&-Gz#{w8s-h$Z79#5?iEs-k|5#3({<&X?$ z{aEZC0E+IZ_%65iLqZg+wu)~VGei%98XIi}@$fAlaGr*gXepFc2kH4Ul_9=m$HF$p zWqhnztBc=?!eItH*c^V@EN^QVSfng^?&z64D6$KXwaa|9tVj+r{hwye}w(e z68B45;E5rTqW7FVeS!lfGH})}+)s(MD6Q4c0KU#G2cO!5if#|pjX!OVJ!nN?hKr|G zzrrv|bsOG?9TauDb=P&+0kS!Sl!ML{$qODV`CO12n35N6F32!M0VhCH&k1kw# zu+TZ}gtfqkYP;Eb#-5o7W|LXkWSxbYarrB4fq_vxoz%PqfSTqIVxrI76O^w89rGlj z0H7DJQm?;Or0_SY(Vm$R3^G~n-*c4gH0Z~%D#W3bcBv4$K~M+Pd4F_eV+^&T6ax@a zXO)nRKo%ixy%}p_N@8Rb2ROBIu+s`kPMMpSo?%6~a`KnVi*Eijh0wXNg{#*M#n#iI z(=K!fo31-#2$`2#8zj_(C!aMe_D&q;0;)a zfhclp#zucIa6=f5>{Z7KUJ|Ee1Hg7Nfrd9$m4Wr+T(BLx#xG#AYu*0JY%{|dn^X3j z{6N*mO?8lOnBqGsOH$x3Ak$FO$m!2DnRmf6Pzh zBiO&dr8${f%wgj7gQgl%GW7zn@MbEnQ&$p4){}P`#lg9Eg?&2^hU>w*{&kKsgV~>7dQq5X%}zI?bj;9eR+U--z86t+98`CC{zqxO_Y8kkf3nd4V{UB?w-Xl z^~=3WH~_ln!x~*0+6p+I8DKo`TGt5~fKVr&8rN#}$HjT&5~UbFRlphl^A#}$fVLy( z2i9)rEzloiVXXqf8MB8qeB(8vYHd_^j~(K}(qhJp2uR7{mF1gJCdcS2*#S90kvA-j zbJv&2c_|ajr>sB64TE*Uxai-LWKZPri^-8Lb{i;|Nj-Dt5Ys=#1n`E(?qERHt|)oG zGUSoymGJXO1IYed&dARxwfyMgWmNgtCcwK7&dgm*zKKN$vWV_Py_THbj6c3W*>}0a zH}T0zSI)j)n;dc9B}JCD-U1q&ZUj)tyIi{qWp=m+_)p@egxaKPS=OC6Ye-aMrWUD2 z*w(2=s86jpuZwh@05bD>obdBVoOt<#3>@(xb-RvHGMp)=f}HpEwO~`Fho=G*6C4`- z`ERCY%O|U)shpg$^u|3>Ke;P* zAqDjyc0CY{dB2>OtX;U-9Qb+|mmO359LSo*ksAU{|3r|DWk%koQq%OJm5rJ*U&pxg- zVqTR@>)H2e?LqV0Q-^ld?CZEOFKZ%Sxk(y)CF0T>0sAEl96lM()n(d9HuqbABJMKR z1Lc7cCr1(tpI2s7J;jy7uAjYyCZ_H{@~7+F1)+h(h>ix#XfQ4w*|6lBhM?s^y0 z#^qK;%qle+DdUXY8S?r4LqUm|RCo zqRq}jKpQm|sa#fV@+UGlhi-1v>njX&7aFhp1tMHY8mc6xAG!eL{8qwo{8{Ij-aDQJ zUJu+miLcx|57UEM4FM~vq50F|OLAjQkOkE;0 zsVuQFwdfcB9o#bNEb=t*QurPBFSkPi5c@CL8rk_@kdLq*^&a0OfYnk9IJX!IB1+*j zHPAu2;HZcP(lSX5L4$vCtQhtJ*KdZoh6s}wCrxM6I&2_fn@(tpIL}h06SJr^Z}IN> zo0HZ^XI9OwR_559nC+H-ylUxM-;jddPTjDhxOpWf3)d?Yq z(|)S^r?(9i)fGar^LDZ0)fPNv$Bq2dW1s$}F{ssjc<#I+w5;Bq};$?%w9T#pJjOWO& zUQA+)e$_HXna@3N57BdkgY*{2IW@P2%r*Dvha6^3<{dxZH|V?|){uk3Lh~bbt8AQ) ze%msfiu%f$vXGP4lquo~XVwvG$azph7(8e#n|lRjKt}&6f-$)YyIVVM1lkfiYv@PD z(mh3T#L&KO1l+&(UF~c(NP=W*suyYU0tpg^_}iA|LP1ua+8?5kt>62pK|5 zrXoRwd75nc7%sp|>>&Oc!hEUr`s#yuEiua?QAjXE-P{S+Y;3YVkw5Voiat{7mq8+E8VX5vP#4qLI_o!_odl`y4+1i6Aq#6lSTVXIej z#u$<-bKaJT+G8UQrF@u@=5fuIsCl8T0>SmO}#dy{) zZYA@Z_zgHURo+1rf~l&77GMySCaQD6Pz;}F$xLi}JRI52jr<{3o+}|-dPbnAlmgGr z4euV82Q1TqD^@)4*$?Fe@bn=+pDgS-ioekv+JsX3)&|!laEhP!>iHj?4;)WJQ~Mv8 zUF&~zzAQ$BM0-id#Ge!b04O8kF!^(BbA&GlX{lO=ZWV8pDi{(ERD{sY!letlEn6qa zh8N-oL3c2D-=F^^ROPupC~2`bsrF=t4;NpcKw@>|yQW>;u{npROMx~tBT7>y`V~CX zO?^ryY@_#SY1~XfIj>Bj_+?3p{q)TABg`y0?+p@xu#o~kmzdFjkbyl)bKOUFer@c5 z-cropjii|t(uYm5X*HvsevzIm99SZPGSqLIV1#*3arD^**0vJ8hSv!Uj+i*m__*lc z?YHm~kMrK+B_TSX6(G+iZT+)(vi%!pSt@J(9scj_EggRm9cH`UpiX%@y;~Ef1Xvlf;dTK{D|O#n@g{`#)fK+rmMT+x zpNFlTUHjXiwiyRW|27tDS+nVGpAV<*F2K*nQ7sTzUEl5D-azrBdp*d?a~ND3 z4c0oDo#DVkO8dK^gXWZ z<}zF#Vr!OD$K`DS;d~~1tL3&@30fsYZfi@nl9$hkKM=A* zCCD)$zjlw?77IeOWL*b*3zkr^xr zaMc?rYrsFkFU$PYe%fKW$(R0wGf*AvFJU1rB?G|0S9yqlj==>Jot`Pn8k6uSJJUM9g1HyDrg+)Tsz@3b4eNlxXe32+y3kGF zV8-Cnx0?P+iA!8*kckli36X&r`GImppiTfl<}zp9%dUfYNuGcUgMlJOc=Ux&qh@R^3;XeNj^O&{XO;@e>@Nn zp&v>}SaBbVnPP!Nxl!=ib=v|Bw}ZS^YWXwof5fA8x42|#DZCP2{M5Ot4$}`s(nK$h zn0ORx5sJtQONTo=D~Y|EDgsxUBj6d+ZO(lcL#|H%HEb-SB>oEKJq#;g^D@20@Y?Zf2G!R+)H-cO-fi*rZ03m{85FmW z=RiMB2gM^ zOek^uuGAiZ^8{z`JZG^32vhd>cbIH(xQ|QTJ|fyTl4dz7=*b3ys%T+`Bigx=&?ioNFZi zfQHL^gHoveNsK@4o+L8kJ)}JBF{$~8B8r_?tf>Ni$jY{%#c$LF^AJsUi6&4t=T29CL)}3R!)h0w*izEDP|P#(E$+O>$f$T#HH#=M$!zGp>1G|>%cNRZzi;R+tCMF9x&)_9!fs3p zN^9@&P}2T9!G~k|3*KL9ZFAC|ynV?j^f{7IyOt+?e0(CYo(U6V1Wy2p&)(m$s9jSn zy*6fjKW7mmsr@X{s2r=f0lgP8rXon*<>g%6f2KZdZ7y=2rP%6N^|b&{eqc}jc6C2! zOW+IyxpJB5bzy`i^|H{sHcb`Px_D|;zJRVZG#jn-si(s{JEKaT1EWZ(UZ7O(k-<>R zOKx3D__%mub6?}F)t8clz5)?OM@QEB=+F5tBdhb*$(u{VqL9<$7BPTPg7?g^1Bm4Q z!)Ln;2JwBbjpdUEmpJi%D&WaO6TvvT$LJUabRCPMS0F6-mX>eX|DBZ-Xm76`EN|8R zVu>VPrloP3`gwNttXZw09pb)1F@}&%CxuGg2K!lsKE~vIAO@u%(ckjEl_g-YwG)Wr zLPuwJx-Ck7%}bi%lfhiNHEpPvbmV<}=YF@Cvod~%nG~$=D5D>5rb(8(hM1ZIj6OtR zylPqobN|rxF(FD=bLvYI%*N65NN1x$qO7N@3n>go&yG!<2}md@nudu3hSm;46{ZQf z)T>k1YK6h>06!UB~WW(bb_~GDJB%%db+jiyyt$#;Mz;d5>6R zO;`mgm^{F1YPXO*L+B8?K4@uoG)<)g&dMxw97wlsmnIi(a z$h>BMtiGLX_gvIwxh7#9t^uE_Cvb6`;q~;wcH$2Y^;; zOM(yXfHjBQkLf1Um>Trs@^*f2>cGLky8R^v@YB|j8JG`*fSAzgxbtCUgRy70T&NF< z5Hp9|VVP%J`S|&${rcG|(+*RbW4_O|eHy+^1*GvP1e(V|=jn#~ItyfBJne%tzEukg zU3utYcvchnMt?)i46bb8X2<0x1Mg{XYeEPW>8rVE=X($I10_3_>sFqsmi|1K!qeT< zaX1q2dEc4cI}oJ#N;tr3FD6=2U2y*N!l}*b=_%b;9k{s zV=CaTWnQ0W4`*=`ElPeN#a8ODV`!%=tcm|)Bch;*H#Ua01Ajg=#cwKJ%Py;awr$4_ z9b@n@A@b#VfBjfcQDM9J#q*A*DrNpI{(6|F+_!<^-kj+hjo;0k_Qtuo?;+h@pK&wo zov-4;;yC$J=HS9<$L7jc|5Vf_rBT0Ux!Wzgn#tQZ5we%D?$4v7Y_NHK#z$0RSta<^ z_t@d4#C87zN-FZD^G9(Gxx{^`UBR%&HX+7fGj)&MPpya{O37fIlw|#h3wvCNqIP4p zslsxX$9;50Td*IFy(%`omYAzT{p{KmCZ?FR$~;dXccA-|7WV}}8t`xQ;<{JNoMS#^rG4j(z? z@X~#C9J#B5NmG}rJ!>%%-aS?-^ZBVwc&8_ylj>3bo7rxQ@C)=up7uuqOpjgB88gy( z))rj6h$a3!GETSPaBf88JXey4ic=T&?h6dL+$(#iaAiEoGBZP*=U7hTgr*MK@Ais; zW<$+%0l{IpbOzWn3}EwR$&EZTuGA*8O7at<;fLi!PgJfM@nrt@wqDY{JxZ=jy!;dY zuA6JBB6kW4Hn{||ntU`I*1cP%EBjkBEd^mSZr6R@dOgHeWjwlR+Lvl6YO=GuK?G@n z#Ofy|RhLv%OD{uBJ|(9-DQ6gtwgMXRNH>kWIiQJInxEQ-1|Hb~@`8s&%)Q$dV=w;E za(+gNu!?ip-#wvRTRwo;O&dn6y0jo{Q30*`TJ!Nry^V(uElV|=yhA45cY9=d-J(sj zLV4qEy)e#DQk|9Zjlie*Nem2$#3f9AO}}&1C%ayEvP15XW?a=rAi+zGD=5bx(Pblw z_DzM*J6v?ZPcXAbmpqv{t#k%;?Be87373I>VS3uyQ6*A-biShyzPZTRV%nw;Nr-vo zU0B-2{0i68(DK!GQQ*(Jk8UqCjxh|uq@beBlGZ6M2|m(#5yZUS5tV>}lq#&TV-!4A zkvC^lHDV#}Iwz4su$wRuRcPPsOTxitT*&BBr`C<*@L^-if6%+vjbV;rHA$^?oWgT0 zhMqaAn9PIM8Es{GDnVhdP1Guis+M~V{m$GbT+HXZHx{Tm9cUV2E*WyCg*4bDV>LzV zgD@JmdPJ7a8Q0|ks)a?+bxUav;9cPb=(SE`B49+Z=fvw=(QyFsDHl2E=a}kN0ACS& zr}04ukh@<3Fey?K{R^{h};{q=35=e&H=&U30LMO#|I8wAsipaR{(O z!f=a1ZrhVWAnft(1LR_R)V3QY1fsvdF+9;VK)e>vOzKOzh=Hzg5hLYqXD9&{=!>!LZ898_i=%G>uh|4$`&sUG=b&$ z);?@|eEgSe2e_zuoGgzDz=8_rpkM(QRRXw9krMu`!w(L@K4(W91PI09SV`O#d z*(NchyG03s%KayVwEaAQ(2F8)%}T0Nrv7=dU)i%jIwmsy{1oR=Eu7-#t+5k-NfJkYL1N z)(&m2@IfGAY$IfZv%oVIXw>f|8Sp@fvOyflEa-8C6zccF1DId-lch3+1#PCHSVOWZ z4KR{B=xeUX7VStX3k*+}WPw``j`QG=vfTCG^mJshz_!XGoWHK*%}O{2@*ZoWT$SQ3 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/32] 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") From 7e5c306acbc4795b52d81f845f1dd83d46b7c908 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Wed, 11 Mar 2026 01:08:52 +0700 Subject: [PATCH 29/32] Update build.gradle --- core/build.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index ed29f60f..bd9ce465 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,17 +1,17 @@ apply plugin: "java-library" dependencies { - implementation api("com.zigythebird:mochafloats:$rootProject.molang_version") { + api("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false } compileOnlyApi("org.jetbrains:annotations:26.0.2") // Minecraft libs - implementation api("com.google.code.gson:gson:2.13.2") - implementation api("org.slf4j:slf4j-api:2.0.17") - implementation api("it.unimi.dsi:fastutil:8.5.18") - implementation api("io.netty:netty-buffer:4.2.7.Final") - implementation api("org.joml:joml:1.10.8") + api("com.google.code.gson:gson:2.13.2") + api("org.slf4j:slf4j-api:2.0.17") + api("it.unimi.dsi:fastutil:8.5.18") + api("io.netty:netty-buffer:4.2.7.Final") + api("org.joml:joml:1.10.8") // Testing testImplementation("org.junit.jupiter:junit-jupiter-api:6.0.1") From 480d2d7a2d7c26db81418df31c74a3a24e2a4a15 Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Wed, 25 Mar 2026 04:08:49 +0700 Subject: [PATCH 30/32] Port to 26.1 --- build.gradle | 12 ++------ core/build.gradle | 5 ++-- .../playeranimcore/util/ServiceUtil.java | 26 ------------------ gradle.properties | 9 +++--- gradle/wrapper/gradle-wrapper.jar | Bin 46175 -> 48966 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- minecraft/build.gradle | 5 ++-- .../src/fabric/resources/fabric.mod.json | 2 +- .../playeranim/PlayerAnimLibService.java | 7 +++-- .../resources/META-INF/neoforge.mods.toml | 2 +- 11 files changed, 19 insertions(+), 53 deletions(-) delete mode 100644 core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java diff --git a/build.gradle b/build.gradle index 6ee88b91..7d530959 100644 --- a/build.gradle +++ b/build.gradle @@ -2,9 +2,9 @@ import org.redlance.dima_dencep.gradle.publish2discord.tasks.PublishDiscordTask import org.apache.commons.lang3.StringUtils plugins { - id "org.redlance.dima_dencep.gradle.PublishToDiscord" version "1.0.6" + id "org.redlance.dima_dencep.gradle.PublishToDiscord" version "1.0.8" id "xyz.wagyourtail.unimined" version "1.4.2+redlance.2" apply false - id "com.gradleup.shadow" version "9.3.1" apply false + id "com.gradleup.shadow" version "9.4.0" apply false } allprojects { @@ -24,14 +24,6 @@ allprojects { includeModule("org.lwjgl", "lwjgl-freetype") } } - maven { - 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") - } - } maven { name = "NeoForged" url = "https://maven.neoforged.net/releases" diff --git a/core/build.gradle b/core/build.gradle index bd9ce465..c0fc5a30 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,9 +1,8 @@ apply plugin: "java-library" dependencies { - api("com.zigythebird:mochafloats:$rootProject.molang_version") { - transitive = false - } + api("org.redlance.common-utils:services:$rootProject.commonutils_version") { transitive = false } + api("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false } compileOnlyApi("org.jetbrains:annotations:26.0.2") // Minecraft libs diff --git a/core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java b/core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java deleted file mode 100644 index b8f593a3..00000000 --- a/core/src/main/java/com/zigythebird/playeranimcore/util/ServiceUtil.java +++ /dev/null @@ -1,26 +0,0 @@ -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/gradle.properties b/gradle.properties index f703cfd2..86bb3f2a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,15 +3,16 @@ org.gradle.jvmargs=-Xmx2G org.gradle.parallel=true # Mod properties -mod_version = 1.1.6+dev +mod_version = 1.2.0 maven_group = com.zigythebird.playeranim archives_base_name = PlayerAnimationLib # Minecraft properties -minecraft_version = 26.1-snapshot-11 +minecraft_version = 26.1 # Dependencies fabric_loader_version = 0.18.4 -fabric_api_version = 0.143.11+26.1 -neoforge_version = 26.1.0.0-alpha.0+snapshot-11.20260304.010323 +fabric_api_version = 0.144.0+26.1 +neoforge_version = 26.1.0.1-beta molang_version = 5.0.0 +commonutils_version = 1.1.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 61285a659d17295f1de7c53e24fdf13ad755c379..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644 GIT binary patch delta 39855 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

SdO`o?U^bCPz6Ehh!k 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


Xdyd*p!l1Y@nCA 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index dbc3ce4a..c61a118f 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.4.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index adff685a..739907df 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 966051bc..3c482eca 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -62,9 +62,8 @@ dependencies { shadow(project(path: ":core")) { transitive = false } // Common - platformInclude("com.zigythebird:mochafloats:$rootProject.molang_version") { - transitive = false - } + platformInclude("org.redlance.common-utils:services:$rootProject.commonutils_version") { transitive = false } + platformInclude("com.zigythebird:mochafloats:$rootProject.molang_version") { transitive = false } // Fabric fabricImplementation fabricApi.fabricModule("fabric-command-api-v2", rootProject.fabric_api_version) diff --git a/minecraft/src/fabric/resources/fabric.mod.json b/minecraft/src/fabric/resources/fabric.mod.json index 72b20875..7a131c29 100644 --- a/minecraft/src/fabric/resources/fabric.mod.json +++ b/minecraft/src/fabric/resources/fabric.mod.json @@ -26,7 +26,7 @@ ], "depends": { "fabricloader": ">=0.18.4", - "minecraft": ">=26.1-alpha.6", + "minecraft": ">=26.1", "fabric-resource-loader-v1": "*", "fabric-command-api-v2": "*" }, diff --git a/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java b/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java index 6fd5acd7..c0be171f 100644 --- a/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java +++ b/minecraft/src/main/java/com/zigythebird/playeranim/PlayerAnimLibService.java @@ -1,9 +1,10 @@ package com.zigythebird.playeranim; -import com.zigythebird.playeranimcore.util.ServiceUtil; +import org.redlance.common.services.AdvancedService; +import org.redlance.common.services.ServiceUtils; -public interface PlayerAnimLibService extends ServiceUtil.ActiveService { - PlayerAnimLibService INSTANCE = ServiceUtil.loadService(PlayerAnimLibService.class); +public interface PlayerAnimLibService extends AdvancedService { + PlayerAnimLibService INSTANCE = ServiceUtils.loadService(PlayerAnimLibService.class); boolean isModLoaded(String id); } diff --git a/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml b/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml index 542f6547..bab12bc3 100644 --- a/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml +++ b/minecraft/src/neoforge/resources/META-INF/neoforge.mods.toml @@ -18,7 +18,7 @@ logoFile = "icon.png" [[dependencies.player_animation_library]] modId = "neoforge" type = "required" -versionRange = "[26.1.0.0-alpha,)" +versionRange = "[26.1.0.1-beta,)" ordering = "NONE" side = "BOTH" From 7a9d5026a265a82ca0fbdeadcd1b9d14992b2b5c Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Wed, 25 Mar 2026 04:10:13 +0700 Subject: [PATCH 31/32] Update CHANGELOG.md --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39ef53e5..c0c34d16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,5 @@ -- Fix head in first-person \ No newline at end of file +- Port to 26.1 +- Better RawAnimation +- Make get3DTransform return void +- Network V6 +- Bone refactor \ No newline at end of file From 3f04b3767f19846ca4f5ad7c8ba06a1c7de7e5cb Mon Sep 17 00:00:00 2001 From: dima_dencep Date: Wed, 25 Mar 2026 04:11:12 +0700 Subject: [PATCH 32/32] Update release.yml --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 85211da9..33625b23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,7 +54,7 @@ jobs: files: | ./minecraft/build/libs/PlayerAnimationLibMerged-*.jar - version-type: release + version-type: alpha loaders: | fabric