From d50781da77ca101d9d50a95f7b2d6fb1c03bc9fb Mon Sep 17 00:00:00 2001 From: Saad Nadeem Date: Sat, 17 Oct 2026 03:56:04 -0400 Subject: [PATCH 1/3] fix(legacy): refresh skin after account switch --- .../client/gui/preview/PlayerPreviewRenderer.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt b/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt index 5fa45d3..d93955a 100644 --- a/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt +++ b/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt @@ -1347,6 +1347,7 @@ import org.polyfrost.polyplus.client.render.PoseStack import org.polyfrost.polyplus.client.utils.ClientPlatform import kotlinx.coroutines.launch import java.util.Collections +import java.util.UUID import org.slf4j.LoggerFactory import java.util.concurrent.ConcurrentHashMap @@ -1662,18 +1663,22 @@ object PlayerPreviewRenderer { @Volatile private var fetchedSkin: Pair? = null - private var skinRequested = false + private var skinRequestedFor: UUID? = null private fun localSkin(mc: Minecraft): Pair { mc.player?.let { return it.skinTextureLocation to (it.modelType == "slim") } - fetchedSkin?.let { return it } val profile = mc.session.profile - if (!skinRequested) { - skinRequested = true + if (skinRequestedFor != profile.id) { + val id = profile.id + skinRequestedFor = id + fetchedSkin = null mc.skinManager.register(profile, { type, location, texture -> - if (type == MinecraftProfileTexture.Type.SKIN) fetchedSkin = location to (texture.getMetadata("model") == "slim") + if (type == MinecraftProfileTexture.Type.SKIN && skinRequestedFor == id) { + fetchedSkin = location to (texture.getMetadata("model") == "slim") + } }, false) } + fetchedSkin?.let { return it } return DefaultSkinUtils.getDefaultSkin(profile.id) to (DefaultSkinUtils.getDefaultModelType(profile.id) == "slim") } From eac0b80ac9cd275e03efd8805bfc4a89d2dddf6c Mon Sep 17 00:00:00 2001 From: Saad Nadeem Date: Sat, 17 Oct 2026 05:33:45 -0400 Subject: [PATCH 2/3] fix(legacy): show mojang capes --- .../client/gui/preview/PlayerPreviewRenderer.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt b/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt index d93955a..8fbff27 100644 --- a/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt +++ b/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt @@ -1624,10 +1624,11 @@ object PlayerPreviewRenderer { private fun capeFor(mc: Minecraft, source: PlayerPreviewSource): Identifier? = when (source) { is PlayerPreviewSource.Override -> if (source.equipment.get(BodySlot.Backpack) != null) null - else source.capeCosmeticId?.let(CosmeticAssetCache::getCapeResource) + else source.capeCosmeticId?.let(CosmeticAssetCache::getCapeResource) ?: accountCape(mc) PlayerPreviewSource.LocalLive -> CosmeticCatalog.localEquipped().cape?.let(CosmeticAssetCache::getCapeResource) ?: mc.player?.capeTextureLocation + ?: accountCape(mc) } private fun equipmentFor(source: PlayerPreviewSource): CosmeticEquipment = when (source) { @@ -1663,6 +1664,8 @@ object PlayerPreviewRenderer { @Volatile private var fetchedSkin: Pair? = null + @Volatile + private var fetchedCape: Identifier? = null private var skinRequestedFor: UUID? = null private fun localSkin(mc: Minecraft): Pair { @@ -1672,9 +1675,12 @@ object PlayerPreviewRenderer { val id = profile.id skinRequestedFor = id fetchedSkin = null + fetchedCape = null mc.skinManager.register(profile, { type, location, texture -> - if (type == MinecraftProfileTexture.Type.SKIN && skinRequestedFor == id) { - fetchedSkin = location to (texture.getMetadata("model") == "slim") + if (skinRequestedFor == id) when (type) { + MinecraftProfileTexture.Type.SKIN -> fetchedSkin = location to (texture.getMetadata("model") == "slim") + MinecraftProfileTexture.Type.CAPE -> fetchedCape = location + else -> {} } }, false) } @@ -1682,6 +1688,9 @@ object PlayerPreviewRenderer { return DefaultSkinUtils.getDefaultSkin(profile.id) to (DefaultSkinUtils.getDefaultModelType(profile.id) == "slim") } + private fun accountCape(mc: Minecraft): Identifier? = + fetchedCape.takeIf { skinRequestedFor == mc.session.profile.id } + private fun readback(fbo: RenderTarget, w: Int, h: Int): ImageBitmap { val data = BufferUtils.createByteBuffer(w * h * 4) withSavedFramebuffer { From 15b42d79cd074d04cd10cf1da9629269e6d89b10 Mon Sep 17 00:00:00 2001 From: Saad Nadeem Date: Sat, 17 Oct 2026 05:34:26 -0400 Subject: [PATCH 3/3] feat(legacy): show optifine capes if cera is enabled --- .../gui/preview/PlayerPreviewRenderer.kt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt b/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt index 8fbff27..3741a3e 100644 --- a/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt +++ b/src/main/kotlin/org/polyfrost/polyplus/client/gui/preview/PlayerPreviewRenderer.kt @@ -1345,6 +1345,10 @@ import org.polyfrost.polyplus.client.network.http.responses.BodySlot import org.polyfrost.polyplus.client.render.PlayerRenderContext import org.polyfrost.polyplus.client.render.PoseStack import org.polyfrost.polyplus.client.utils.ClientPlatform +import org.polyfrost.polyplus.PolyPlusConstants +import net.minecraft.client.render.texture.HttpImageProcessor +import net.minecraft.client.render.texture.HttpTexture +import java.awt.image.BufferedImage import kotlinx.coroutines.launch import java.util.Collections import java.util.UUID @@ -1628,6 +1632,7 @@ object PlayerPreviewRenderer { PlayerPreviewSource.LocalLive -> CosmeticCatalog.localEquipped().cape?.let(CosmeticAssetCache::getCapeResource) ?: mc.player?.capeTextureLocation + ?: optifineCape(mc) ?: accountCape(mc) } @@ -1691,6 +1696,44 @@ object PlayerPreviewRenderer { private fun accountCape(mc: Minecraft): Identifier? = fetchedCape.takeIf { skinRequestedFor == mc.session.profile.id } + private val OPTIFINE_USERNAME = Regex("[A-Za-z0-9_]+") + private val optifineCapesRequested = ConcurrentHashMap.newKeySet() + private val optifineCapesLoaded = ConcurrentHashMap.newKeySet() + + private fun optifineCape(mc: Minecraft): Identifier? { + if (!ceraOptifineCapes()) return null + val name = mc.session.username + if (!name.matches(OPTIFINE_USERNAME)) return null + val location = Identifier.fromNamespaceAndPath(PolyPlusConstants.ID, "optifine_cape/${name.lowercase()}") + if (optifineCapesRequested.add(name)) { + mc.textureManager.register(location, HttpTexture(null, "https://optifine.net/capes/$name.png", null, object : HttpImageProcessor { + override fun process(image: BufferedImage): BufferedImage { + var width = 64 + var height = 32 + while (width < image.width || height < image.height) { + width *= 2 + height *= 2 + } + return BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB).apply { + graphics.apply { drawImage(image, 0, 0, null); dispose() } + } + } + + override fun onTextureDownloaded() { + optifineCapesLoaded.add(name) + } + })) + } + return location.takeIf { name in optifineCapesLoaded } + } + + private val ceraConfig by lazy { runCatching { Class.forName("dev.rdh.cera.Cera").getField("CONFIG") }.getOrNull() } + + private fun ceraOptifineCapes(): Boolean = runCatching { + val config = ceraConfig?.get(null) ?: return false + config.javaClass.getField("optifineCosmetics").getBoolean(config) + }.getOrDefault(false) + private fun readback(fbo: RenderTarget, w: Int, h: Int): ImageBitmap { val data = BufferUtils.createByteBuffer(w * h * 4) withSavedFramebuffer {