From c82c051704424763c20742b616228cfe636b9f65 Mon Sep 17 00:00:00 2001 From: nea Date: Sat, 9 Sep 2023 04:50:29 +0200 Subject: Add custom textures to placed skulls --- .../nea/firmament/features/debug/PowerUserTools.kt | 31 ++++++++++++ .../features/texturepack/CustomSkyBlockTextures.kt | 55 +++++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) (limited to 'src/main/kotlin/moe/nea/firmament/features') diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt index 398042d..52834f3 100644 --- a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt @@ -6,17 +6,24 @@ package moe.nea.firmament.features.debug +import net.minecraft.block.SkullBlock +import net.minecraft.block.entity.SkullBlockEntity import net.minecraft.item.ItemStack import net.minecraft.text.Text +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.hit.HitResult import moe.nea.firmament.events.CustomItemModelEvent import moe.nea.firmament.events.HandledScreenKeyPressedEvent import moe.nea.firmament.events.ItemTooltipEvent import moe.nea.firmament.events.ScreenOpenEvent import moe.nea.firmament.events.TickEvent +import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.features.FirmamentFeature +import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.mixins.accessor.AccessorHandledScreen import moe.nea.firmament.util.ClipboardUtils +import moe.nea.firmament.util.MC import moe.nea.firmament.util.skyBlockId object PowerUserTools : FirmamentFeature { @@ -28,6 +35,7 @@ object PowerUserTools : FirmamentFeature { val copyItemId by keyBindingWithDefaultUnbound("copy-item-id") val copyTexturePackId by keyBindingWithDefaultUnbound("copy-texture-pack-id") val copyNbtData by keyBindingWithDefaultUnbound("copy-nbt-data") + val copySkullTexture by keyBindingWithDefaultUnbound("copy-skull-texture") } override val config @@ -55,6 +63,29 @@ object PowerUserTools : FirmamentFeature { lastCopiedStackViewTime = true it.lines.add(text) } + WorldKeyboardEvent.subscribe { + if (it.matches(TConfig.copySkullTexture)) { + val p = MC.camera ?: return@subscribe + val blockHit = p.raycast(20.0, 0.0f, false) ?: return@subscribe + if (blockHit.type != HitResult.Type.BLOCK || blockHit !is BlockHitResult) { + MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + return@subscribe + } + val blockAt = p.world.getBlockState(blockHit.blockPos)?.block + val entity = p.world.getBlockEntity(blockHit.blockPos) + if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.owner == null) { + MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + return@subscribe + } + val id = CustomSkyBlockTextures.getSkullTexture(entity.owner!!) + if (id == null) { + MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + } else { + ClipboardUtils.setTextContent(id.toString()) + MC.sendChat(Text.translatable("firmament.tooltip.copied.skull", id.toString())) + } + } + } TickEvent.subscribe { if (!lastCopiedStackViewTime) lastCopiedStack = null diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt index b086811..66c0987 100644 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt @@ -6,11 +6,21 @@ package moe.nea.firmament.features.texturepack +import com.mojang.authlib.GameProfile +import com.mojang.authlib.minecraft.MinecraftProfileTexture +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable +import net.minecraft.block.SkullBlock +import net.minecraft.client.MinecraftClient +import net.minecraft.client.render.RenderLayer +import net.minecraft.client.texture.PlayerSkinProvider import net.minecraft.client.util.ModelIdentifier +import net.minecraft.util.Identifier import moe.nea.firmament.events.CustomItemModelEvent import moe.nea.firmament.events.TickEvent import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.IdentityCharacteristics +import moe.nea.firmament.util.item.decodeProfileTextureProperty import moe.nea.firmament.util.skyBlockId object CustomSkyBlockTextures : FirmamentFeature { @@ -19,6 +29,7 @@ object CustomSkyBlockTextures : FirmamentFeature { object TConfig : ManagedConfig(identifier) { val enabled by toggle("enabled") { true } + val skullsEnabled by toggle("skulls-enabled") { true } val cacheDuration by integer("cache-duration", 0, 20) { 1 } } @@ -32,8 +43,50 @@ object CustomSkyBlockTextures : FirmamentFeature { it.overrideModel = ModelIdentifier("firmskyblock", id.identifier.path, "inventory") } TickEvent.subscribe { - if (it.tickCount % TConfig.cacheDuration == 0) + if (it.tickCount % TConfig.cacheDuration == 0) { CustomItemModelEvent.clearCache() + skullTextureCache.clear() + } } } + + private val skullTextureCache = mutableMapOf, Any>() + private val sentinelPresentInvalid = Object() + + val mcUrlRegex = "https?://textures.minecraft.net/texture/([a-fA-F0-9]+)".toRegex() + fun getSkullId(profile: GameProfile): String? { + val textures = profile.properties.get(PlayerSkinProvider.TEXTURES) + val textureProperty = textures.singleOrNull() ?: return null + val texture = decodeProfileTextureProperty(textureProperty) ?: return null + val textureUrl = + texture.textures[MinecraftProfileTexture.Type.SKIN]?.url ?: return null + val mcUrlData = mcUrlRegex.matchEntire(textureUrl) ?: return null + return mcUrlData.groupValues[1] + } + + fun getSkullTexture(profile: GameProfile): Identifier? { + val id = getSkullId(profile) ?: return null + return Identifier("firmskyblock", "textures/placedskull/$id.png") + } + + fun modifySkullTexture( + type: SkullBlock.SkullType?, + profile: GameProfile?, + cir: CallbackInfoReturnable + ) { + if (type != SkullBlock.Type.PLAYER) return + if (!TConfig.skullsEnabled) return + if (profile == null) return + val ic = IdentityCharacteristics(profile) + + val n = skullTextureCache.getOrPut(ic) { + val id = getSkullTexture(profile) ?: return@getOrPut sentinelPresentInvalid + if (!MinecraftClient.getInstance().resourceManager.getResource(id).isPresent) { + return@getOrPut sentinelPresentInvalid + } + return@getOrPut id + } + if (n === sentinelPresentInvalid) return + cir.returnValue = RenderLayer.getEntityTranslucent(n as Identifier) + } } -- cgit