diff options
| author | Linnea Gräf <nea@nea.moe> | 2025-06-23 13:34:02 +0200 |
|---|---|---|
| committer | Linnea Gräf <nea@nea.moe> | 2025-06-23 13:34:02 +0200 |
| commit | 051668fe9ac8d02fd9546e588d4255ee5e120f40 (patch) | |
| tree | c36e1415e78c37c71b0abaab3099349d8650d9dd /src/main/kotlin | |
| parent | 72b8d8c8a37cd4396de44f0bcd2a9e8bd4b073b9 (diff) | |
| download | Firmament-051668fe9ac8d02fd9546e588d4255ee5e120f40.tar.gz Firmament-051668fe9ac8d02fd9546e588d4255ee5e120f40.tar.bz2 Firmament-051668fe9ac8d02fd9546e588d4255ee5e120f40.zip | |
feat: Add dev capes
Diffstat (limited to 'src/main/kotlin')
| -rw-r--r-- | src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt | 5 | ||||
| -rw-r--r-- | src/main/kotlin/features/misc/CustomCapes.kt | 165 | ||||
| -rw-r--r-- | src/main/kotlin/features/misc/Devs.kt | 16 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/CustomRenderLayers.kt | 9 |
4 files changed, 192 insertions, 3 deletions
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<UUID>, + ) { + 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 { |
