From 051668fe9ac8d02fd9546e588d4255ee5e120f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linnea=20Gr=C3=A4f?= Date: Mon, 23 Jun 2025 13:34:02 +0200 Subject: [PATCH] feat: Add dev capes --- .../CustomCapeFeatureRenderer.java | 44 +++++ .../devcosmetics/CustomCapeStorage.java | 23 +++ .../SaveCapeToPlayerEntityRenderState.java | 19 ++ .../features/debug/itemeditor/ExportRecipe.kt | 5 +- src/main/kotlin/features/misc/CustomCapes.kt | 165 ++++++++++++++++++ src/main/kotlin/features/misc/Devs.kt | 16 ++ .../kotlin/util/render/CustomRenderLayers.kt | 9 + .../firmament/shaders/cape/parallax.fsh | 53 ++++++ .../assets/firmament/textures/cape/REUSE.toml | 16 ++ .../firmament/textures/cape/firm_static.png | Bin 0 -> 42249 bytes .../textures/cape/firmament_star.png | Bin 0 -> 1141 bytes .../textures/cape/parallax_background.png | Bin 0 -> 2053 bytes .../textures/cape/parallax_template.png | Bin 0 -> 516 bytes 13 files changed, 347 insertions(+), 3 deletions(-) create mode 100644 src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeFeatureRenderer.java create mode 100644 src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeStorage.java create mode 100644 src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/SaveCapeToPlayerEntityRenderState.java create mode 100644 src/main/kotlin/features/misc/CustomCapes.kt create mode 100644 src/main/kotlin/features/misc/Devs.kt create mode 100644 src/main/resources/assets/firmament/shaders/cape/parallax.fsh create mode 100644 src/main/resources/assets/firmament/textures/cape/REUSE.toml create mode 100644 src/main/resources/assets/firmament/textures/cape/firm_static.png create mode 100644 src/main/resources/assets/firmament/textures/cape/firmament_star.png create mode 100644 src/main/resources/assets/firmament/textures/cape/parallax_background.png create mode 100644 src/main/resources/assets/firmament/textures/cape/parallax_template.png diff --git a/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeFeatureRenderer.java b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeFeatureRenderer.java new file mode 100644 index 0000000..398400f --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeFeatureRenderer.java @@ -0,0 +1,44 @@ +package moe.nea.firmament.mixins.feature.devcosmetics; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import kotlin.Unit; +import moe.nea.firmament.features.misc.CustomCapes; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.feature.CapeFeatureRenderer; +import net.minecraft.client.render.entity.feature.FeatureRenderer; +import net.minecraft.client.render.entity.feature.FeatureRendererContext; +import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.client.render.entity.model.PlayerEntityModel; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import net.minecraft.client.util.SkinTextures; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(CapeFeatureRenderer.class) +public abstract class CustomCapeFeatureRenderer extends FeatureRenderer { + public CustomCapeFeatureRenderer(FeatureRendererContext context) { + super(context); + } + + @WrapOperation( + method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/PlayerEntityRenderState;FF)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/model/BipedEntityModel;render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;II)V") + ) + private void onRender(BipedEntityModel instance, MatrixStack matrixStack, VertexConsumer vertexConsumer, int light, int overlay, Operation original, @Local PlayerEntityRenderState playerEntityRenderState, @Local SkinTextures skinTextures, @Local VertexConsumerProvider vertexConsumerProvider) { + // TODO: load special cape from playerEntityRenderState + CustomCapes.render( + playerEntityRenderState, + vertexConsumer, + RenderLayer.getEntitySolid(skinTextures.capeTexture()), + vertexConsumerProvider, + updatedConsumer -> { + original.call(instance, matrixStack, updatedConsumer, light, overlay); + return Unit.INSTANCE; + }); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeStorage.java b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeStorage.java new file mode 100644 index 0000000..428d7ec --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/CustomCapeStorage.java @@ -0,0 +1,23 @@ +package moe.nea.firmament.mixins.feature.devcosmetics; + +import moe.nea.firmament.features.misc.CustomCapes; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(PlayerEntityRenderState.class) +public class CustomCapeStorage implements CustomCapes.CapeStorage { + @Unique + CustomCapes.CustomCape customCape; + + @Override + public CustomCapes.@Nullable CustomCape getCape_firmament() { + return customCape; + } + + @Override + public void setCape_firmament(CustomCapes.@Nullable CustomCape customCape) { + this.customCape = customCape; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/SaveCapeToPlayerEntityRenderState.java b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/SaveCapeToPlayerEntityRenderState.java new file mode 100644 index 0000000..72bb79a --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/feature/devcosmetics/SaveCapeToPlayerEntityRenderState.java @@ -0,0 +1,19 @@ +package moe.nea.firmament.mixins.feature.devcosmetics; + +import moe.nea.firmament.features.misc.CustomCapes; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.render.entity.PlayerEntityRenderer; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +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(PlayerEntityRenderer.class) +public class SaveCapeToPlayerEntityRenderState { + @Inject(method = "updateRenderState(Lnet/minecraft/client/network/AbstractClientPlayerEntity;Lnet/minecraft/client/render/entity/state/PlayerEntityRenderState;F)V", + at = @At("TAIL")) + private void addCustomCape(AbstractClientPlayerEntity abstractClientPlayerEntity, PlayerEntityRenderState playerEntityRenderState, float f, CallbackInfo ci) { +CustomCapes.addCapeData(abstractClientPlayerEntity, playerEntityRenderState); + } +} diff --git a/src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt b/src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt index d7f4620..4d43f6e 100644 --- a/src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt +++ b/src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt @@ -5,7 +5,6 @@ import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import net.minecraft.client.network.AbstractClientPlayerEntity -import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.entity.decoration.ArmorStandEntity import moe.nea.firmament.Firmament import moe.nea.firmament.annotations.Subscribe @@ -64,7 +63,7 @@ object ExportRecipe { ?: "" val reply = waitForTextInput("$guessName (NPC)", "Export stub") val id = generateName(reply) - ItemExporter.exportStub(id, reply) { + ItemExporter.exportStub(id, "§9$reply") { val playerEntity = entity as? AbstractClientPlayerEntity val textureUrl = playerEntity?.skinTextures?.textureUrl if (textureUrl != null) @@ -117,7 +116,7 @@ object ExportRecipe { val shopId = SkyblockId(title.uppercase().replace(" ", "_") + "_NPC") if (!ItemExporter.isExported(shopId)) { // TODO: export location + skin of last clicked npc - ItemExporter.exportStub(shopId, "$title (NPC)") + ItemExporter.exportStub(shopId, "§9$title (NPC)") } for (index in (9..9 * 5)) { val item = event.screen.getSlotByIndex(index, false)?.stack ?: continue diff --git a/src/main/kotlin/features/misc/CustomCapes.kt b/src/main/kotlin/features/misc/CustomCapes.kt new file mode 100644 index 0000000..5e4764e --- /dev/null +++ b/src/main/kotlin/features/misc/CustomCapes.kt @@ -0,0 +1,165 @@ +package moe.nea.firmament.features.misc + +import com.mojang.blaze3d.systems.RenderSystem +import java.util.OptionalDouble +import java.util.OptionalInt +import util.render.CustomRenderPipelines +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import net.minecraft.client.network.AbstractClientPlayerEntity +import net.minecraft.client.render.BufferBuilder +import net.minecraft.client.render.RenderLayer +import net.minecraft.client.render.VertexConsumer +import net.minecraft.client.render.VertexConsumerProvider +import net.minecraft.client.render.entity.state.PlayerEntityRenderState +import net.minecraft.client.util.BufferAllocator +import net.minecraft.util.Identifier +import moe.nea.firmament.Firmament +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.TimeMark + +object CustomCapes { + interface CustomCapeRenderer { + fun replaceRender( + renderLayer: RenderLayer, + vertexConsumerProvider: VertexConsumerProvider, + model: (VertexConsumer) -> Unit + ) + } + + data class TexturedCapeRenderer( + val location: Identifier + ) : CustomCapeRenderer { + override fun replaceRender( + renderLayer: RenderLayer, + vertexConsumerProvider: VertexConsumerProvider, + model: (VertexConsumer) -> Unit + ) { + model(vertexConsumerProvider.getBuffer(RenderLayer.getEntitySolid(location))) + } + } + + data class ParallaxedHighlightCapeRenderer( + val template: Identifier, + val background: Identifier, + val overlay: Identifier, + val animationSpeed: Duration, + ) : CustomCapeRenderer { + override fun replaceRender( + renderLayer: RenderLayer, + vertexConsumerProvider: VertexConsumerProvider, + model: (VertexConsumer) -> Unit + ) { + BufferAllocator(2048).use { allocator -> + val bufferBuilder = BufferBuilder(allocator, renderLayer.drawMode, renderLayer.vertexFormat) + model(bufferBuilder) + bufferBuilder.end().use { buffer -> + val commandEncoder = RenderSystem.getDevice().createCommandEncoder() + val vertexBuffer = renderLayer.vertexFormat.uploadImmediateVertexBuffer(buffer.buffer) + val indexBufferConstructor = RenderSystem.getSequentialBuffer(renderLayer.drawMode) + val indexBuffer = indexBufferConstructor.getIndexBuffer(buffer.drawParameters.indexCount) + val templateTexture = MC.textureManager.getTexture(template) + val backgroundTexture = MC.textureManager.getTexture(background) + val foregroundTexture = MC.textureManager.getTexture(overlay) + commandEncoder.createRenderPass( + MC.instance.framebuffer.colorAttachment, + OptionalInt.empty(), + MC.instance.framebuffer.depthAttachment, + OptionalDouble.empty(), + ).use { renderPass -> + // TODO: account for lighting + renderPass.setPipeline(CustomRenderPipelines.PARALLAX_CAPE_SHADER) + renderPass.bindSampler("Sampler0", templateTexture.glTexture) + renderPass.bindSampler("Sampler1", backgroundTexture.glTexture) + renderPass.bindSampler("Sampler3", foregroundTexture.glTexture) + val animationValue = (startTime.passedTime() / animationSpeed).mod(1F) + renderPass.setUniform("Animation", animationValue.toFloat()) + renderPass.setIndexBuffer(indexBuffer, indexBufferConstructor.indexType) + renderPass.setVertexBuffer(0, vertexBuffer) + renderPass.drawIndexed(0, buffer.drawParameters.indexCount) + } + } + } + } + } + + interface CapeStorage { + companion object { + @JvmStatic + fun cast(playerEntityRenderState: PlayerEntityRenderState) = + playerEntityRenderState as CapeStorage + + } + + var cape_firmament: CustomCape? + } + + data class CustomCape( + val id: String, + val label: String, + val render: CustomCapeRenderer, + ) + + enum class AllCapes(val label: String, val render: CustomCapeRenderer) { + FIRMAMENT_ANIMATED( + "Animated Firmament", ParallaxedHighlightCapeRenderer( + Firmament.identifier("textures/cape/parallax_template.png"), + Firmament.identifier("textures/cape/parallax_background.png"), + Firmament.identifier("textures/cape/firmament_star.png"), + 110.seconds + ) + ), +// FURFSKY( +// "FurfSky", +// TexturedCapeRenderer(Firmament.identifier("textures/cape/fsr_static.png")) +// ), + FIRMAMENT_STATIC( + "Firmament", + TexturedCapeRenderer(Firmament.identifier("textures/cape/firm_static.png")) + ) + ; + + val cape = CustomCape(name, label, render) + } + + val byId = AllCapes.entries.associateBy { it.cape.id } + val byUuid = listOf( + Devs.nea to AllCapes.FIRMAMENT_ANIMATED, + Devs.kath to AllCapes.FIRMAMENT_STATIC, + Devs.jani to AllCapes.FIRMAMENT_ANIMATED, + ).flatMap { (dev, cape) -> dev.uuids.map { it to cape.cape } }.toMap() + + @JvmStatic + fun render( + playerEntityRenderState: PlayerEntityRenderState, + vertexConsumer: VertexConsumer, + renderLayer: RenderLayer, + vertexConsumerProvider: VertexConsumerProvider, + model: (VertexConsumer) -> Unit + ) { + val capeStorage = CapeStorage.cast(playerEntityRenderState) + val firmCape = capeStorage.cape_firmament + if (firmCape != null) { + firmCape.render.replaceRender(renderLayer, vertexConsumerProvider, model) + } else { + model(vertexConsumer) + } + } + + @JvmStatic + fun addCapeData( + player: AbstractClientPlayerEntity, + playerEntityRenderState: PlayerEntityRenderState + ) { + val cape = byUuid[player.uuid] + val capeStorage = CapeStorage.cast(playerEntityRenderState) + if (cape == null) { + capeStorage.cape_firmament = null + } else { + capeStorage.cape_firmament = cape + playerEntityRenderState.capeVisible = true; + } + } + + val startTime = TimeMark.now() +} diff --git a/src/main/kotlin/features/misc/Devs.kt b/src/main/kotlin/features/misc/Devs.kt new file mode 100644 index 0000000..7a5da2b --- /dev/null +++ b/src/main/kotlin/features/misc/Devs.kt @@ -0,0 +1,16 @@ +package moe.nea.firmament.features.misc + +import java.util.UUID + +object Devs { + data class Dev( + val uuids: List, + ) { + constructor(vararg uuid: UUID) : this(uuid.toList()) + constructor(vararg uuid: String) : this(uuid.map { UUID.fromString(it) }) + } + + val nea = Dev("d3cb85e2-3075-48a1-b213-a9bfb62360c1", "842204e6-6880-487b-ae5a-0595394f9948") + val kath = Dev("add71246-c46e-455c-8345-c129ea6f146c", "b491990d-53fd-4c5f-a61e-19d58cc7eddf") + val jani = Dev("8a9f1841-48e9-48ed-b14f-76a124e6c9df") +} diff --git a/src/main/kotlin/util/render/CustomRenderLayers.kt b/src/main/kotlin/util/render/CustomRenderLayers.kt index be0bbd7..3d9e598 100644 --- a/src/main/kotlin/util/render/CustomRenderLayers.kt +++ b/src/main/kotlin/util/render/CustomRenderLayers.kt @@ -49,6 +49,15 @@ object CustomRenderPipelines { .withFragmentShader(Firmament.identifier("circle_discard_color")) .withBlend(BlendFunction.TRANSLUCENT) .build() + val PARALLAX_CAPE_SHADER = + RenderPipeline.builder(RenderPipelines.ENTITY_SNIPPET) + .withLocation(Firmament.identifier("parallax_cape")) + .withFragmentShader(Firmament.identifier("cape/parallax")) + .withSampler("Sampler0") + .withSampler("Sampler1") + .withSampler("Sampler3") + .withUniform("Animation", UniformType.FLOAT) + .build() } object CustomRenderLayers { diff --git a/src/main/resources/assets/firmament/shaders/cape/parallax.fsh b/src/main/resources/assets/firmament/shaders/cape/parallax.fsh new file mode 100644 index 0000000..bc9a440 --- /dev/null +++ b/src/main/resources/assets/firmament/shaders/cape/parallax.fsh @@ -0,0 +1,53 @@ +#version 150 + +#moj_import +#define M_PI 3.1415926535897932384626433832795 +#define M_TAU (2.0 * M_PI) +uniform sampler2D Sampler0; +uniform sampler2D Sampler1; +uniform sampler2D Sampler3; + +uniform vec4 ColorModulator; +uniform float FogStart; +uniform float FogEnd; +uniform vec4 FogColor; +uniform float Animation; + +in float vertexDistance; +in vec4 vertexColor; +in vec4 lightMapColor; +in vec4 overlayColor; +in vec2 texCoord0; + +out vec4 fragColor; + +float highlightDistance(vec2 coord, vec2 direction, float time) { + vec2 dir = normalize(direction); + float projection = dot(coord, dir); + float animationTime = sin(projection + time * 13 * M_TAU); + if (animationTime < 0.997) { + return 0.0; + } + return animationTime; +} + +void main() { + vec4 color = texture(Sampler0, texCoord0); + if (color.g > 0.99) { + // TODO: maybe this speed in each direction should be a uniform + color = texture(Sampler1, texCoord0 + Animation * vec2(3.0, -2.0)); + } + + vec4 highlightColor = texture(Sampler3, texCoord0); + if (highlightColor.a > 0.5) { + color = highlightColor; + float animationHighlight = highlightDistance(texCoord0, vec2(-12.0, 2.0), Animation); + color.rgb += (animationHighlight); + } + #ifdef ALPHA_CUTOUT + if (color.a < ALPHA_CUTOUT) { + discard; + } + #endif + fragColor = linear_fog(color, vertexDistance, FogStart, FogEnd, FogColor); +} diff --git a/src/main/resources/assets/firmament/textures/cape/REUSE.toml b/src/main/resources/assets/firmament/textures/cape/REUSE.toml new file mode 100644 index 0000000..7cb21f2 --- /dev/null +++ b/src/main/resources/assets/firmament/textures/cape/REUSE.toml @@ -0,0 +1,16 @@ +#SPDX-FileCopyrightText: 2025 Linnea Gräf +# +#SPDX-License-Identifier: CC0-1.0 +version = 1 + +[[annotations]] +path = ["firmament_star.png", "parallax_background.png", "parallax_template.png"] +SPDX-License-Identifier = "CC-BY-4.0" +SPDX-FileCopyrightText = ["ic22487", "Linnea Gräf"] + +[[annotations]] +path = ["firm_static.png"] +SPDX-License-Identifier = "CC-BY-4.0" +SPDX-FileCopyrightText = ["ic22487", "kathund"] + + diff --git a/src/main/resources/assets/firmament/textures/cape/firm_static.png b/src/main/resources/assets/firmament/textures/cape/firm_static.png new file mode 100644 index 0000000000000000000000000000000000000000..b01511c8378752d63e87e9237371f97bde51f1ed GIT binary patch literal 42249 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

%ak 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�J(7|Ys_GA+Y5Y!^^ywR>tKWP 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 Ri+1~Jbk*$2+e^3Z{||?RM0x-K literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/firmament/textures/cape/firmament_star.png b/src/main/resources/assets/firmament/textures/cape/firmament_star.png new file mode 100644 index 0000000000000000000000000000000000000000..520d309c2d7c8398104aa567d63e4330a2508436 GIT binary patch literal 1141 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58aUX1%y{W;-5&-9 z7IjY-$B>G+w>S4@i3Ex;JlO1ba@nSB;zt_z6*}}4mI(xRwMN{Y<>Wg1MpSpl+NhO# z6`H0s32YRoVQ{>pvb$CC`x~owZzgycS*s-e(2F^A?*87-zUTh-PT&wwaA;s)WMZM5 zF@fp+`)}Ret}dpN6&)UYU=ib6zrxcqbwm1x`E?dOv$YMgm{gcp`kWSgWqa^FOeFQ+ zPo=WA59i-~Ex!C5f0Ciyv8S&W3R-mOulHe6Zj6)WlKk+rxNdLnjX#&<|Nr?=Dc~RP zf9k}7_0y*Atv6#hyhA`gJdK^v{N9$}^=9|Z8grCHCahyqsQz)}WW)J{^C4_CvTxrM ziS(OSZQSzNu1w7D+?;c635B~m9tP>>>5G4SvYKtd>Hj77)-p3m{yD$ir|4^GQQ!XS zCJ(Od)cCaT|JtKgY$k9u^xsUk2k)yK zCI3{;b!j;8kaJE((3QpE&Gm=B6iIzZ-fPAiG1rIl)yqdSPfm={Ua>6c#uBx6iVg{K zjmNSXZthM$`1H>Hm>s|4_2)&`?R+&q^X^Ph9xsTLSCx+ypC{F7l# z$&ZWQSijwNw{k&gX_=$GIM3&M`O=pkXD?~1hvxEs5wOBPg&6)%=fZ>eiC2o_Y+jAc)I$z JtaD0e0swY5VB`P* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/firmament/textures/cape/parallax_background.png b/src/main/resources/assets/firmament/textures/cape/parallax_background.png new file mode 100644 index 0000000000000000000000000000000000000000..05ef0faf8ecc4cb73d31d2bf5b02b12e0829c39d GIT binary patch literal 2053 zcmXX{dpy(o8~?7EX=H8@5h^EU&W=u57uU&c#N1L!W0ceDI7=$Mbn!pXYgA@Av!l`Fx(wlTGmV+JG=Y006MT z$NNB#%Cl7Fs-do0U%yL9QMvW;-bW|^psBZJkk^Au1pvV7d=9vU(2mbU_+}mRFt|7C z*RXISdk-j%xrM`h=0QrM)pYgLd=4SfG|1=1JM(OHrS*wZILjLz%mGbn(t?&z2!Rz5B$8 zbE8klza+X0tppuiV1UZkdAyg)w4bF?!tpw?U#Rn?h&bc(&xgra;pY_I>O7_VPrbr4 z>k|YL@`{4}sNB0Qp~b;v22)v?LydP~4oA<9+%}hrr!&bBqoLS=h6$7BqsRNI)M&is zS-3HW@oK5pQWTLZ9o_pVdG$#<@$f$4_VsEb8TXmbORcC&PUJL2LaDnFgWv!#Jj*CM zj1){O*TTm=Xwu%=$^F`KbbG{Z=UVcX-h5imhV@=tvw(y7h!1w(!UyQAT0$yE^1ykm zT+p;6*2l;<0U6}JtH_`d3xW2a&??{E)9;Lv&Q34nU~;@nfjnJ`c%ww=K$s6?dN7= zqszRTgMoorDZWa46f#Mki7PN_u+oFA(|JqZiFshw3ZJ*&!p3;SWztuDWl{~3Vh3sJ zvpb~mM7t);r11KnBM}ori0WN(tnG!T>HxudIp90oN1g_&7uf$1OVoTwbWKbKdzRSR&88Y>ba6^E2Nw-@ka3OcyW1+A16CE>O4WEW1~K`#9D}o{Le&JvB^%NrOrH<|**{ zRi4>`~1GTsaF{dj;*i zV?J5SPZo_Y7750XB>Da=>V2(S$_8*#MdZ*qigz=0X7;9MwDj%Clm6p2rM-7$FF2di}mS0VM72Jh+GD{aUnXaqd zw>-s9-Zl}WxhHYd`V-l>Zw|}8Wxu&s$emfelT#Kimtsu@JTCMjrsIFE#;GrH))mfR zHnPUtt0dQMvuQohc_y0MQJL}gJ%5>dHSb+3k0arD*`(_=9)s7GwX_OEc_JgMao=zg z?*nt6W1$Vkh+ya|C|#befkUk4fbTo z<5;_*{6X@}qItR^o4etgvIVoifLNFveRlsJ7|~nEji{=f5ya>HudC#VX2-@7Fd%llzGMi4amS;ro{`Yzqvz>Y$oGtr*r( zWP6uiUa7{mfOq}TS?*edaQcN6Hm$Koyc-I0IEK-#K5Vr~v{c|$9Pttk*6$zY)GsJR z0e>hyK7;g{I(ND4f3dO+9uSHiV!BARD?}Ba@x~lUIXu$qv!4a${TIG_AT_7Z!sQUj z@buIfSZ6rVC2~1k>vtjXAw!WtMI8|Akc!2Yy$vSf$@}>mi>j64iixCw7 zr&6H&#dA}i>iZ3xQ774LfOmF>VC|t4*aI3w1)UmJkc(_^a?P%%4QV1BS;=~*2Wt?G z<}rjN#%+M2S+L-d>J1WQ(3t9sWP$cId2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/firmament/textures/cape/parallax_template.png b/src/main/resources/assets/firmament/textures/cape/parallax_template.png new file mode 100644 index 0000000000000000000000000000000000000000..ada76eb2dad1701526469aab358ef04f7c0efd1e GIT binary patch literal 516 zcmV+f0{i`mP)K`K@i4gFE6I|Gx_-0E1YtCrg0 z3XI<#vhJg+zVV6WGp=tepYdk3F*u3)%f46t)kX(UtWOzS^nxHr3oV;-;v+_~4GEv; z1}Q*44j>QreD|o7bsM@?0>Xl1c0*#Lxb|r`>ym8N-EXQ9&ODcdj7M$N0LV`sMZaG^ zJMmN#h$!T6?iOxF!)|a`pyLc)AOl2Fz-#)_d_=J5Ks083rLm5xS{~HIm>=#7~ z*$Tq^%^5g(12#I@PdA-~x zmof1BZh+b1dbptdi_3u14eA^)OC0S1W~0WbUGH0fmO