diff --git a/.github/ISSUE_TEMPLATE/api-bug-report.md b/.github/ISSUE_TEMPLATE/api-bug-report.md new file mode 100644 index 0000000..426fa3f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/api-bug-report.md @@ -0,0 +1,36 @@ +--- +name: API bug report +about: Issue about the API (not the buildscript) +title: "[API]" +labels: bug +assignees: KosmX + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Setup config (minecraft, modloader, libraries):** + - Minecraft version: [e.g. 1.19.3] + - Mod loader: [e.g. Fabric 0.14.11] + - PlayerAnimator Library version [e.g. 0.4.0+1.19.3] + - MC library version (e.g. Fabric API version) + +**Other mods (If you use other mods, please specify! it might be an incompatibility):** + +*Optional:* +** Used library methods, ideas (If you're a developer, what function is not working as expected)** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/buildscript-error.md b/.github/ISSUE_TEMPLATE/buildscript-error.md new file mode 100644 index 0000000..76f4162 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/buildscript-error.md @@ -0,0 +1,33 @@ +--- +name: Buildscript error +about: Something is wrong with buildscript +title: '' +labels: build +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Buildscript content or link to content (If you don't share your code, I cannot debug it):** +https://github.com/KosmX/fabricPlayerAnimatorExample/blob/1.19/build.gradle + +**To Reproduce** +Steps to reproduce the behavior: +1. Run `gradle runClient` +2. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Environment (please complete the following information):** + - OS: [e.g. Windows 11, Archlinux, Ubuntu 22.04] + - IDE [e.g. IntelliJ, Eclipse, vim+bash] + - Gradle version [e.g. 7.5.1] + - JDK version [e.g. 17.0.5 - Adoptium] + - gradle plugin [e.g. Fabric loom, ForgeGradle] (if I don't see it in your project) + - Minecraft, Loader: (Fabric 0.14.11+1.19.2) + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/library-crash.md b/.github/ISSUE_TEMPLATE/library-crash.md new file mode 100644 index 0000000..addee12 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/library-crash.md @@ -0,0 +1,32 @@ +--- +name: Library crash +about: User crash report +title: '' +labels: bug, library +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Crash report (please copy the whole crash report!)** +``` +Minecraft 1.19.3 +... +``` + +**Logs (if you have logs from that run, please share it):** +``` +... +``` diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 31e1af7..5f5defc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -5,13 +5,23 @@ on: workflow_dispatch: inputs: type: - description: 'alpha/beta/release' + description: 'release type' required: false - default: 'alpha' + type: choice + options: + - alpha + - beta + - release changelog: description: 'changelog' required: false default: '' + upload: + required: true + type: choice + options: + - true + - false # A workflow run is made up of one or more jobs that can run sequentially or in parallel @@ -37,8 +47,13 @@ jobs: java-version: '17' # Runs a single command using the runners shell + - name: validate gradle wrapper + uses: gradle/wrapper-validation-action@v1 + - name: make gradle wrapper executable + if: ${{ runner.os != 'Windows' }} + run: chmod +x ./gradlew - name: Publish package - run: gradle publish --no-daemon + run: ./gradlew publish --no-daemon env: KOSMX_MAVEN_USER: ${{ secrets.MAVEN_USER }} KOSMX_MAVEN_TOKEN: ${{ secrets.MAVEN_PASS }} @@ -47,3 +62,4 @@ jobs: CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }} CHANGELOG: ${{github.event.inputs.changelog}} RELEASE_TYPE: ${{github.event.inputs.type}} + UPLOAD_TO_PORTAL: ${{github.event.inputs.upload}} diff --git a/build.gradle b/build.gradle index d92b9a2..ba8fbd3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,11 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.0.+" apply false + id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false //Publishing id 'com.matthewprenger.cursegradle' version '1.4.0' apply false - id "com.modrinth.minotaur" version "2.4.3" apply false + id "com.modrinth.minotaur" version "2.8.7" apply false + id 'com.github.johnrengelman.shadow' version '8.1.1' apply false } architectury { @@ -60,6 +61,7 @@ ext.ENV = System.getenv() ext.cfType = ENV.RELEASE_TYPE ? ENV.RELEASE_TYPE : "alpha" ext.changes = ENV.CHANGELOG ? ENV.CHANGELOG.replaceAll("\\\\n", "\n") : "" ext.ENV = System.getenv() +boolean upload = ENV.UPLOAD_TO_PORTAL ? ENV.UPLOAD_TO_PORTAL == "true" : false ext.keysExists = ENV.KOSMX_MAVEN_USER != null || project.getGradle().getStartParameter().isDryRun() @@ -81,6 +83,8 @@ if(keysExists) { } publish { - finalizedBy(':minecraft:publishMod') + if (upload) { + finalizedBy(':minecraft:publishMod') + } } } \ No newline at end of file diff --git a/coreLib/build.gradle b/coreLib/build.gradle index 256607a..9b233a9 100644 --- a/coreLib/build.gradle +++ b/coreLib/build.gradle @@ -12,11 +12,11 @@ dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - compileOnly 'org.projectlombok:lombok:1.18.24' - annotationProcessor 'org.projectlombok:lombok:1.18.24' + compileOnly 'org.projectlombok:lombok:1.18.26' + annotationProcessor 'org.projectlombok:lombok:1.18.26' - testCompileOnly 'org.projectlombok:lombok:1.18.24' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.24' + testCompileOnly 'org.projectlombok:lombok:1.18.26' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.26' compileOnly 'org.jetbrains:annotations:23.0.0' } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/AnimUtils.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/AnimUtils.java index 06167f5..4af8a44 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/AnimUtils.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/AnimUtils.java @@ -19,8 +19,9 @@ public static AnimationStack getPlayerAnimLayer(Object player) throws IllegalArg } /** - * Disable first person animation see-through. - * Has no effect if using mod like FirstPersonModel + * Unused, use proper first person library instead + * will be removed after next release (1.1) */ + @Deprecated public static boolean disableFirstPersonAnim = true; } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/firstPerson/FirstPersonConfiguration.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/firstPerson/FirstPersonConfiguration.java new file mode 100644 index 0000000..167307c --- /dev/null +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/firstPerson/FirstPersonConfiguration.java @@ -0,0 +1,17 @@ +package dev.kosmx.playerAnim.api.firstPerson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class FirstPersonConfiguration { + boolean showRightArm = false; + boolean showLeftArm = false; + boolean showRightItem = true; + boolean showLeftItem = true; +} diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/firstPerson/FirstPersonMode.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/firstPerson/FirstPersonMode.java new file mode 100644 index 0000000..1894a0b --- /dev/null +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/firstPerson/FirstPersonMode.java @@ -0,0 +1,52 @@ +package dev.kosmx.playerAnim.api.firstPerson; + +import lombok.Getter; +import org.jetbrains.annotations.ApiStatus; + +public enum FirstPersonMode { + + /** + * The animation does not decide first person mode, this way, the animation will be transparent in first person mode. + */ + NONE(false), + /** + * Use the vanilla renderer, most of the time broken, if you use this, please check your animation + */ + VANILLA(true), + + /** + * Use the 3rd person player model (only arms/items) to render accurate first-person perspective + */ + THIRD_PERSON_MODEL(true), + + /** + * First person animation is DISABLED, vanilla idle will be active. + */ + DISABLED(false), + +; + @Getter + private final boolean enabled; + + + FirstPersonMode(boolean enabled) { + this.enabled = enabled; + } + + + + private static final ThreadLocal firstPersonPass = ThreadLocal.withInitial(() -> false); + + + /** + * @return is the current render pass a first person pass + */ + public static boolean isFirstPersonPass() { + return firstPersonPass.get(); + } + + @ApiStatus.Internal + public static void setFirstPersonPass(boolean newValue) { + firstPersonPass.set(newValue); + } +} diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationContainer.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationContainer.java index ec4dd53..db4dc6a 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationContainer.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationContainer.java @@ -1,19 +1,24 @@ package dev.kosmx.playerAnim.api.layered; import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.core.util.Vec3f; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * A container to make swapping animation object easier * It will clone the behaviour of the held animation - * + *

* you can put endless AnimationContainer into each other * @param Nullable animation */ public class AnimationContainer implements IAnimation { + @Nullable protected T anim; - public AnimationContainer(T anim) { + public AnimationContainer(@Nullable T anim) { this.anim = anim; } @@ -21,11 +26,11 @@ public AnimationContainer() { this.anim = null; } - public void setAnim(T newAnim) { + public void setAnim(@Nullable T newAnim) { this.anim = newAnim; } - public T getAnim() { + public @Nullable T getAnim() { return this.anim; } @@ -40,7 +45,7 @@ public void tick() { } @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { return anim == null ? value0 : anim.get3DTransform(modelName, type, tickDelta, value0); } @@ -48,4 +53,15 @@ public Vec3f get3DTransform(String modelName, TransformType type, float tickDelt public void setupAnim(float tickDelta) { if (this.anim != null) this.anim.setupAnim(tickDelta); } + + @Override + public @NotNull FirstPersonMode getFirstPersonMode(float tickDelta) { + return anim != null ? anim.getFirstPersonMode(tickDelta) : FirstPersonMode.NONE; + } + + // Override candidate + @Override + public @NotNull FirstPersonConfiguration getFirstPersonConfiguration(float tickDelta) { + return anim != null ? anim.getFirstPersonConfiguration(tickDelta) : IAnimation.super.getFirstPersonConfiguration(tickDelta); + } } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationStack.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationStack.java index 9811768..38b7c2b 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationStack.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/AnimationStack.java @@ -1,11 +1,13 @@ package dev.kosmx.playerAnim.api.layered; import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.core.util.Pair; import dev.kosmx.playerAnim.core.util.Vec3f; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.List; /** * Player animation stack, can contain multiple active or passive layers, will always be evaluated from the lowest index. @@ -13,7 +15,7 @@ */ public class AnimationStack implements IAnimation { - private final List> layers = new ArrayList<>(); + private final ArrayList> layers = new ArrayList<>(); /** * @@ -37,9 +39,9 @@ public void tick() { } @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { for (Pair layer : layers) { - if (layer.getRight().isActive()) { + if (layer.getRight().isActive() && (!FirstPersonMode.isFirstPersonPass() || layer.getRight().getFirstPersonMode(tickDelta).isEnabled())) { value0 = layer.getRight().get3DTransform(modelName, type, tickDelta, value0); } } @@ -88,4 +90,27 @@ public boolean removeLayer(int layerLevel) { return layers.removeIf(integerIAnimationPair -> integerIAnimationPair.getLeft() == layerLevel); } + @Override + public @NotNull FirstPersonMode getFirstPersonMode(float tickDelta) { + for (int i = layers.size(); i > 0;) { + Pair layer = layers.get(--i); + if (layer.getRight().isActive()) { // layer.right.requestFirstPersonMode(tickDelta).takeIf{ it != NONE }?.let{ return@requestFirstPersonMode it } + FirstPersonMode mode = layer.getRight().getFirstPersonMode(tickDelta); + if (mode != FirstPersonMode.NONE) return mode; + } + } + return FirstPersonMode.NONE; + } + + @Override + public @NotNull FirstPersonConfiguration getFirstPersonConfiguration(float tickDelta) { + for (int i = layers.size(); i > 0;) { + Pair layer = layers.get(--i); + if (layer.getRight().isActive()) { // layer.right.requestFirstPersonMode(tickDelta).takeIf{ it != NONE }?.let{ return@requestFirstPersonMode it } + FirstPersonMode mode = layer.getRight().getFirstPersonMode(tickDelta); + if (mode != FirstPersonMode.NONE) return layer.getRight().getFirstPersonConfiguration(tickDelta); + } + } + return IAnimation.super.getFirstPersonConfiguration(tickDelta); + } } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/IAnimation.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/IAnimation.java index e8d554e..dd1957d 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/IAnimation.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/IAnimation.java @@ -2,7 +2,10 @@ import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.core.util.Vec3f; +import org.jetbrains.annotations.NotNull; /** * An entry in {@link AnimationStack}, used to get the animated parts current transform @@ -30,7 +33,7 @@ default void tick(){} * @param value0 The value before the transform. For identity transform return with it. * @return The new transform value */ - Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0); + @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0); /** * Called before rendering a character @@ -38,4 +41,22 @@ default void tick(){} */ void setupAnim(float tickDelta); + /** + * Active animation can request first person render mode. + * @param tickDelta current tickDelta + * @return {@link FirstPersonMode} + */ + @NotNull + default FirstPersonMode getFirstPersonMode(float tickDelta) { + return FirstPersonMode.NONE; + } + + /** + * @param tickDelta + * @return current first person configuration, only requested when playing this animation + */ + @NotNull + default FirstPersonConfiguration getFirstPersonConfiguration(float tickDelta) { + return new FirstPersonConfiguration(); + } } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/KeyframeAnimationPlayer.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/KeyframeAnimationPlayer.java index 48e6953..d18c7b2 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/KeyframeAnimationPlayer.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/KeyframeAnimationPlayer.java @@ -1,16 +1,33 @@ package dev.kosmx.playerAnim.api.layered; import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.core.data.KeyframeAnimation; import dev.kosmx.playerAnim.core.util.*; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; /** - * Animation player for EmoteX emote format, - * It does not mean, you can not use it, It means Emotecraft uses this too! + *

KeyframeAnimationPlayer

+ * If you're here, you're probably looking for this (except if you want to animate from code)
+ * It plays {@link KeyframeAnimation} + *

+ * {@code new KeyframeAnimationPlayer(animation)} + * + *


+ * New FirstPerson mode is supported with chainable setters :D
+ * + * new KeyframeAnimationPlayer(animation)
+ * .setFirstPersonConfiguration(new FirstPersonConfiguration())
+ * .setFirstPersonMode(FirstPersonMode.THIRD_PERSON_MODEL);
+ *
+ * */ @SuppressWarnings({"unused", "ConstantConditions"}) public class KeyframeAnimationPlayer implements IAnimation { @@ -27,19 +44,42 @@ public class KeyframeAnimationPlayer implements IAnimation { public final HashMap bodyParts; public int perspective = 0; + + @Setter + @Accessors(chain = true) + @NotNull + private FirstPersonConfiguration firstPersonConfiguration = new FirstPersonConfiguration(); + + + @Override + public @NotNull FirstPersonConfiguration getFirstPersonConfiguration(float tickDelta) { + return firstPersonConfiguration; + } + + @Setter + @Accessors(chain = true) + @NotNull + private FirstPersonMode firstPersonMode = FirstPersonMode.NONE; + + + @Override + public @NotNull FirstPersonMode getFirstPersonMode(float tickDelta) { + return firstPersonMode; + } + /** * - * @param emote emote to play + * @param animation animation to play * @param t begin playing from tick * @param mutable if true, the part data will be copied as a construction step. * The copied version can be changed while playing the animation but the copy takes time. */ - public KeyframeAnimationPlayer(KeyframeAnimation emote, int t, boolean mutable) { - if (emote == null) throw new IllegalArgumentException("Animation can not be null"); - this.data = emote; + public KeyframeAnimationPlayer(@NotNull KeyframeAnimation animation, int t, boolean mutable) { + if (animation == null) throw new IllegalArgumentException("Animation can not be null"); + this.data = animation; - this.bodyParts = new HashMap<>(emote.getBodyParts().size()); - for(Map.Entry part:emote.getBodyParts().entrySet()){ + this.bodyParts = new HashMap<>(animation.getBodyParts().size()); + for(Map.Entry part:animation.getBodyParts().entrySet()){ this.bodyParts.put(part.getKey(), new BodyPart(mutable ? part.getValue().copy() : part.getValue())); } @@ -52,14 +92,14 @@ public KeyframeAnimationPlayer(KeyframeAnimation emote, int t, boolean mutable) /** * - * @param emote emote to play + * @param animation {@link KeyframeAnimation} to play * @param t begin playing from tick */ - public KeyframeAnimationPlayer(KeyframeAnimation emote, int t) { - this(emote, t, false); + public KeyframeAnimationPlayer(@NotNull KeyframeAnimation animation, int t) { + this(animation, t, false); } - public KeyframeAnimationPlayer(KeyframeAnimation animation) { + public KeyframeAnimationPlayer(@NotNull KeyframeAnimation animation) { this(animation, 0); } @@ -92,7 +132,7 @@ public boolean isActive() { } @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { BodyPart part = bodyParts.get(modelName); if (part == null) return value0; switch (type) { @@ -311,7 +351,7 @@ protected final float getValueFromKeyframes(KeyframeAnimation.KeyFrame before, K } if (tickBefore == tickAfter) return before.value; float f = (currentTick + tickDelta - (float) tickBefore) / (tickAfter - tickBefore); - return MathHelper.lerp(Easing.easingFromEnum(data.isEasingBefore ? after.ease : before.ease, f), before.value, after.value); + return MathHelper.lerp((data.isEasingBefore ? after.ease : before.ease).invoke(f), before.value, after.value); } } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/ModifierLayer.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/ModifierLayer.java index 0ae6cae..2983ad2 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/ModifierLayer.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/ModifierLayer.java @@ -1,12 +1,15 @@ package dev.kosmx.playerAnim.api.layered; import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.api.layered.modifier.AbstractFadeModifier; import dev.kosmx.playerAnim.api.layered.modifier.AbstractModifier; import dev.kosmx.playerAnim.core.util.Ease; import dev.kosmx.playerAnim.core.util.Vec3f; import lombok.Getter; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -49,17 +52,17 @@ public void tick() { } else if (animation != null) animation.tick(); } - public void addModifier(AbstractModifier modifier, int idx) { + public void addModifier(@NotNull AbstractModifier modifier, int idx) { modifier.setHost(this); modifiers.add(idx, modifier); this.linkModifiers(); } - public void addModifierBefore(AbstractModifier modifier) { + public void addModifierBefore(@NotNull AbstractModifier modifier) { this.addModifier(modifier, 0); } - public void addModifierLast(AbstractModifier modifier) { + public void addModifierLast(@NotNull AbstractModifier modifier) { this.addModifier(modifier, modifiers.size()); } @@ -80,7 +83,7 @@ public void setAnimation(@Nullable T animation) { * @param fadeModifier Fade modifier, use {@link AbstractFadeModifier#standardFadeIn(int, Ease)} for simple fade. * @param newAnimation New animation, can be null to fade into default state. */ - public void replaceAnimationWithFade(AbstractFadeModifier fadeModifier, @Nullable T newAnimation) { + public void replaceAnimationWithFade(@NotNull AbstractFadeModifier fadeModifier, @Nullable T newAnimation) { replaceAnimationWithFade(fadeModifier, newAnimation, false); } @@ -90,7 +93,7 @@ public void replaceAnimationWithFade(AbstractFadeModifier fadeModifier, @Nullabl * @param newAnimation New animation, can be null to fade into default state. * @param fadeFromNothing Do fade even if we go from nothing. (for KeyframeAnimation, it can be false by default) */ - public void replaceAnimationWithFade(AbstractFadeModifier fadeModifier, @Nullable T newAnimation, boolean fadeFromNothing) { + public void replaceAnimationWithFade(@NotNull AbstractFadeModifier fadeModifier, @Nullable T newAnimation, boolean fadeFromNothing) { if (fadeFromNothing || getAnimation() != null && getAnimation().isActive()) { fadeModifier.setBeginAnimation(this.getAnimation()); addModifierLast(fadeModifier); @@ -125,7 +128,7 @@ public boolean isActive() { } @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { if (modifiers.size() > 0) { return modifiers.get(0).get3DTransform(modelName, type, tickDelta, value0); } else if (animation != null) return animation.get3DTransform(modelName, type, tickDelta, value0); @@ -138,4 +141,20 @@ public void setupAnim(float tickDelta) { modifiers.get(0).setupAnim(tickDelta); } else if (animation != null) animation.setupAnim(tickDelta); } + + @Override + public @NotNull FirstPersonMode getFirstPersonMode(float tickDelta) { + if (modifiers.size() > 0) { + return modifiers.get(0).getFirstPersonMode(tickDelta); + } else if (animation != null) return animation.getFirstPersonMode(tickDelta); + return IAnimation.super.getFirstPersonMode(tickDelta); + } + + @Override + public @NotNull FirstPersonConfiguration getFirstPersonConfiguration(float tickDelta) { + if (modifiers.size() > 0) { + return modifiers.get(0).getFirstPersonConfiguration(tickDelta); + } else if (animation != null) return animation.getFirstPersonConfiguration(tickDelta); + return IAnimation.super.getFirstPersonConfiguration(tickDelta); + } } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/PlayerAnimationFrame.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/PlayerAnimationFrame.java index 0f12516..1eabc36 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/PlayerAnimationFrame.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/PlayerAnimationFrame.java @@ -3,6 +3,7 @@ import dev.kosmx.playerAnim.api.TransformType; import dev.kosmx.playerAnim.core.util.Pair; import dev.kosmx.playerAnim.core.util.Vec3f; +import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; @@ -65,7 +66,7 @@ public void resetPose() { @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { PlayerPart part = parts.get(modelName); if (part == null) return value0; switch (type) { diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/AbstractFadeModifier.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/AbstractFadeModifier.java index 9a7b803..c73a701 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/AbstractFadeModifier.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/AbstractFadeModifier.java @@ -3,10 +3,9 @@ import dev.kosmx.playerAnim.api.TransformType; import dev.kosmx.playerAnim.api.layered.IAnimation; import dev.kosmx.playerAnim.core.util.Ease; -import dev.kosmx.playerAnim.core.util.Easing; import dev.kosmx.playerAnim.core.util.Vec3f; import lombok.Setter; - +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -55,7 +54,7 @@ public void tick() { } @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { if (calculateProgress(tickDelta) > 1) { return super.get3DTransform(modelName, type, tickDelta, value0); } @@ -89,7 +88,7 @@ public static AbstractFadeModifier standardFadeIn(int length, Ease ease) { return new AbstractFadeModifier(length) { @Override protected float getAlpha(String modelName, TransformType type, float progress) { - return Easing.easingFromEnum(ease, progress); + return ease.invoke(progress); } }; } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/AdjustmentModifier.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/AdjustmentModifier.java new file mode 100644 index 0000000..15d2711 --- /dev/null +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/AdjustmentModifier.java @@ -0,0 +1,184 @@ +package dev.kosmx.playerAnim.api.layered.modifier; + +import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.layered.IAnimation; +import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer; +import dev.kosmx.playerAnim.core.util.Vec3f; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +/** + * Adjusts body parts during animations.
+ * Make sure this instance is the very first one, over the KeyframeAnimationPlayer, in the animation stack. + *

+ * Example use (adjusting the vertical angle of a custom attack animation): + *

+ * {@code
+ * new AdjustmentModifier((partName) -> {
+ *     float rotationX = 0;
+ *     float rotationY = 0;
+ *     float rotationZ = 0;
+ *     float offsetX = 0;
+ *     float offsetY = 0;
+ *     float offsetZ = 0;
+ *
+ *     var pitch = player.getPitch() / 2F;
+ *     pitch = (float) Math.toRadians(pitch);
+ *     switch (partName) {
+ *         case "body" -> {
+ *             rotationX = (-1F) * pitch;
+ *         }
+ *         case "rightArm", "leftArm" -> {
+ *             rotationX = pitch;
+ *         }
+ *         default -> {
+ *             return Optional.empty();
+ *         }
+ *     }
+ *
+ *     return Optional.of(new AdjustmentModifier.PartModifier(
+ *             new Vec3f(rotationX, rotationY, rotationZ),
+ *             new Vec3f(offsetX, offsetY, offsetZ))
+ *     );
+ * });
+ * }
+ * 
+ */ +public class AdjustmentModifier extends AbstractModifier { + public static final class PartModifier { + private final Vec3f rotation; + private final Vec3f offset; + + public PartModifier( + Vec3f rotation, + Vec3f offset + ) { + this.rotation = rotation; + this.offset = offset; + } + + public Vec3f rotation() { + return rotation; + } + + 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.offset, that.offset); + } + + @Override + public int hashCode() { + return Objects.hash(rotation, offset); + } + + @Override + public String toString() { + return "PartModifier[" + + "rotation=" + rotation + ", " + + "offset=" + offset + ']'; + } + } + + public boolean enabled = true; + + protected Function> source; + + public AdjustmentModifier(Function> source) { + this.source = source; + } + + protected float getFadeIn(float delta) { + float fadeIn = 1; + IAnimation animation = this.getAnim(); + if(animation instanceof KeyframeAnimationPlayer) { + KeyframeAnimationPlayer player = (KeyframeAnimationPlayer)anim; + float currentTick = player.getTick() + delta; + fadeIn = currentTick / (float) player.getData().beginTick; + fadeIn = Math.min(fadeIn, 1F); + } + return fadeIn; + } + + @Override + public void tick() { + super.tick(); + + if (remainingFadeout > 0) { + remainingFadeout -= 1; + if(remainingFadeout <= 0) { + instructedFadeout = 0; + } + } + } + + protected int instructedFadeout = 0; + private int remainingFadeout = 0; + + public void fadeOut(int fadeOut) { + instructedFadeout = fadeOut; + remainingFadeout = fadeOut + 1; + } + + protected float getFadeOut(float delta) { + float fadeOut = 1; + if(remainingFadeout > 0 && instructedFadeout > 0) { + float current = Math.max(remainingFadeout - delta , 0); + fadeOut = current / ((float)instructedFadeout); + fadeOut = Math.min(fadeOut, 1F); + return fadeOut; + } + IAnimation animation = this.getAnim(); + if(animation instanceof KeyframeAnimationPlayer) { + KeyframeAnimationPlayer player = (KeyframeAnimationPlayer)anim; + + float currentTick = player.getTick() + delta; + float position = (-1F) * (currentTick - player.getData().stopTick); + float length = player.getData().stopTick - player.getData().endTick; + if (length > 0) { + fadeOut = position / length; + fadeOut = Math.min(fadeOut, 1F); + } + } + return fadeOut; + } + + @Override + public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + if (!enabled) { + return super.get3DTransform(modelName, type, tickDelta, value0); + } + + Optional partModifier = source.apply(modelName); + + Vec3f modifiedVector = value0; + float fade = getFadeIn(tickDelta) * getFadeOut(tickDelta); + if (partModifier.isPresent()) { + modifiedVector = super.get3DTransform(modelName, type, tickDelta, modifiedVector); + return transformVector(modifiedVector, type, partModifier.get(), fade); + } else { + return super.get3DTransform(modelName, type, tickDelta, value0); + } + } + + protected Vec3f transformVector(Vec3f vector, TransformType type, PartModifier partModifier, float fade) { + switch (type) { + case POSITION: + return vector.add(partModifier.offset().scale(fade)); + case ROTATION: + return vector.add(partModifier.rotation().scale(fade)); + case BEND: + break; + } + return vector; + } +} \ No newline at end of file diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/MirrorModifier.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/MirrorModifier.java index c71d45a..cfa412d 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/MirrorModifier.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/MirrorModifier.java @@ -1,11 +1,13 @@ package dev.kosmx.playerAnim.api.layered.modifier; import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; import dev.kosmx.playerAnim.core.util.Vec3f; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.HashMap; @@ -25,8 +27,8 @@ public class MirrorModifier extends AbstractModifier { private boolean enabled = true; @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { - if (!enabled) return super.get3DTransform(modelName, type, tickDelta, value0); + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { + if (!isEnabled()) return super.get3DTransform(modelName, type, tickDelta, value0); if (mirrorMap.containsKey(modelName)) modelName = mirrorMap.get(modelName); value0 = transformVector(value0, type); @@ -35,6 +37,19 @@ public Vec3f get3DTransform(String modelName, TransformType type, float tickDelt return transformVector(vec3f, type); } + // Override candidate + @Override + public @NotNull FirstPersonConfiguration getFirstPersonConfiguration(float tickDelta) { + FirstPersonConfiguration configuration = super.getFirstPersonConfiguration(tickDelta); + if (isEnabled()) { + return new FirstPersonConfiguration() + .setShowLeftArm(configuration.isShowRightArm()) + .setShowRightArm(configuration.isShowLeftArm()) + .setShowLeftItem(configuration.isShowRightItem()) + .setShowRightItem(configuration.isShowLeftItem()); + } else return configuration; + } + protected Vec3f transformVector(Vec3f value0, TransformType type) { switch (type) { case POSITION: diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/SpeedModifier.java b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/SpeedModifier.java index a6a2a83..4c4ea52 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/SpeedModifier.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/api/layered/modifier/SpeedModifier.java @@ -3,6 +3,7 @@ import dev.kosmx.playerAnim.api.TransformType; import dev.kosmx.playerAnim.core.util.Vec3f; import lombok.NoArgsConstructor; +import org.jetbrains.annotations.NotNull; /** * Modifies the animation speed. @@ -49,7 +50,7 @@ protected void step(float delta) { } @Override - public Vec3f get3DTransform(String modelName, TransformType type, float tickDelta, Vec3f value0) { + public @NotNull Vec3f get3DTransform(@NotNull String modelName, @NotNull TransformType type, float tickDelta, @NotNull Vec3f value0) { return super.get3DTransform(modelName, type, shiftedDelta, value0); } } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/core/data/KeyframeAnimation.java b/coreLib/src/main/java/dev/kosmx/playerAnim/core/data/KeyframeAnimation.java index d22407b..b2bfa7d 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/core/data/KeyframeAnimation.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/core/data/KeyframeAnimation.java @@ -449,9 +449,14 @@ public int length() { * @return given keyframe */ public int findAtTick(int tick) { - int i = -1; - while (this.keyFrames.size() > i + 1 && this.keyFrames.get(i + 1).tick <= tick) { - i++; + int i = Collections.binarySearch(this.keyFrames, null, (frame, ignore) -> Integer.compare(frame.tick, tick)); + if (i < 0) { + i = -i - 2; + } + + // small correction for edge-case: it is possible to have two keyframes with the same tick in the array, in that case, I should return the later one. + if (i + 1 < keyFrames.size() && keyFrames.get(i + 1).tick == tick) { + return i + 1; } return i; } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/core/impl/AnimationProcessor.java b/coreLib/src/main/java/dev/kosmx/playerAnim/core/impl/AnimationProcessor.java index c77ba8f..4dee8a9 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/core/impl/AnimationProcessor.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/core/impl/AnimationProcessor.java @@ -2,10 +2,13 @@ import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.api.layered.IAnimation; import dev.kosmx.playerAnim.core.util.Pair; import dev.kosmx.playerAnim.core.util.Vec3f; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; /** * Tool to easily play animation to the player. @@ -37,6 +40,18 @@ public void setTickDelta(float tickDelta) { this.animation.setupAnim(tickDelta); } + public boolean isFirstPersonAnimationDisabled() { + return !animation.getFirstPersonMode(tickDelta).isEnabled(); + } + + public @NotNull FirstPersonMode getFirstPersonMode() { + return animation.getFirstPersonMode(tickDelta); + } + + public @NotNull FirstPersonConfiguration getFirstPersonConfiguration() { + return animation.getFirstPersonConfiguration(tickDelta); + } + public Pair getBend(String modelName) { Vec3f bendVec = this.get3DTransform(modelName, TransformType.BEND, Vec3f.ZERO); return new Pair<>(bendVec.getX(), bendVec.getY()); diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Ease.java b/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Ease.java index 0c40466..7c34d57 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Ease.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Ease.java @@ -1,35 +1,52 @@ package dev.kosmx.playerAnim.core.util; +import lombok.Getter; + /** * Easings form easings.net
* + constant + linear */ public enum Ease { - LINEAR(0), CONSTANT(1), - INSINE(6), OUTSINE(7), INOUTSINE(8), INCUBIC(9), OUTCUBIC(10), INOUTCUBIC(11), - INQUAD(12), OUTQUAD(13), INOUTQUAD(14), INQUART(15), OUTQUART(16), INOUTQUART(17), - INQUINT(18), OUTQUINT(19), INOUTQUINT(20), INEXPO(21), OUTEXPO(22), INOUTEXPO(23), - INCIRC(24), OUTCIRC(25), INOUTCIRC(26), INBACK(27), OUTBACK(28), INOUTBACK(29), - INELASTIC(30), OUTELASTIC(31), INOUTELASTIC(32), INBOUNCE(33), OUTBOUNCE(34), INOUTBOUNCE(35); + LINEAR(0, f -> f), CONSTANT(1, f -> 0f), + INSINE(6, Easing::inSine), OUTSINE(7, Easing::outSine), INOUTSINE(8, Easing::inOutSine), + INCUBIC(9, Easing::inCubic), OUTCUBIC(10, Easing::outCubic), INOUTCUBIC(11, Easing::inOutCubic), + INQUAD(12, Easing::inQuad), OUTQUAD(13, Easing::outQuad), INOUTQUAD(14, Easing::inOutQuad), + INQUART(15, Easing::inQuart), OUTQUART(16, Easing::outQuart), INOUTQUART(17, Easing::inOutQuart), + INQUINT(18, Easing::inQuint), OUTQUINT(19, Easing::outQuint), INOUTQUINT(20, Easing::inOutQuint), + INEXPO(21, Easing::inExpo), OUTEXPO(22, Easing::outExpo), INOUTEXPO(23, Easing::inOutExpo), + INCIRC(24, Easing::inCirc), OUTCIRC(25, Easing::outCirc), INOUTCIRC(26, Easing::inOutCirc), + INBACK(27, Easing::inBack), OUTBACK(28, Easing::outBack), INOUTBACK(29, Easing::inOutBack), + INELASTIC(30, Easing::inElastic), OUTELASTIC(31, Easing::outElastic), INOUTELASTIC(32, Easing::inOutElastic), + INBOUNCE(33, Easing::inBounce), OUTBOUNCE(34, Easing::outBack), INOUTBOUNCE(35, Easing::inOutBounce); + @Getter final byte id; + private final _F impl; /** - * @param id id + * @param id id + * @param impl implementation */ - Ease(byte id){ + Ease(byte id, _F impl){ this.id = id; + this.impl = impl; } /** - * @param id id + * @param id id + * @param impl implementation */ - Ease(int id) { - this((byte) id); + Ease(int id, _F impl) { + this((byte) id, impl); } - public byte getId() { - return id; + /** + * Run the easing + * @param f float between 0 and 1 + * @return ease(f) + */ + public float invoke(float f) { + return impl.invoke(f); } //To be able to send these as bytes instead of String names. @@ -39,4 +56,8 @@ public static Ease getEase(byte b){ } return LINEAR; } + + private interface _F { + float invoke(float f); + } } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Easing.java b/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Easing.java index 72f49bc..3051b59 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Easing.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/Easing.java @@ -1,86 +1,22 @@ package dev.kosmx.playerAnim.core.util; +import org.jetbrains.annotations.Nullable; + public class Easing { - /* + /** * Easing functions from easings.net * All function have a string codename * EasingFromString - * + *

* All function needs an input between 0 and 1 - * except + * + * @deprecated Just use {@link Ease#invoke(float)} */ - public static float easingFromEnum(Ease type, float f){ - switch(type){ - case INOUTSINE: - return inOutSine(f); - case INSINE: - return inSine(f); - case OUTSINE: - return outSine(f); - case INCUBIC: - return inCubic(f); - case OUTCUBIC: - return outCubic(f); - case LINEAR: - return f; - case INOUTCUBIC: - return inOutCubic(f); - case INQUAD: - return inQuad(f); - case INQUART: - return inQuart(f); - case OUTQUAD: - return outQuad(f); - case OUTQUART: - return outQuart(f); - case INOUTQUAD: - return inOutQuad(f); - case INOUTQUART: - return inOutQuart(f); - case INBACK: - return inBack(f); - case INCIRC: - return inCirc(f); - case INEXPO: - return inExpo(f); - case INQUINT: - return inQuint(f); - case OUTBACK: - return outBack(f); - case OUTCIRC: - return outCirc(f); - case OUTEXPO: - return outExpo(f); - case INBOUNCE: - return inBounce(f); - case OUTQUINT: - return outQuint(f); - case INELASTIC: - return inElastic(f); - case INOUTBACK: - return inOutBack(f); - case INOUTCIRC: - return inOutCirc(f); - case INOUTEXPO: - return inOutExpo(f); - case OUTBOUNCE: - return outBounce(f); - case INOUTQUINT: - return inOutQuint(f); - case OUTELASTIC: - return outElastic(f); - case INOUTBOUNCE: - return inOutBounce(f); - case INOUTELASTIC: - return inOutElastic(f); - case CONSTANT: - return 0; - default: - //CommonData.logger.warn("easing function unknown: " + type); - return f; - } + @Deprecated + public static float easingFromEnum(@Nullable Ease type, float f) { + return type != null ? type.invoke(f) : f; } /** @@ -90,11 +26,11 @@ public static float easingFromEnum(Ease type, float f){ public static Ease easeFromString(String string){ try{ if(string.equals("step"))return Ease.CONSTANT; - if(string.substring(0, 4).toUpperCase().equals("EASE")){ + if(string.substring(0, 4).equalsIgnoreCase("EASE")){ string = string.substring(4); } return Ease.valueOf(string.toUpperCase()); - }catch(Exception exception){ + } catch(Exception exception){ //Main.log(Level.ERROR, "Ease name unknown: \"" + string + "\" using linear", true); //Main.log(Level.WARN, exception.toString()); return Ease.LINEAR; @@ -195,7 +131,6 @@ public static float inOutCirc(float x){ } public static float inBack(float x){ - return c3 * x * x * x - c1 * x * x; } diff --git a/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/MathHelper.java b/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/MathHelper.java index 1d1a976..36401c1 100644 --- a/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/MathHelper.java +++ b/coreLib/src/main/java/dev/kosmx/playerAnim/core/util/MathHelper.java @@ -22,6 +22,11 @@ public static int colorHelper(int r, int g, int b, int a){ return ((a & 255) << 24) | ((r & 255) << 16) | ((g & 255) << 8) | (b & 255); //Sometimes minecraft uses ints as color... } + /** + * Clamp f to -Pi until Pi range + * @param f radians + * @return radians + */ public static float clampToRadian(float f){ final double a = Math.PI*2; double b = ((f + Math.PI)%a); diff --git a/coreLib/src/test/java/dev/kosmx/playerAnim/core/data/KeyframeAnimationTest.java b/coreLib/src/test/java/dev/kosmx/playerAnim/core/data/KeyframeAnimationTest.java new file mode 100644 index 0000000..bc089c4 --- /dev/null +++ b/coreLib/src/test/java/dev/kosmx/playerAnim/core/data/KeyframeAnimationTest.java @@ -0,0 +1,48 @@ +package dev.kosmx.playerAnim.core.data; + +import dev.kosmx.playerAnim.core.util.Ease; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Random; + +public class KeyframeAnimationTest { + @Test + public void testKeyframeAnimation() { + KeyframeAnimation.StateCollection.State state = new KeyframeAnimation.StateCollection(0).x; + // Easy case + state.addKeyFrame(1, 0, Ease.CONSTANT); + state.addKeyFrame(5, 0, Ease.CONSTANT); + state.addKeyFrame(10, 10, Ease.CONSTANT); + state.addKeyFrame(10, 10, Ease.CONSTANT); + + state.addKeyFrame(15, 10, Ease.CONSTANT); + + verify(state); + state.getKeyFrames().clear(); + + + // random case + Random random = new Random(); + + for (int i = 0; i < 10000; i += random.nextInt(100)) { + state.addKeyFrame(i, i, Ease.CONSTANT); + } + + verify(state); + } + + public static void verify(KeyframeAnimation.StateCollection.State state) { + + for (int t = 0; t < state.getKeyFrames().size(); t++) { + // Iterative, 100% works algorithm + + int i = -1; + while (state.getKeyFrames().size() > i + 1 && state.getKeyFrames().get(i + 1).tick <= t) { + i++; + } + + Assertions.assertEquals(i, state.findAtTick(t), "KeyframeAnimationTest failed at tick " + t); + } + } +} diff --git a/gradle.properties b/gradle.properties index fef90ba..90da2cb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,16 @@ -org.gradle.jvmargs=-Xmx2048M +org.gradle.jvmargs=-Xmx4G minecraft_version=1.16.5 enabled_platforms=fabric,forge archives_base_name=player-animation-lib #Major: API break, Minor: non-breaking but significant, Patch: minor bugfix/change + MC implementation fix -mod_version=0.4.0 +mod_version=1.0.2 maven_group=dev.kosmx.player-anim - fabric_loader_version=0.14.9 fabric_api_version=0.42.0+1.16 forge_version=1.16.5-36.2.39 -bendy_lib=1.2.1 +bendy_lib=2.1.1 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927..d64cd49 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661..a441313 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 index 1b6c787..1aa94a4 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd3..93e3f59 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/IBendHelper.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/IBendHelper.java deleted file mode 100644 index e1a10e4..0000000 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/IBendHelper.java +++ /dev/null @@ -1,74 +0,0 @@ -package dev.kosmx.playerAnim.impl; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; -import dev.kosmx.playerAnim.core.impl.AnimationProcessor; -import dev.kosmx.playerAnim.core.util.Pair; -import dev.kosmx.playerAnim.core.util.SetableSupplier; -import dev.kosmx.playerAnim.impl.animation.BendHelper; -import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.core.Direction; - -import javax.annotation.Nullable; - -public interface IBendHelper { - - static void rotateMatrixStack(PoseStack matrices, Pair pair){ - float offset = 0.375f; - matrices.translate(0, offset, 0); - float bend = pair.getRight(); - float axisf = - pair.getLeft(); - Vector3f axis = new Vector3f((float) Math.cos(axisf), 0, (float) Math.sin(axisf)); - //return this.setRotation(axis.getRadialQuaternion(bend)); - matrices.mulPose(axis.rotation(bend)); - matrices.translate(0, - offset, 0); - } - - static IBendHelper create(ModelPart modelPart, boolean isUpperPart, @Nullable SetableSupplier emote){ - return Helper.isBendEnabled() ? BendHelper.createNew(modelPart, isUpperPart, emote) : new DummyBendable(); - } - - static IBendHelper create(ModelPart modelPart, @Nullable SetableSupplier emote){ - return create(modelPart, false, emote); - } - - static IBendHelper create(ModelPart modelPart, boolean isUpperPart) { - return create(modelPart, isUpperPart, null); - } - - void addBendedCuboid(int i, int i1, int i2, int i3, int i4, int i5, float scale, Direction up); - - void setAnimation(SetableSupplier emoteSupplier); - - default void bend(Pair vec) { - this.bend(vec.getLeft(), vec.getRight()); - } - - void bend(float a, float b); - - void copyBend(IBendHelper torso); - - - class DummyBendable implements IBendHelper { - - @Override - public void addBendedCuboid(int i, int i1, int i2, int i3, int i4, int i5, float scale, Direction up) { - - } - - @Override - public void setAnimation(SetableSupplier emoteSupplier) { - - } - - @Override - public void bend(float a, float b) { - - } - - @Override - public void copyBend(IBendHelper torso) { - - } - } -} diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/IMutableModel.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/IMutableModel.java index d04dcbf..2e5a81a 100644 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/IMutableModel.java +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/IMutableModel.java @@ -2,6 +2,8 @@ import dev.kosmx.playerAnim.core.impl.AnimationProcessor; import dev.kosmx.playerAnim.core.util.SetableSupplier; +import dev.kosmx.playerAnim.impl.animation.IBendHelper; + import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/AnimationApplier.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/AnimationApplier.java index 5e62cfe..9f81235 100644 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/AnimationApplier.java +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/AnimationApplier.java @@ -4,6 +4,7 @@ import dev.kosmx.playerAnim.api.TransformType; import dev.kosmx.playerAnim.api.layered.IAnimation; import dev.kosmx.playerAnim.core.impl.AnimationProcessor; +import dev.kosmx.playerAnim.core.util.MathHelper; import dev.kosmx.playerAnim.core.util.Pair; import dev.kosmx.playerAnim.core.util.Vec3f; import net.minecraft.client.model.geom.ModelPart; @@ -20,10 +21,22 @@ public void updatePart(String partName, ModelPart part) { part.x = pos.getX(); part.y = pos.getY(); part.z = pos.getZ(); - Vec3f rot = this.get3DTransform(partName, TransformType.ROTATION, new Vec3f(part.xRot, part.yRot, part.zRot)); + Vec3f rot = this.get3DTransform(partName, TransformType.ROTATION, new Vec3f( // clamp guards + MathHelper.clampToRadian(part.xRot), + MathHelper.clampToRadian(part.yRot), + MathHelper.clampToRadian(part.zRot))); part.xRot = rot.getX(); part.yRot = rot.getY(); part.zRot = rot.getZ(); + if (!partName.equals("head")) { + if (partName.equals("torso")) { + Pair torsoBend = getBend(partName); + Pair bodyBend = getBend("body"); + IBendHelper.INSTANCE.bend(part, new Pair<>(torsoBend.getLeft() + bodyBend.getLeft(), torsoBend.getRight() + bodyBend.getRight())); + } else { + IBendHelper.INSTANCE.bend(part, getBend(partName)); + } + } } -} +} \ No newline at end of file diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/BendHelper.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/BendHelper.java index 73f395a..72b8e8b 100644 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/BendHelper.java +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/BendHelper.java @@ -1,99 +1,40 @@ package dev.kosmx.playerAnim.impl.animation; -import com.mojang.math.Matrix4f; -import dev.kosmx.playerAnim.core.impl.AnimationProcessor; -import dev.kosmx.playerAnim.core.util.SetableSupplier; -import dev.kosmx.playerAnim.impl.IBendHelper; -import dev.kosmx.playerAnim.impl.IUpperPartHelper; -import io.github.kosmx.bendylib.IModelPart; -import io.github.kosmx.bendylib.MutableModelPart; +import dev.kosmx.playerAnim.core.util.Pair; +import io.github.kosmx.bendylib.ModelPartAccessor; import io.github.kosmx.bendylib.impl.BendableCuboid; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.core.Direction; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.NotNull; @ApiStatus.Internal -public class BendHelper extends MutableModelPart implements IBendHelper { +public class BendHelper implements IBendHelper { - @Nullable - protected SetableSupplier emote; - protected float axis = 0; - protected float angl = 0; - - - public BendHelper(ModelPart modelPart, boolean isUpperPart, @Nullable SetableSupplier emote){ - super(modelPart); - this.emote = emote; - ((IModelPart) modelPart).mutate(this); - ((IUpperPartHelper) modelPart).setUpperPart(isUpperPart); - } - - /** - * function to avoid impossible type resolve - */ - public static IBendHelper createNew(ModelPart modelPart, boolean isUpper, @Nullable SetableSupplier emote) { - return new BendHelper(modelPart, isUpper, emote); - } - - @Override - public String modId(){ - return "playerAnimator"; - } - - - /** - * This mod has always 4 priority, but not always active. - * - * @return 0 - */ @Override - public int getPriority(){ - return 4; - } - - public Matrix4f getMatrix4f(){ - return ((BendableCuboid) this.iCuboids.get(0)).getLastPosMatrix(); - } - - public BendableCuboid getCuboid(){ - return (BendableCuboid) this.iCuboids.get(0); - } - - @Override - public boolean isActive(){ - return this.emote != null && this.emote.get() != null && this.emote.get().isActive() && angl != 0; - } - - @Override - public void setAnimation(@Nullable SetableSupplier emote){ - this.emote = emote; - } - - @Nullable - public SetableSupplier getEmote(){ - return emote; + public void bend(ModelPart modelPart, float axis, float rotation){ + // Don't enable bend until rotation is bigger than epsilon. This should avoid unnecessary heavy calculations. + if (Math.abs(rotation) >= 0.0001f) { + ModelPartAccessor.optionalGetCuboid(modelPart, 0).ifPresent(mutableCuboid -> ((BendableCuboid) mutableCuboid.getAndActivateMutator("bend")).applyBend(axis, rotation)); + } else { + ModelPartAccessor.optionalGetCuboid(modelPart, 0).ifPresent(mutableCuboid -> mutableCuboid.getAndActivateMutator(null)); + } } @Override - public void bend(float a, float b){ - this.axis = a; - this.angl = b; - ((BendableCuboid) this.iCuboids.get(0)).applyBend(a, b); - } - - - public void copyBend(@NotNull IBendHelper mutableModelPart){ - if (mutableModelPart instanceof BendHelper) { - BendHelper modelPart = (BendHelper) mutableModelPart; - this.bend(modelPart.axis, modelPart.angl); + public void bend(ModelPart modelPart, @Nullable Pair pair){ + if(pair != null) { + this.bend(modelPart, pair.getLeft(), pair.getRight()); + } + else { + //ModelPartAccessor.getCuboid(modelPart, 0).getAndActivateMutator(null); + ModelPartAccessor.optionalGetCuboid(modelPart, 0).ifPresent(mutableCuboid -> mutableCuboid.getAndActivateMutator(null)); } } @Override - public void addBendedCuboid(int i, int i1, int i2, int i3, int i4, int i5, float scale, Direction up) { - this.addCuboid(i, i1, i2, i3, i4, i5, scale, up); + public void initBend(ModelPart modelPart, Direction direction) { + ModelPartAccessor.optionalGetCuboid(modelPart, 0).ifPresent(mutableModelPart -> mutableModelPart.registerMutator("bend", data -> new BendableCuboid.Builder().setDirection(direction).build(data))); } -} +} \ No newline at end of file diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/IBendHelper.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/IBendHelper.java new file mode 100644 index 0000000..e0cdf0b --- /dev/null +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/impl/animation/IBendHelper.java @@ -0,0 +1,51 @@ +package dev.kosmx.playerAnim.impl.animation; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import dev.kosmx.playerAnim.core.util.Pair; +import dev.kosmx.playerAnim.impl.Helper; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.core.Direction; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public interface IBendHelper { + + IBendHelper INSTANCE = Helper.isBendEnabled() ? new BendHelper() : new DummyBendable(); + static void rotateMatrixStack(PoseStack matrices, Pair pair){ + float offset = 0.375f; + matrices.translate(0, offset, 0); + float bend = pair.getRight(); + float axisf = - pair.getLeft(); + Vector3f axis = new Vector3f((float) Math.cos(axisf), 0, (float) Math.sin(axisf)); + //return this.setRotation(axis.getRadialQuaternion(bend)); + matrices.mulPose(axis.rotation(bend)); + matrices.translate(0, - offset, 0); + } + + void bend(ModelPart modelPart, float a, float b); + + void bend(ModelPart modelPart, @Nullable Pair pair); + + void initBend(ModelPart modelPart, Direction direction); + + class DummyBendable implements IBendHelper { + + @Override + public void bend(ModelPart modelPart, float a, float b) { + + } + + @Override + public void bend(ModelPart modelPart, @org.jetbrains.annotations.Nullable Pair pair) { + + } + + @Override + public void initBend(ModelPart modelPart, Direction direction) { + + } + } +} \ No newline at end of file diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/minecraftApi/layers/LeftHandedHelperModifier.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/minecraftApi/layers/LeftHandedHelperModifier.java new file mode 100644 index 0000000..1b08625 --- /dev/null +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/minecraftApi/layers/LeftHandedHelperModifier.java @@ -0,0 +1,22 @@ +package dev.kosmx.playerAnim.minecraftApi.layers; + +import dev.kosmx.playerAnim.api.layered.modifier.MirrorModifier; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.Player; + +/** + * Left-handedness helper + * If enabled, automatically mirror all animation if player is left-handed + */ +public class LeftHandedHelperModifier extends MirrorModifier { + private final Player player; + + public LeftHandedHelperModifier(Player player) { + this.player = player; + } + + @Override + public boolean isEnabled() { + return super.isEnabled() && player.getMainArm() == HumanoidArm.LEFT; + } +} diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/BipedEntityModelMixin.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/BipedEntityModelMixin.java index 01e0623..ab853be 100644 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/BipedEntityModelMixin.java +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/BipedEntityModelMixin.java @@ -6,67 +6,50 @@ import dev.kosmx.playerAnim.core.util.SetableSupplier; import dev.kosmx.playerAnim.impl.Helper; import dev.kosmx.playerAnim.impl.IMutableModel; -import dev.kosmx.playerAnim.impl.IBendHelper; +import dev.kosmx.playerAnim.impl.animation.IBendHelper; import dev.kosmx.playerAnim.impl.IUpperPartHelper; import net.minecraft.client.model.AgeableListModel; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.client.renderer.RenderType; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.LivingEntity; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.function.Function; - @Mixin(HumanoidModel.class) public abstract class BipedEntityModelMixin extends AgeableListModel implements IMutableModel { + @Final @Shadow public ModelPart rightArm; + @Final @Shadow public ModelPart leftArm; + @Final + @Shadow + public ModelPart rightLeg; + @Final + @Shadow + public ModelPart leftLeg; @Unique private SetableSupplier animation = new SetableSupplier<>(); - @Unique - private IBendHelper mutatedTorso; - @Unique - private IBendHelper mutatedRightArm; - @Unique - private IBendHelper mutatedLeftArm; - @Unique - private IBendHelper mutatedLeftLeg; - @Unique - private IBendHelper mutatedRightLeg; - - @Inject(method = "(Ljava/util/function/Function;FFII)V", at = @At("RETURN")) - private void initBend(Function texturedLayerFactory, float scale, float pivotY, int textureWidth, int textureHeight, CallbackInfo ci){ - mutatedLeftArm = IBendHelper.create(this.leftArm, true); - mutatedLeftLeg = IBendHelper.create(this.leftLeg, false); - mutatedRightArm = IBendHelper.create(this.rightArm, true); - mutatedRightLeg = IBendHelper.create(this.rightLeg, false); - mutatedTorso = IBendHelper.create(this.body, false); - ((IUpperPartHelper) this.head).setUpperPart(true); - ((IUpperPartHelper) this.hat).setUpperPart(true); - - mutatedTorso.addBendedCuboid(- 4, 0, - 2, 8, 12, 4, scale, Direction.DOWN); - mutatedRightLeg.addBendedCuboid(- 2, 0, - 2, 4, 12, 4, scale, Direction.UP); - mutatedLeftLeg.addBendedCuboid(- 2, 0, - 2, 4, 12, 4, scale, Direction.UP); - - mutatedLeftArm.addBendedCuboid(- 1, - 2, - 2, 4, 12, 4, scale, Direction.UP); - mutatedRightArm.addBendedCuboid(- 3, - 2, - 2, 4, 12, 4, scale, Direction.UP); + @Inject(method = "(F)V", at = @At("RETURN")) + private void initBend(CallbackInfo ci){ + IBendHelper.INSTANCE.initBend(body, Direction.DOWN); + IBendHelper.INSTANCE.initBend(rightArm, Direction.UP); + IBendHelper.INSTANCE.initBend(leftArm, Direction.UP); + IBendHelper.INSTANCE.initBend(rightLeg, Direction.UP); + IBendHelper.INSTANCE.initBend(leftLeg, Direction.UP); + ((IUpperPartHelper)rightArm).setUpperPart(true); + ((IUpperPartHelper)leftArm).setUpperPart(true); + ((IUpperPartHelper)head).setUpperPart(true); + ((IUpperPartHelper)hat).setUpperPart(true); } @Override - public void setEmoteSupplier(SetableSupplier emoteSupplier) { - this.mutatedLeftLeg.setAnimation(emoteSupplier); - this.mutatedRightLeg.setAnimation(emoteSupplier); - this.mutatedLeftArm.setAnimation(emoteSupplier); - this.mutatedRightArm.setAnimation(emoteSupplier); - this.mutatedTorso.setAnimation(emoteSupplier); + public void setEmoteSupplier(SetableSupplier emoteSupplier){ this.animation = emoteSupplier; } @@ -74,15 +57,6 @@ public void setEmoteSupplier(SetableSupplier emoteSupplier) private void copyMutatedAttributes(HumanoidModel bipedEntityModel, CallbackInfo ci){ if(animation != null) { ((IMutableModel) bipedEntityModel).setEmoteSupplier(animation); - if (animation.get() != null && animation.get().isActive()) { - IMutableModel thisWithMixin = (IMutableModel) bipedEntityModel; - AnimationProcessor playedEmote = animation.get(); - thisWithMixin.getTorso().bend(playedEmote.getBend("torso")); - thisWithMixin.getLeftArm().bend(playedEmote.getBend("leftArm")); - thisWithMixin.getLeftLeg().bend(playedEmote.getBend("leftLeg")); - thisWithMixin.getRightArm().bend(playedEmote.getBend("rightArm")); - thisWithMixin.getRightLeg().bend(playedEmote.getBend("rightLeg")); - } } } @@ -118,72 +92,15 @@ public void renderToBuffer(PoseStack matrices, VertexConsumer vertices, int ligh } else super.renderToBuffer(matrices, vertices, light, overlay, red, green, blue, alpha); } + @Final @Shadow public ModelPart body; - @Shadow - public ModelPart head; + @Shadow @Final public ModelPart head; - @Shadow - public ModelPart hat; - - @Shadow - public ModelPart leftLeg; - - @Shadow - public ModelPart rightLeg; + @Shadow @Final public ModelPart hat; @Override public SetableSupplier getEmoteSupplier(){ return animation; } - - @Override - public IBendHelper getTorso() { - return mutatedTorso; - } - - @Override - public IBendHelper getRightArm() { - return mutatedRightArm; - } - - @Override - public IBendHelper getLeftArm() { - return mutatedLeftArm; - } - - @Override - public IBendHelper getRightLeg() { - return mutatedRightLeg; - } - - @Override - public IBendHelper getLeftLeg() { - return mutatedLeftLeg; - } - - @Override - public void setTorso(IBendHelper v) { - mutatedTorso = v; - } - - @Override - public void setRightArm(IBendHelper v) { - mutatedRightArm= v; - } - - @Override - public void setLeftArm(IBendHelper v) { - mutatedLeftArm = v; - } - - @Override - public void setRightLeg(IBendHelper v) { - mutatedRightLeg = v; - } - - @Override - public void setLeftLeg(IBendHelper v) { - mutatedLeftLeg = v; - } -} +} \ No newline at end of file diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/LivingEntityRenderRedirect_bendOnly.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/LivingEntityRenderRedirect_bendOnly.java index 4042c3a..045c8ca 100644 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/LivingEntityRenderRedirect_bendOnly.java +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/LivingEntityRenderRedirect_bendOnly.java @@ -3,8 +3,8 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.kosmx.playerAnim.impl.IAnimatedPlayer; import dev.kosmx.playerAnim.impl.IUpperPartHelper; +import dev.kosmx.playerAnim.impl.animation.IBendHelper; import dev.kosmx.playerAnim.impl.Helper; -import dev.kosmx.playerAnim.impl.IBendHelper; import net.minecraft.client.model.EntityModel; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerModelMixin.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerModelMixin.java index bc62710..4f28fc2 100644 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerModelMixin.java +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerModelMixin.java @@ -1,13 +1,13 @@ package dev.kosmx.playerAnim.mixin; import dev.kosmx.playerAnim.core.impl.AnimationProcessor; -import dev.kosmx.playerAnim.core.util.Pair; import dev.kosmx.playerAnim.core.util.SetableSupplier; import dev.kosmx.playerAnim.impl.IAnimatedPlayer; import dev.kosmx.playerAnim.impl.IMutableModel; import dev.kosmx.playerAnim.impl.IPlayerModel; +import dev.kosmx.playerAnim.impl.IUpperPartHelper; import dev.kosmx.playerAnim.impl.animation.AnimationApplier; -import dev.kosmx.playerAnim.impl.IBendHelper; +import dev.kosmx.playerAnim.impl.animation.IBendHelper; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.PlayerModel; import net.minecraft.client.model.geom.ModelPart; @@ -40,69 +40,34 @@ public class PlayerModelMixin extends HumanoidModel i @Unique private boolean firstPersonNext = false; - - //private BendableModelPart mutatedTorso; - @Unique - - private IBendHelper mutatedJacket; - @Unique - - private IBendHelper mutatedRightSleeve; - @Unique - - private IBendHelper mutatedLeftSleeve; - @Unique - - private IBendHelper mutatedRightPantLeg; - @Unique - - private IBendHelper mutatedLeftPantLeg; - - @Unique - private IMutableModel thisWithMixin; public PlayerModelMixin(float f) { super(f); } - //private BendHelper mutatedTorso; - //private MutableModelPart head :D ... it were be funny XD - @Inject(method = "", at = @At("RETURN")) - private void initBendableStuff(float scale, boolean thinArms, CallbackInfo ci){ - thisWithMixin = (IMutableModel) this; + private void initBendableStuff(float f, boolean bl, CallbackInfo ci){ + IMutableModel thisWithMixin = (IMutableModel) this; emoteSupplier.set(null); - this.mutatedJacket = IBendHelper.create(this.jacket, false, emoteSupplier); - this.mutatedRightSleeve = IBendHelper.create(this.rightSleeve, true, emoteSupplier); - this.mutatedLeftSleeve = IBendHelper.create(this.leftSleeve, true, emoteSupplier); - this.mutatedRightPantLeg = IBendHelper.create(this.rightPants, emoteSupplier); - this.mutatedLeftPantLeg = IBendHelper.create(this.leftPants, emoteSupplier); - - thisWithMixin.setLeftArm(IBendHelper.create(this.leftArm, true)); - thisWithMixin.setRightArm(IBendHelper.create(this.rightArm, true)); thisWithMixin.setEmoteSupplier(emoteSupplier); - thisWithMixin.setLeftLeg(IBendHelper.create(this.leftLeg, false, emoteSupplier)); - thisWithMixin.getLeftLeg().addBendedCuboid(- 2, 0, - 2, 4, 12, 4, scale, Direction.UP); - - mutatedJacket.addBendedCuboid(- 4, 0, - 2, 8, 12, 4, scale + 0.25f, Direction.DOWN); - mutatedRightPantLeg.addBendedCuboid(- 2, 0, - 2, 4, 12, 4, scale + 0.25f, Direction.UP); - mutatedLeftPantLeg.addBendedCuboid(- 2, 0, - 2, 4, 12, 4, scale + 0.25f, Direction.UP); - if(thinArms){ - thisWithMixin.getLeftArm().addBendedCuboid(- 1, - 2, - 2, 3, 12, 4, scale, Direction.UP); - thisWithMixin.getRightArm().addBendedCuboid(- 2, - 2, - 2, 3, 12, 4, scale, Direction.UP); - mutatedLeftSleeve.addBendedCuboid(- 1, - 2, - 2, 3, 12, 4, scale + 0.25f, Direction.UP); - mutatedRightSleeve.addBendedCuboid(- 2, - 2, - 2, 3, 12, 4, scale + 0.25f, Direction.UP); - }else{ - thisWithMixin.getLeftArm().addBendedCuboid(- 1, - 2, - 2, 4, 12, 4, scale, Direction.UP); - thisWithMixin.getRightArm().addBendedCuboid(- 3, - 2, - 2, 4, 12, 4, scale, Direction.UP); - mutatedLeftSleeve.addBendedCuboid(- 1, - 2, - 2, 4, 12, 4, scale + 0.25f, Direction.UP); - mutatedRightSleeve.addBendedCuboid(- 3, - 2, - 2, 4, 12, 4, scale + 0.25f, Direction.UP); - } + addBendMutator(this.jacket, Direction.DOWN); + addBendMutator(this.rightPants, Direction.UP); + addBendMutator(this.rightSleeve, Direction.UP); + addBendMutator(this.leftPants, Direction.UP); + addBendMutator(this.leftSleeve, Direction.UP); + + ((IUpperPartHelper)rightSleeve).setUpperPart(true); + ((IUpperPartHelper)leftSleeve).setUpperPart(true); } + @Unique + private void addBendMutator(ModelPart part, Direction d){ + IBendHelper.INSTANCE.initBend(part, d); + } + @Unique private void setDefaultPivot(){ this.leftLeg.setPos(1.9F, 12.0F, 0.0F); @@ -147,26 +112,22 @@ private void setEmote(T livingEntity, float f, float g, float h, float i, float emote.updatePart("torso", this.body); - Pair torsoBend = emote.getBend("torso"); - Pair bodyBend = emote.getBend("body"); - thisWithMixin.getTorso().bend(new Pair<>(torsoBend.getLeft() + bodyBend.getLeft(), torsoBend.getRight() + bodyBend.getRight())); - thisWithMixin.getLeftArm().bend(emote.getBend("leftArm")); - thisWithMixin.getLeftLeg().bend(emote.getBend("leftLeg")); - thisWithMixin.getRightArm().bend(emote.getBend("rightArm")); - thisWithMixin.getRightLeg().bend(emote.getBend("rightLeg")); - - mutatedJacket.copyBend(thisWithMixin.getTorso()); - mutatedLeftPantLeg.copyBend(thisWithMixin.getLeftLeg()); - mutatedRightPantLeg.copyBend(thisWithMixin.getRightLeg()); - mutatedLeftSleeve.copyBend(thisWithMixin.getLeftArm()); - mutatedRightSleeve.copyBend(thisWithMixin.getRightArm()); } else { firstPersonNext = false; emoteSupplier.set(null); + resetBend(this.body); + resetBend(this.leftArm); + resetBend(this.rightArm); + resetBend(this.leftLeg); + resetBend(this.rightLeg); } } + @Unique + private static void resetBend(ModelPart part) { + IBendHelper.INSTANCE.bend(part, null); + } /** * @author KosmX - Player Animator library diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerRendererMixin.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerRendererMixin.java index 3bf8153..817d03b 100644 --- a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerRendererMixin.java +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/PlayerRendererMixin.java @@ -2,11 +2,13 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import dev.kosmx.playerAnim.api.AnimUtils; import dev.kosmx.playerAnim.api.TransformType; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.core.util.Vec3f; import dev.kosmx.playerAnim.impl.IAnimatedPlayer; import dev.kosmx.playerAnim.impl.IPlayerModel; +import net.minecraft.client.Minecraft; import net.minecraft.client.model.PlayerModel; import net.minecraft.client.model.geom.ModelPart; import dev.kosmx.playerAnim.impl.animation.AnimationApplier; @@ -16,6 +18,7 @@ import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.client.renderer.entity.player.PlayerRenderer; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -26,6 +29,49 @@ public abstract class PlayerRendererMixin extends LivingEntityRenderer entityModel, float f) { super(entityRenderDispatcher, entityModel, f); } + @Inject(method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/LivingEntityRenderer;render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V")) + private void hideBonesInFirstPerson(AbstractClientPlayer entity, + float f, float g, PoseStack matrixStack, + MultiBufferSource vertexConsumerProvider, + int i, CallbackInfo ci) { + if (FirstPersonMode.isFirstPersonPass()) { + AnimationApplier animationApplier = ((IAnimatedPlayer) entity).playerAnimator_getAnimation(); + FirstPersonConfiguration config = animationApplier.getFirstPersonConfiguration(); + + if (entity == Minecraft.getInstance().getCameraEntity()) { + // Hiding all parts, because they should not be visible in first person + setAllPartsVisible(false); + // Showing arms based on configuration + boolean showRightArm = config.isShowRightArm(); + boolean showLeftArm = config.isShowLeftArm(); + this.model.rightArm.visible = showRightArm; + this.model.rightSleeve.visible = showRightArm; + this.model.leftArm.visible = showLeftArm; + this.model.leftSleeve.visible = showLeftArm; + } + } + + // No `else` case needed to show parts, since the default state should be correct already + } + + @Unique + private void setAllPartsVisible(boolean visible) { + this.model.head.visible = visible; + this.model.body.visible = visible; + this.model.leftLeg.visible = visible; + this.model.rightLeg.visible = visible; + this.model.rightArm.visible = visible; + this.model.leftArm.visible = visible; + + this.model.hat.visible = visible; + this.model.leftSleeve.visible = visible; + this.model.rightSleeve.visible = visible; + this.model.leftPants.visible = visible; + this.model.rightPants.visible = visible; + this.model.jacket.visible = visible; + } + @Inject(method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFF)V", at = @At("RETURN")) private void applyBodyTransforms(AbstractClientPlayer abstractClientPlayerEntity, PoseStack matrixStack, float f, float bodyYaw, float tickDelta, CallbackInfo ci){ @@ -46,8 +92,9 @@ private void applyBodyTransforms(AbstractClientPlayer abstractClientPlayerEntity @Inject(method = "renderHand", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/PlayerModel;setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V")) private void notifyModelOfFirstPerson(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, AbstractClientPlayer abstractClientPlayer, ModelPart modelPart, ModelPart modelPart2, CallbackInfo ci) { - if (this.getModel() instanceof IPlayerModel && AnimUtils.disableFirstPersonAnim) { - ((IPlayerModel)this.getModel()).playerAnimator_prepForFirstPersonRender(); + PlayerModel m = this.getModel(); + if (m instanceof IPlayerModel && !((IAnimatedPlayer)abstractClientPlayer).playerAnimator_getAnimation().getFirstPersonMode().isEnabled()) { + ((IPlayerModel)m).playerAnimator_prepForFirstPersonRender(); } } } diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/CameraAccessor.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/CameraAccessor.java new file mode 100644 index 0000000..8e63865 --- /dev/null +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/CameraAccessor.java @@ -0,0 +1,11 @@ +package dev.kosmx.playerAnim.mixin.firstPerson; + +import net.minecraft.client.Camera; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Camera.class) +public interface CameraAccessor { + @Accessor + public void setDetached(boolean value); +} diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/EntityRenderDispatcherMixin.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/EntityRenderDispatcherMixin.java new file mode 100644 index 0000000..e1985a2 --- /dev/null +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/EntityRenderDispatcherMixin.java @@ -0,0 +1,25 @@ +package dev.kosmx.playerAnim.mixin.firstPerson; + +import com.mojang.blaze3d.vertex.PoseStack; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.LevelReader; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderDispatcher.class) +public class EntityRenderDispatcherMixin { + @Inject(method = "renderShadow", at = @At("HEAD"), cancellable = true) + private static void renderShadow_HEAD_PlayerAnimator(PoseStack matrices, MultiBufferSource vertexConsumers, Entity entity, float opacity, float tickDelta, LevelReader world, float radius, CallbackInfo ci) { + if (entity instanceof Player && FirstPersonMode.isFirstPersonPass()) { + // Shadow doesn't render in first person, + // so we don't want to make it appear during first person animation + ci.cancel(); + } + } +} diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/ItemInHandRendererMixin.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/ItemInHandRendererMixin.java new file mode 100644 index 0000000..4bf7d92 --- /dev/null +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/ItemInHandRendererMixin.java @@ -0,0 +1,54 @@ +package dev.kosmx.playerAnim.mixin.firstPerson; + +import com.mojang.blaze3d.vertex.PoseStack; + +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; +import dev.kosmx.playerAnim.impl.IAnimatedPlayer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.ItemInHandRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ItemInHandRenderer.class) +public class ItemInHandRendererMixin { + @Inject(method = "renderHandsWithItems", at = @At("HEAD"), cancellable = true) + private void disableDefaultItemIfNeeded(float f, PoseStack poseStack, MultiBufferSource.BufferSource bufferSource, LocalPlayer localPlayer, int i, CallbackInfo ci) { + if (localPlayer instanceof IAnimatedPlayer && ((IAnimatedPlayer)localPlayer).playerAnimator_getAnimation().getFirstPersonMode() == FirstPersonMode.THIRD_PERSON_MODEL) { + ci.cancel(); + } + } + + /* AW needed, I may do it later + @Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;evaluateWhichHandsToRender(Lnet/minecraft/client/player/LocalPlayer;)Lnet/minecraft/client/renderer/ItemInHandRenderer$HandRenderSelection;")) + private ItemInHandRenderer.HandRenderSelection selectHandsToRender(LocalPlayer localPlayer) { + + return null; + }*/ + + @Inject(method = "renderItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/ItemRenderer;renderStatic(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/client/renderer/block/model/ItemTransforms$TransformType;ZLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/level/Level;II)V"), cancellable = true) + private void cancelItemRender(LivingEntity entity, ItemStack itemStack, ItemTransforms.TransformType transformType, boolean bl, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, CallbackInfo ci) { + if (entity != Minecraft.getInstance().getCameraEntity()) { + return; + } + if (FirstPersonMode.isFirstPersonPass() && entity instanceof IAnimatedPlayer) { + FirstPersonConfiguration config = ((IAnimatedPlayer)entity).playerAnimator_getAnimation().getFirstPersonConfiguration(); + if (transformType == ItemTransforms.TransformType.FIRST_PERSON_RIGHT_HAND || transformType == ItemTransforms.TransformType.THIRD_PERSON_RIGHT_HAND) { + if (!config.isShowRightItem()) { + ci.cancel(); + } + } else { + if (!config.isShowLeftItem()) { + ci.cancel(); + } + } + } + } +} diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/LevelRendererMixin.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/LevelRendererMixin.java new file mode 100644 index 0000000..75703d2 --- /dev/null +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/LevelRendererMixin.java @@ -0,0 +1,54 @@ +package dev.kosmx.playerAnim.mixin.firstPerson; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; +import dev.kosmx.playerAnim.impl.IAnimatedPlayer; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LevelRenderer.class) +public class LevelRendererMixin { + + @Unique + private boolean defaultCameraState = false; + + // @Redirect(at = @At(target = "Lnet/minecraft/client/Camera;isDetached()Z")) is forbidden + + @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;isDetached()Z")) + private void fakeThirdPersonMode(PoseStack poseStack, float f, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) { + // mods may need to redirect that method, I want to avoid compatibility issues as long as possible + defaultCameraState = camera.isDetached(); + Entity entity = camera.getEntity(); + if (entity instanceof IAnimatedPlayer && ((IAnimatedPlayer)entity).playerAnimator_getAnimation().getFirstPersonMode() == FirstPersonMode.THIRD_PERSON_MODEL) { + FirstPersonMode.setFirstPersonPass(!camera.isDetached() && (!(camera.getEntity() instanceof LivingEntity) || !((LivingEntity)camera.getEntity()).isSleeping())); // this will cause a lot of pain + ((CameraAccessor)camera).setDetached(true); + } + } + @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;isDetached()Z", shift = At.Shift.AFTER)) + private void resetThirdPerson(PoseStack poseStack, float f, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) { + ((CameraAccessor)camera).setDetached(defaultCameraState); + } + + + + @Inject(method = "renderEntity", at = @At("TAIL")) + private void dontRenderEntity_End(Entity entity, double cameraX, double cameraY, double cameraZ, + float tickDelta, PoseStack matrices, MultiBufferSource vertexConsumers, CallbackInfo ci) { + Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera(); + if (entity == camera.getEntity()) { + FirstPersonMode.setFirstPersonPass(false); // Unmark this render cycle + } + } +} diff --git a/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/LivingEntityRendererMixin.java b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/LivingEntityRendererMixin.java new file mode 100644 index 0000000..8a1f27e --- /dev/null +++ b/minecraft/common/src/main/java/dev/kosmx/playerAnim/mixin/firstPerson/LivingEntityRendererMixin.java @@ -0,0 +1,32 @@ +package dev.kosmx.playerAnim.mixin.firstPerson; + +import com.mojang.blaze3d.vertex.PoseStack; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.client.renderer.entity.layers.ItemInHandLayer; +import net.minecraft.world.entity.LivingEntity; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.List; +import java.util.stream.Collectors; + +@Mixin(value = LivingEntityRenderer.class, priority = 2000) +public class LivingEntityRendererMixin { + @Shadow @Final protected List layers; + + @Redirect( + method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/entity/LivingEntityRenderer;layers:Ljava/util/List;", opcode = Opcodes.GETFIELD)) + private List filterLayers(LivingEntityRenderer instance, LivingEntity entity, float f, float g, PoseStack poseStack, MultiBufferSource multiBufferSource, int i) { + if (entity instanceof LocalPlayer && FirstPersonMode.isFirstPersonPass()) { + return layers.stream().filter(layer -> layer instanceof ItemInHandLayer).collect(Collectors.toList()); + } else return layers; + } +} diff --git a/minecraft/common/src/main/resources/playerAnimator-common.mixins.json b/minecraft/common/src/main/resources/playerAnimator-common.mixins.json index dc6c6ce..6f6c835 100644 --- a/minecraft/common/src/main/resources/playerAnimator-common.mixins.json +++ b/minecraft/common/src/main/resources/playerAnimator-common.mixins.json @@ -7,13 +7,18 @@ "client": [ "ArmorFeatureRendererMixin", "BipedEntityModelMixin", + "firstPerson.CameraAccessor", + "firstPerson.EntityRenderDispatcherMixin", "FeatureRendererMixin", "HeldItemMixin", + "firstPerson.ItemInHandRendererMixin", + "firstPerson.LevelRendererMixin", + "firstPerson.LivingEntityRendererMixin", + "LivingEntityRenderRedirect_bendOnly", "ModelPartMixin", "PlayerEntityMixin", "PlayerModelMixin", - "PlayerRendererMixin", - "LivingEntityRenderRedirect_bendOnly" + "PlayerRendererMixin" ], "mixins": [ ], diff --git a/minecraft/fabric/build.gradle b/minecraft/fabric/build.gradle index 428d14b..0a4eb36 100644 --- a/minecraft/fabric/build.gradle +++ b/minecraft/fabric/build.gradle @@ -1,7 +1,5 @@ -plugins { - id "com.github.johnrengelman.shadow" version "7.1.2" -} +apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.modrinth.minotaur' apply plugin: 'com.matthewprenger.cursegradle' @@ -53,7 +51,12 @@ dependencies { common(shadowCommon(project(path: ":coreLib")) {transitive false}) {transitive false} //Why can I nest these? //Testing libraries - //modImplementation "io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendy_lib}" + // modLocalRuntime files("../libs/bendy-lib-2.1.1-fabric.jar") + modLocalRuntime "io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendy_lib}" + modLocalRuntime "maven.modrinth:3dskinlayers:1.6.7" + modLocalRuntime "maven.modrinth:emotecraft:2.2.6-SNAPSHOT-build.44-MC1.16.5-fabric" + modLocalRuntime "maven.modrinth:modmenu:1.16.23" + modLocalRuntime "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" modImplementation fabricApi.module("fabric-resource-loader-v0", project.fabric_api_version) @@ -73,18 +76,18 @@ shadowJar { exclude "architectury.common.json" configurations = [project.configurations.shadowCommon] - classifier "dev-shadow" + archiveClassifier.set("dev-shadow") } remapJar { injectAccessWidener = true inputFile.set shadowJar.archiveFile dependsOn shadowJar - classifier null + archiveClassifier.set(null) } jar { - classifier "dev" + archiveClassifier.set("dev") } sourcesJar { diff --git a/minecraft/fabric/src/main/resources/assets/player-animator/lang/tt_ru.json b/minecraft/fabric/src/main/resources/assets/player-animator/lang/tt_ru.json new file mode 100644 index 0000000..dc7e479 --- /dev/null +++ b/minecraft/fabric/src/main/resources/assets/player-animator/lang/tt_ru.json @@ -0,0 +1,3 @@ +{ + "modmenu.descriptionTranslation.player-animator": "Уенчыны гади анимацияләү өчен җиңел (авырлык буенча) китапханә" +} diff --git a/minecraft/fabric/src/main/resources/fabric.mod.json b/minecraft/fabric/src/main/resources/fabric.mod.json index 0be792c..260d1e1 100644 --- a/minecraft/fabric/src/main/resources/fabric.mod.json +++ b/minecraft/fabric/src/main/resources/fabric.mod.json @@ -11,7 +11,7 @@ "homepage": "kosmx.dev", "sources": "https://github.com/KosmX/fabricPlayerAnimation" }, - "license": "Insert License Here", + "license": "MIT", "environment": "*", "entrypoints": { "client": ["dev.kosmx.playerAnim.fabric.client.FabricClientInitializer"] @@ -23,6 +23,9 @@ "minecraft": ">=1.16", "fabric-resource-loader-v0": "*" }, + "breaks": { + "bettercombat": "<1.6.0" + }, "custom": { "modmenu": { "badges": ["library"] diff --git a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/AnimationRegistry.java b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/AnimationRegistry.java deleted file mode 100644 index 9299ef5..0000000 --- a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/AnimationRegistry.java +++ /dev/null @@ -1,43 +0,0 @@ -package dev.kosmx.animatorTestmod; - -import dev.kosmx.playerAnim.core.data.KeyframeAnimation; -import dev.kosmx.playerAnim.core.data.gson.AnimationSerializing; -import net.minecraft.server.packs.resources.ResourceManager; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; - -public class AnimationRegistry { - // static final Logger LOGGER = LogUtils.getLogger(); - public static final Map animations = new HashMap<>(); - - public static void load(ResourceManager resourceManager) { - String dataFolder = "animations"; - - - /* - try (InputStream reader = AnimationRegistry.class.getResourceAsStream("assets\\testmod\\animations\\two_handed_slash_horizontal_right.json")) { - KeyframeAnimation animation = AnimationSerializing.deserializeAnimation(reader).get(0); - animations.put("two_handed_slash_horizontal_right", animation); - - } catch(IOException e) { - e.printStackTrace(); - } - */ - byte[] bytes = Base64.getDecoder().decode(SomeString.something); - try (InputStream reader = new ByteArrayInputStream(bytes)) { - KeyframeAnimation animation = AnimationSerializing.deserializeAnimation(reader).get(0); - KeyframeAnimation.AnimationBuilder modified = animation.mutableCopy(); - modified.getOrCreatePart("torso").fullyEnablePart(true); //crouching workaround - animations.put("two_handed_vertical_right_right", modified.build()); - - } catch(IOException e) { - e.printStackTrace(); - } - - - - } -} diff --git a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/CodedAnimation.java b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/CodedAnimation.java new file mode 100644 index 0000000..d5eb31d --- /dev/null +++ b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/CodedAnimation.java @@ -0,0 +1,2 @@ +package dev.kosmx.animatorTestmod;public class CodedAnimation { +} diff --git a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/PlayerAnimTestmod.java b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/PlayerAnimTestmod.java index 9ddc447..e164fa5 100644 --- a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/PlayerAnimTestmod.java +++ b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/PlayerAnimTestmod.java @@ -1,5 +1,7 @@ package dev.kosmx.animatorTestmod; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonConfiguration; +import dev.kosmx.playerAnim.api.firstPerson.FirstPersonMode; import dev.kosmx.playerAnim.api.layered.IAnimation; import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer; import dev.kosmx.playerAnim.api.layered.ModifierLayer; @@ -78,7 +80,11 @@ public static void playTestAnimation() { } else { //Fade from current animation to a new one. //Will not fade if there is no animation currently. - testAnimation.replaceAnimationWithFade(AbstractFadeModifier.functionalFadeIn(20, (modelName, type, value) -> value), new KeyframeAnimationPlayer(PlayerAnimationRegistry.getAnimation(new ResourceLocation("testmod", "two_handed_slash_vertical_right")))); + testAnimation.replaceAnimationWithFade(AbstractFadeModifier.functionalFadeIn(20, (modelName, type, value) -> value), + new KeyframeAnimationPlayer(PlayerAnimationRegistry.getAnimation(new ResourceLocation("testmod", "two_handed_slash_vertical_right"))) + .setFirstPersonMode(FirstPersonMode.THIRD_PERSON_MODEL) + .setFirstPersonConfiguration(new FirstPersonConfiguration().setShowRightArm(true).setShowLeftItem(false)) + ); } diff --git a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/SomeString.java b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/SomeString.java deleted file mode 100644 index 10bb6e7..0000000 --- a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/SomeString.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.kosmx.animatorTestmod; - -/** - * 'Cause I could not load the animations from assets - * - * It is a base64 encoded version of it :D - */ -public class SomeString { - public final static String something = "ew0KICAgICJuYW1lIjogInR3b19oYW5kZWRfc2xhc2hfaG9yaXpvbnRhbF9yaWdodCIsDQogICAgImF1dGhvciI6ICJEYWVkZWx1cyIsDQogICAgImRlc2NyaXB0aW9uIjogIlR3byBoYW5kZWQgc2xhc2ggYXR0YWNrIHJpZ2h0IHRvIGxlZnQiLA0KICAgICJlbW90ZSI6ew0KICAgICAgICAiaXNMb29wIjogImZhbHNlIiwNCiAgICAgICAgInJldHVyblRpY2siOiAyLA0KICAgICAgICAiYmVnaW5UaWNrIjoxMCwNCiAgICAgICAgImVuZFRpY2siOjE4LA0KICAgICAgICAic3RvcFRpY2siOjI4LA0KICAgICAgICAiZGVncmVlcyI6ZmFsc2UsDQogICAgICAgICJtb3ZlcyI6Ww0KICAgICAgICAgICAgDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjotMC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTEsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOi0wLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6LTAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEzLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjotMC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjotMC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOi0wLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjExLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0wLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMywNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi0wLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6LTAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjotMC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTMsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi0wLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi0wLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6LTAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOi0wLjMxMjE0NTUwMTM3NTE5ODM2DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTEsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6MC4wMzAwNzgyNDM0NjQyMzE0OQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOjAuNjI5NzQ3MzkwNzQ3MDcwMw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEzLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOjEuMDU3NTY5MDI2OTQ3MDIxNQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjoxLjE4Njk3NTU5ODMzNTI2NjENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjoxLjE4NTY0MTUyNzE3NTkwMzMNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6LTAuMDc4ODY5MDUyMjMxMzExOA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjExLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjotMC4wMTY1NDcwNDQ3MzkxMjcxNg0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjotMC4yMjk0MTE3ODA4MzQxOTgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMywNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6LTAuMzMyNDk4NDAxNDAzNDI3MQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6LTAuMzMxNzY5MDE5MzY1MzEwNjcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6LTAuMzM3MTY5MzQ5MTkzNTczDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjowLjI1MzAyODEyNDU3MDg0NjU2DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTEsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImhlYWQiOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjotMC4wMzIwMTg3OTkzMzQ3NjQ0OA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTAuMzY2MjYyMDE4NjgwNTcyNQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEzLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJoZWFkIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTAuNDE5Njk0OTYwMTE3MzQwMQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjQxNDM1NDYyMjM2NDA0NDINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAiaGVhZCI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjM3OTI5Mzk0ODQxMTk0MTUzDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOi0wLjMyNDA5NDI2NTY5OTM4NjYNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6MC4wMjU5OTIyMjk1ODA4NzkyMQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjowLjY2MzAyNDg0MjczOTEwNTINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOjEuMjE1MDMxNTA0NjMxMDQyNQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjoxLjIzMjUyNDk5MTAzNTQ2MTQNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOi01LjU0MTA5Mzk5NTQ0MDgyNWUtMTcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOjAuMDA1MjEzOTI1NjE0OTUzMDQxDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjowLjAxMDQyNzg1MTIyOTkwNjA4Mg0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOi0wLjE3MDI2OTQ1OTQ4NjAwNzcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOi0wLjAzMjI5MjQ3Nzc4NjU0MDk4NQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOjAuMjM4ODIwNzkxMjQ0NTA2ODQNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjotMC4wMDg5NjMyNzE5NzU1MTcyNzMNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjotMC4yODQ3NzgwODgzMzEyMjI1Mw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjotMC4zMjIxNTI0MzU3Nzk1NzE1Mw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjE3OTkxNTQ1Nzk2Mzk0MzQ4DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjowLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOjAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6MC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6MC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjowLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOjAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjExLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6MC4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjowLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjowLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAidG9yc28iOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOjAuMA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTAuMDQ0NjA5MDM2Mjk2NjA2MDY0DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTEsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMC4wNjU3NzAxMDQ1Mjc0NzM0NQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTAuMDY0OTk5OTk3NjE1ODE0MjENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInRvcnNvIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMC4xNDA5MzU5NDI1MzA2MzIwMg0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJ0b3JzbyI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTAuMTg3OTE0NTk1MDA3ODk2NDINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6MC4yMzE3MDU5Nzg1MTI3NjM5OA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjowLjEwODUzMjcxOTMxNDA5ODM2DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjowLjA0OTkwNDEwMDU5NjkwNDc1NQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjowLjAzMTQ4OTY2MjgyNjA2MTI1DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjoxLjM3MDEzNzY5MTQ5NzgwMjcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOjEuNjMxNDE3MTU1MjY1ODA4DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6MS42ODk4ODYwOTMxMzk2NDg0DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjoxLjY1NjA3NTAwMDc2MjkzOTUNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOjMuMzg5ODc5MjI2Njg0NTcwMw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6Mi44NjQ5MjE1Njk4MjQyMTg4DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6Mi44NjQ5MjE1Njk4MjQyMTg4DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjoyLjg2NDkyMTU2OTgyNDIxODgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOjAuMDk1MTM2MDc2MjExOTI5MzINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0xLjYyMDAwOTE4Mzg4MzY2Nw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0xLjYyMDAwOTE4Mzg4MzY2Nw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTEuNjIwMDA5MTgzODgzNjY3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjotNS43MDM1NDg0MzEzOTY0ODQNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi00LjQzMzEwOTc2MDI4NDQyNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi00LjQzMzEwOTc2MDI4NDQyNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6LTQuNDMzMTA5NzYwMjg0NDI0DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6MC4yODE4NTAwMTAxNTY2MzE0Nw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0xLjMwMzk4OTg4NzIzNzU0ODgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTEuODEzNzcxNzI0NzAwOTI3Nw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0yLjE1NzY0MDkzMzk5MDQ3ODUNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6MS4yNTMxNzAwMTM0Mjc3MzQ0DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOjEuNTkyNDIwMjIwMzc1MDYxDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjoxLjM5NTYwNTgwMjUzNjAxMDcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6MS4yOTY3OTMyMjI0MjczNjgyDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6MC4wMDY0ODgzMjM2NzczMzEyMDkNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjowLjA5MDgxMDY1NjU0NzU0NjM5DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOjAuMjcwMDc2NDUzNjg1NzYwNQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOjAuMTE2NzEyOTEyOTE3MTM3MTUNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjQ4NjYwNDMwMzEyMTU2NjgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjcxMjcyMjU5OTUwNjM3ODINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjotMC45MDY5NTI2NzkxNTcyNTcxDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjotMS4yOTMxOTI3NDQyNTUwNjYNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6Mi42Nzc4NzU1MTg3OTg4MjgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6Mi42Nzc4NzU1MTg3OTg4MjgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOjEuOTI1Nzk4NDE2MTM3Njk1Mw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjoyLjI3ODMyMzE3MzUyMjk0OQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMi43ODQyNTc0MTE5NTY3ODcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTIuNzg0MjU3NDExOTU2Nzg3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMy4yNjAyNDM0MTU4MzI1MTk1DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRBcm0iOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0wLjk1NDcxNTM3MTEzMTg5Nw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjoyLjAzNTUxMDc3ODQyNzEyNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0QXJtIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjoyLjAzNTUxMDc3ODQyNzEyNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6NS4zNjMxOTM5ODg4MDAwNDkNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdEFybSI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6NS44NTg4NTAwMDIyODg4MTgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6LTAuMjUyMjk0MTUyOTc1MDgyNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjExLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjotMC4wMDA1ODc2NDkwNjEzNDQ1NjQNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6MC41MjE5NzUwNDA0MzU3OTENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOjEuMTU3Nzk0MTE3OTI3NTUxMw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjoxLjE0MDM3NzQwMjMwNTYwMw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6LTAuMDMyMjQ4ODY5NTM4MzA3MTkNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOi0wLjAwODU2OTU1MzQ5NDQ1MzQzDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjotMC4xNjM3ODc0MDk2NjMyMDAzOA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOi0wLjA4MzY5NDUxMDE2MTg3NjY4DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjotMC4xMjA5Mjk3ODUwNzI4MDM1DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6MC4yMTA5ODU4MDk1NjQ1OTA0NQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjExLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjA0ODk0MzE0MzMzNzk2NTAxDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTAuNDAzMTI3NDAyMDY3MTg0NDUNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTAuMzE4MzgyMTQzOTc0MzA0Mg0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjIxMjE0MDc4MzY2NzU2NDQNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi0xLjkNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi0xLjkzNDgzODY3NjQ1MjYzNjYNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi0yLjM1OTkzMDY1ODM0MDQ1NA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgIngiOi0zLjIwNDMyNDE1MDA4NTQ0OQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6LTMuMjA0MzI0MTUwMDg1NDQ5DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjoxMi4wDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTEsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjoxMS4wMzI2MzQ3OTQ3MTIwNjcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOjExLjE5MjUwMzA5NDY3MzE1Nw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOjExLjYwMjMzNDY3ODE3MzA2NQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6MTEuNjAyMzM0Njc4MTczMDY1DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjowLjENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMSwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0xLjAzOTQwOTQyMjg3NDQ1MDYNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0wLjI2NTM5MTE2NTAxODA4MTcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMC4zMjUxMTk2OTgwNDc2Mzc5Ng0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTAuMzI1MTE5Njk4MDQ3NjM3OTYNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjotMC40NDY5MDk3MjU2NjYwNDYxNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ5YXciOjAuMDI2ODM5MTI0MDM4ODE1NQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjotMC4zMTc0NTA0MzM5Njk0OTc3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6LTAuMzM0MjQyNTUyNTE4ODQ0Ng0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEwLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjotMC4xNjc1Mzc3NjM3MTQ3OTAzNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjotMC4wMTAzMjE0NDM5MDA0NjU5NjUNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOjAuMDIwMTI4MDQ1MjMxMTAzODk3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTgsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5PVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOi0wLjEwNDY5MzA4NDk1NTIxNTQ1DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjowLjU4Mzg0MTE0NTAzODYwNDcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjE1MDAyMjIyMzU5MTgwNDUNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInBpdGNoIjotMC4yMjcxMzMwNjU0NjIxMTI0Mw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTAuMTg5NTUwNjgyOTAyMzM2MTINCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6MTEuNzA5NzA1NjUwODA2NDI3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOjEyLjANCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOjExLjkxNDY2NDQ3NzEwOTkwOQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjoxMS45MTQ2NjQ0NzcxMDk5MDkNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6MC41MTIyMjM5MjMyMDYzMjk0DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0wLjENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxNCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VPVVRRVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgImxlZnRMZWciOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0xLjAxMTIxNDA1MzYzMDgyOQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE4LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMS4wMTEyMTQwNTM2MzA4MjkNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6Mi4xMjg2NTIwMDA0MjcyNDYNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6MS45DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJsZWZ0TGVnIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjoyLjk2Njk0ODE3NTQzMDI5NzgNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxOCwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTk9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAibGVmdExlZyI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6Mi45NjY5NDgxNzU0MzAyOTc4DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6MC44ODg2MzQ2MjIwOTcwMTU0DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAieCI6MC4xNDk3MDcxOTgxNDMwMDUzNw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRJdGVtIjp7DQogICAgICAgICAgICAgICAgICAgICJ4IjowLjEyMDg3ODQ4NzgyNTM5MzY4DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAieiI6LTEuMTE2NTQ4MDYxMzcwODQ5Ng0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEl0ZW0iOnsNCiAgICAgICAgICAgICAgICAgICAgInoiOi0xLjM3ODUwNjA2NDQxNDk3OA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRJdGVtIjp7DQogICAgICAgICAgICAgICAgICAgICJ6IjotMC4zNzEwOTM1NzExODYwNjU3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAieSI6LTMuMDg2MDk1ODA5OTM2NTIzNA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjEyLA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRUlOUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEl0ZW0iOnsNCiAgICAgICAgICAgICAgICAgICAgInkiOi0xLjQ5NzAyNTQ4OTgwNzEyOQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRJdGVtIjp7DQogICAgICAgICAgICAgICAgICAgICJ5IjowLjA1MjI1ODM3MjMwNjgyMzczDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAicGl0Y2giOi0wLjY4NzMzNTYxMDM4OTcwOTUNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRJdGVtIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTAuOTY3MzE0NTQxMzM5ODc0Mw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0sDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgInRpY2siOjE0LA0KICAgICAgICAgICAgICAgICJlYXNpbmciOiAiRUFTRU9VVFFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRJdGVtIjp7DQogICAgICAgICAgICAgICAgICAgICJwaXRjaCI6LTEuODEyMzM0NjU2NzE1MzkzDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjowLjM5MDQxNzUxNjIzMTUzNjg3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTIsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAieWF3IjowLjIwMDcxMTc3MTg0NTgxNzU3DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEl0ZW0iOnsNCiAgICAgICAgICAgICAgICAgICAgInlhdyI6LTAuMDAxODQ0ODUzMTYyNzY1NTAzDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTAsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFSU5RVUFEIiwNCiAgICAgICAgICAgICAgICAidHVybiI6IDAsDQogICAgICAgICAgICAgICAgInJpZ2h0SXRlbSI6ew0KICAgICAgICAgICAgICAgICAgICAicm9sbCI6LTIuNzA5OTYzNTYwMTA0MzcNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICJ0aWNrIjoxMiwNCiAgICAgICAgICAgICAgICAiZWFzaW5nIjogIkVBU0VJTlFVQUQiLA0KICAgICAgICAgICAgICAgICJ0dXJuIjogMCwNCiAgICAgICAgICAgICAgICAicmlnaHRJdGVtIjp7DQogICAgICAgICAgICAgICAgICAgICJyb2xsIjotMy4wOTY5MjUwMjAyMTc4OTU1DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfSwNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAidGljayI6MTQsDQogICAgICAgICAgICAgICAgImVhc2luZyI6ICJFQVNFT1VUUVVBRCIsDQogICAgICAgICAgICAgICAgInR1cm4iOiAwLA0KICAgICAgICAgICAgICAgICJyaWdodEl0ZW0iOnsNCiAgICAgICAgICAgICAgICAgICAgInJvbGwiOi0zLjIyMDIyODY3MjAyNzU4OA0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0NCiAgICAgICAgXQ0KICAgIH0NCn0NCg=="; -} diff --git a/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/mixin/AbstractClientPlayerMixin.java b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/mixin/AbstractClientPlayerMixin.java new file mode 100644 index 0000000..4ecc54a --- /dev/null +++ b/minecraft/fabric/src/testmod/java/dev/kosmx/animatorTestmod/mixin/AbstractClientPlayerMixin.java @@ -0,0 +1,2 @@ +package dev.kosmx.animatorTestmod.mixin;public class AbstractClientPlayerMixin { +} diff --git a/minecraft/fabric/src/testmod/resources/testmod.mixins.json b/minecraft/fabric/src/testmod/resources/testmod.mixins.json index ad6c412..0a52657 100644 --- a/minecraft/fabric/src/testmod/resources/testmod.mixins.json +++ b/minecraft/fabric/src/testmod/resources/testmod.mixins.json @@ -1,7 +1,7 @@ { "required": true, "package": "dev.kosmx.animatorTestmod.mixin", - "compatibilityLevel": "JAVA_16", + "compatibilityLevel": "JAVA_8", "client": [ "ClientPlayerMixin", "MinecraftClientMixin" diff --git a/minecraft/forge/build.gradle b/minecraft/forge/build.gradle index e079bad..8243639 100644 --- a/minecraft/forge/build.gradle +++ b/minecraft/forge/build.gradle @@ -1,7 +1,5 @@ -plugins { - id "com.github.johnrengelman.shadow" version "7.1.2" -} +apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.modrinth.minotaur' apply plugin: 'com.matthewprenger.cursegradle' @@ -39,11 +37,12 @@ dependencies { common(shadowCommon(project(path: ":coreLib")) {transitive false}) {transitive false} //Why can I nest these? //Testing libraries - //* + /* + modLocalRuntime files("../libs/bendy-lib-2.1.1-forge.jar") modLocalRuntime "io.github.kosmx.bendy-lib:bendy-lib-forge:${project.bendy_lib}" modLocalRuntime "maven.modrinth:3dskinlayers:1.5.2-forge-1.19" modLocalRuntime "maven.modrinth:emotecraft:2.2.6-SNAPSHOT-build.44-MC1.19.2-forge" - //*/ + */ } project.archivesBaseName = rootProject.archives_base_name + "-" + project.name @@ -61,17 +60,17 @@ shadowJar { exclude "architectury.common.json" configurations = [project.configurations.shadowCommon] - classifier "dev-shadow" + archiveClassifier.set("dev-shadow") } remapJar { inputFile.set shadowJar.archiveFile dependsOn shadowJar - classifier null + archiveClassifier.set(null) } jar { - classifier "dev" + archiveClassifier.set("dev") } sourcesJar { diff --git a/minecraft/forge/src/main/resources/META-INF/mods.toml b/minecraft/forge/src/main/resources/META-INF/mods.toml index 4db3d5b..8719d76 100644 --- a/minecraft/forge/src/main/resources/META-INF/mods.toml +++ b/minecraft/forge/src/main/resources/META-INF/mods.toml @@ -1,7 +1,7 @@ modLoader = "javafml" loaderVersion = "[35.1.0,)" #issueTrackerURL = "" -license = "Insert License Here" +license = "MIT" [[mods]] modId = "playeranimator"