aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/features/misc/CustomCapes.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/features/misc/CustomCapes.kt')
-rw-r--r--src/main/kotlin/features/misc/CustomCapes.kt192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/main/kotlin/features/misc/CustomCapes.kt b/src/main/kotlin/features/misc/CustomCapes.kt
new file mode 100644
index 0000000..dc5187a
--- /dev/null
+++ b/src/main/kotlin/features/misc/CustomCapes.kt
@@ -0,0 +1,192 @@
+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.client.util.SkinTextures
+import net.minecraft.util.Identifier
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.features.FirmamentFeature
+import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.TimeMark
+
+object CustomCapes : FirmamentFeature {
+ override val identifier: String
+ get() = "developer-capes"
+
+ object TConfig : ManagedConfig(identifier, Category.DEV) {
+ val showCapes by toggle("show-cape") { true }
+ }
+
+ override val config: ManagedConfig
+ get() = TConfig
+
+ 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_STATIC(
+ "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(
+ listOf(
+ Devs.nea to AllCapes.FIRMAMENT_ANIMATED,
+ Devs.kath to AllCapes.FIRMAMENT_STATIC,
+ Devs.jani to AllCapes.FIRMAMENT_ANIMATED,
+ ),
+ Devs.FurfSky.all.map { it to AllCapes.FURFSKY_STATIC },
+ ).flatten().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 = if (TConfig.showCapes) byUuid[player.uuid] else null
+ val capeStorage = CapeStorage.cast(playerEntityRenderState)
+ if (cape == null) {
+ capeStorage.cape_firmament = null
+ } else {
+ capeStorage.cape_firmament = cape
+ playerEntityRenderState.skinTextures = SkinTextures(
+ playerEntityRenderState.skinTextures.texture,
+ playerEntityRenderState.skinTextures.textureUrl,
+ Firmament.identifier("placeholder/fake_cape"),
+ playerEntityRenderState.skinTextures.elytraTexture,
+ playerEntityRenderState.skinTextures.model,
+ playerEntityRenderState.skinTextures.secure,
+ )
+ playerEntityRenderState.capeVisible = true
+ }
+ }
+
+ val startTime = TimeMark.now()
+}