From d188f0135b13ed23a77d46db4ed2040dc1b14bf7 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Fri, 8 Jul 2022 08:51:53 +0200 Subject: added ItemDisplayOverlayFeatures --- .../at/lorenz/mod/ItemDisplayOverlayFeatures.kt | 114 ++++++++++++++++ src/main/java/at/lorenz/mod/config/LorenzConfig.kt | 7 + .../at/lorenz/mod/events/GuiRenderItemEvent.kt | 23 ++++ .../at/lorenz/mod/mixinhooks/RenderItemHook.kt | 85 ++++++++++++ .../java/at/lorenz/mod/mixins/MixinRenderItem.java | 42 ++++++ src/main/java/at/lorenz/mod/utils/ItemUtils.kt | 12 ++ src/main/java/at/lorenz/mod/utils/LorenzUtils.kt | 2 + src/main/java/at/lorenz/mod/utils/NumberUtil.kt | 152 +++++++++++++++++++++ 8 files changed, 437 insertions(+) create mode 100644 src/main/java/at/lorenz/mod/ItemDisplayOverlayFeatures.kt create mode 100644 src/main/java/at/lorenz/mod/events/GuiRenderItemEvent.kt create mode 100644 src/main/java/at/lorenz/mod/mixinhooks/RenderItemHook.kt create mode 100644 src/main/java/at/lorenz/mod/mixins/MixinRenderItem.java create mode 100644 src/main/java/at/lorenz/mod/utils/NumberUtil.kt (limited to 'src/main/java/at/lorenz') diff --git a/src/main/java/at/lorenz/mod/ItemDisplayOverlayFeatures.kt b/src/main/java/at/lorenz/mod/ItemDisplayOverlayFeatures.kt new file mode 100644 index 000000000..ec5078bdc --- /dev/null +++ b/src/main/java/at/lorenz/mod/ItemDisplayOverlayFeatures.kt @@ -0,0 +1,114 @@ +package at.lorenz.mod + +import at.lorenz.mod.config.LorenzConfig +import at.lorenz.mod.events.GuiRenderItemEvent +import at.lorenz.mod.utils.ItemUtils +import at.lorenz.mod.utils.ItemUtils.Companion.cleanName +import at.lorenz.mod.utils.LorenzUtils +import at.lorenz.mod.utils.LorenzUtils.Companion.between +import at.lorenz.mod.utils.LorenzUtils.Companion.matchRegex +import at.lorenz.mod.utils.NumberUtil.romanToDecimal +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class ItemDisplayOverlayFeatures { + + @SubscribeEvent + fun onRenderItemOverlayPost(event: GuiRenderItemEvent.RenderOverlayEvent.Post) { + val item = event.stack ?: return + + //TODO add +// if (!Utils.inSkyblock || item.stackSize != 1 || item.tagCompound?.hasKey("SkytilsNoItemOverlay") == true) return + if (item.stackSize != 1 || item.tagCompound?.hasKey("SkytilsNoItemOverlay") == true) return + + val stackTip = getStackTip(item) + + if (stackTip.isNotEmpty()) { + GlStateManager.disableLighting() + GlStateManager.disableDepth() + GlStateManager.disableBlend() + event.fr.drawStringWithShadow( + stackTip, + (event.x + 17 - event.fr.getStringWidth(stackTip)).toFloat(), + (event.y + 9).toFloat(), + 16777215 + ) + GlStateManager.enableLighting() + GlStateManager.enableDepth() + } + + } + + private fun getStackTip(item: ItemStack): String { + val name = item.cleanName() + + if (LorenzConfig.lorenzItemDisplayMasterStarSkullNumber) { + when (name) { + "First Master Star" -> return "1" + "Second Master Star" -> return "2" + "Third Master Star" -> return "3" + "Fourth Master Star" -> return "4" + "Fifth Master Star" -> return "5" + } + + if (name.matchRegex("(.*)Master Skull - Tier .")) { + return name.substring(name.length - 1) + } + + } + + if (LorenzConfig.lorenzItemDisplayDungeonHeadNumber) { + if (name.contains("Golden ") || name.contains("Diamond ")) { + when { + name.contains("Bonzo") -> return "1" + name.contains("Scarf") -> return "2" + name.contains("Professor") -> return "3" + name.contains("Thorn") -> return "4" + name.contains("Livid") -> return "5" + name.contains("Sadan") -> return "6" + name.contains("Necron") -> return "7" + } + } + } + + if (LorenzConfig.lorenzItemDisplayNewYearCakeNumber) { + if (name.startsWith("New Year Cake")) { + return "§b" + name.split("(Year ", ")")[1] + } + } + + if (LorenzConfig.lorenzItemDisplayPetLevel) { + if (ItemUtils.isPet(name)) { + try { + val level = name.between("Lvl ", "] ").toInt() + if (level != ItemUtils.maxPetLevel(name)) { + return "$level" + } + } catch (e: java.lang.NumberFormatException) { + e.printStackTrace() + LorenzDebug.log("name: '$name'") + LorenzUtils.warning("NumberFormatException at lorenzItemDisplayPetLevel") + } + } + } + + if (LorenzConfig.lorenzItemSackNameDisplay) { + if (ItemUtils.isSack(name)) { + val split = name.split(" ") + val sackName = split[split.size - 2] + return (if (name.contains("Enchanted")) "§5" else "") + sackName.substring(0, 2) + } + } + + if (LorenzConfig.lorenzItemDisplayMinionTier) { + if (name.contains(" Minion ")) { + val array = name.split(" ") + val last = array[array.size - 1] + return last.romanToDecimal().toString() + } + } + + return "" + } +} \ No newline at end of file diff --git a/src/main/java/at/lorenz/mod/config/LorenzConfig.kt b/src/main/java/at/lorenz/mod/config/LorenzConfig.kt index 3877ec4e0..4d34134f8 100644 --- a/src/main/java/at/lorenz/mod/config/LorenzConfig.kt +++ b/src/main/java/at/lorenz/mod/config/LorenzConfig.kt @@ -9,5 +9,12 @@ class LorenzConfig { val lorenzBazaarOrderHelper = true val lorenzDungeonHighlightClickedBlocks = true + + val lorenzItemDisplayMasterStarSkullNumber = true + val lorenzItemDisplayDungeonHeadNumber = true + val lorenzItemDisplayNewYearCakeNumber = true + val lorenzItemDisplayPetLevel = true + val lorenzItemSackNameDisplay = true + val lorenzItemDisplayMinionTier = true } } \ No newline at end of file diff --git a/src/main/java/at/lorenz/mod/events/GuiRenderItemEvent.kt b/src/main/java/at/lorenz/mod/events/GuiRenderItemEvent.kt new file mode 100644 index 000000000..a1af62c69 --- /dev/null +++ b/src/main/java/at/lorenz/mod/events/GuiRenderItemEvent.kt @@ -0,0 +1,23 @@ +package at.lorenz.mod.events + +import net.minecraft.client.gui.FontRenderer +import net.minecraft.item.ItemStack + +abstract class GuiRenderItemEvent : LorenzEvent() { + abstract class RenderOverlayEvent( + open val fr: FontRenderer, + open val stack: ItemStack?, + open val x: Int, + open val y: Int, + open val text: String? + ) : GuiRenderItemEvent() { + data class Post( + override val fr: FontRenderer, + override val stack: ItemStack?, + override val x: Int, + override val y: Int, + override val text: String? + ) : + RenderOverlayEvent(fr, stack, x, y, text) + } +} \ No newline at end of file diff --git a/src/main/java/at/lorenz/mod/mixinhooks/RenderItemHook.kt b/src/main/java/at/lorenz/mod/mixinhooks/RenderItemHook.kt new file mode 100644 index 000000000..0291782b7 --- /dev/null +++ b/src/main/java/at/lorenz/mod/mixinhooks/RenderItemHook.kt @@ -0,0 +1,85 @@ +package at.lorenz.mod.mixinhooks + +import at.lorenz.mod.events.GuiRenderItemEvent +import net.minecraft.client.gui.FontRenderer +import net.minecraft.item.ItemStack +import net.minecraft.util.ResourceLocation +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo + +val RES_ITEM_GLINT = ResourceLocation("textures/misc/enchanted_item_glint.png") + +var skipGlint = false + +//fun renderRarity(stack: ItemStack, x: Int, y: Int, ci: CallbackInfo) { +// if (Utils.inSkyblock && Skytils.config.showItemRarity) { +// if (mc.currentScreen != null) { +// if (isStorageMenuActive || isTradeWindowActive || isCustomAHActive) { +// renderRarity(stack, x, y) +// } +// } +// } +//} + +fun renderItemOverlayPost( + fr: FontRenderer, + stack: ItemStack?, + xPosition: Int, + yPosition: Int, + text: String?, + ci: CallbackInfo +) { + GuiRenderItemEvent.RenderOverlayEvent.Post( + fr, + stack, + xPosition, + yPosition, + text + ).postAndCatch() +} + +//fun renderItemPre(stack: ItemStack, model: IBakedModel, ci: CallbackInfo) { +// if (!Utils.inSkyblock) return +// if (stack.item === Items.skull) { +// val scale = Skytils.config.largerHeadScale.toDouble() +// GlStateManager.scale(scale, scale, scale) +// } +//} + +//fun modifyGlintRendering(stack: ItemStack, model: IBakedModel, ci: CallbackInfo) { +// if (Utils.inSkyblock) { +// val itemId = getSkyBlockItemID(stack) +// if (GlintCustomizer.glintColors.containsKey(itemId)) { +// val color = GlintCustomizer.glintColors[itemId]!!.toInt() +// GlStateManager.depthMask(false) +// GlStateManager.depthFunc(514) +// GlStateManager.disableLighting() +// GlStateManager.blendFunc(768, 1) +// mc.textureManager.bindTexture(RES_ITEM_GLINT) +// GlStateManager.matrixMode(5890) +// GlStateManager.pushMatrix() +// GlStateManager.scale(8.0f, 8.0f, 8.0f) +// val f = (Minecraft.getSystemTime() % 3000L).toFloat() / 3000.0f / 8.0f +// GlStateManager.translate(f, 0.0f, 0.0f) +// GlStateManager.rotate(-50.0f, 0.0f, 0.0f, 1.0f) +// (mc.renderItem as AccessorRenderItem).invokeRenderModel(model, color) +// GlStateManager.popMatrix() +// GlStateManager.pushMatrix() +// GlStateManager.scale(8.0f, 8.0f, 8.0f) +// val f1 = (Minecraft.getSystemTime() % 4873L).toFloat() / 4873.0f / 8.0f +// GlStateManager.translate(-f1, 0.0f, 0.0f) +// GlStateManager.rotate(10.0f, 0.0f, 0.0f, 1.0f) +// (mc.renderItem as AccessorRenderItem).invokeRenderModel(model, color) +// GlStateManager.popMatrix() +// GlStateManager.matrixMode(5888) +// GlStateManager.blendFunc(770, 771) +// GlStateManager.enableLighting() +// GlStateManager.depthFunc(515) +// GlStateManager.depthMask(true) +// mc.textureManager.bindTexture(TextureMap.locationBlocksTexture) +// ci.cancel() +// +// //Since we prematurely exited, we need to reset the matrices +// GlStateManager.popMatrix() +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/at/lorenz/mod/mixins/MixinRenderItem.java b/src/main/java/at/lorenz/mod/mixins/MixinRenderItem.java new file mode 100644 index 000000000..06275b4dd --- /dev/null +++ b/src/main/java/at/lorenz/mod/mixins/MixinRenderItem.java @@ -0,0 +1,42 @@ +package at.lorenz.mod.mixins; + +import at.lorenz.mod.mixinhooks.RenderItemHookKt; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.resources.model.IBakedModel; +import net.minecraft.item.ItemStack; +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(RenderItem.class) +public abstract class MixinRenderItem { +// @Inject(method = "renderItemIntoGUI", at = @At("HEAD")) +// private void renderRarity(ItemStack stack, int x, int y, CallbackInfo ci) { +// RenderItemHookKt.renderRarity(stack, x, y, ci); +// } + + @Inject(method = "renderItemOverlayIntoGUI", at = @At("RETURN")) + private void renderItemOverlayPost(FontRenderer fr, ItemStack stack, int xPosition, int yPosition, String text, CallbackInfo ci) { + RenderItemHookKt.renderItemOverlayPost(fr, stack, xPosition, yPosition, text, ci); + } + +// @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/resources/model/IBakedModel;)V", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/GlStateManager.scale(FFF)V", shift = At.Shift.AFTER)) +// private void renderItemPre(ItemStack stack, IBakedModel model, CallbackInfo ci) { +// RenderItemHookKt.renderItemPre(stack, model, ci); +// } +// +// @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/resources/model/IBakedModel;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderItem;renderEffect(Lnet/minecraft/client/resources/model/IBakedModel;)V", shift = At.Shift.BEFORE), cancellable = true) +// private void modifyGlintRendering(ItemStack stack, IBakedModel model, CallbackInfo ci) { +// RenderItemHookKt.modifyGlintRendering(stack, model, ci); +// } + + @Inject(method = "renderEffect", at = @At("HEAD"), cancellable = true) + public void onRenderEffect(CallbackInfo ci) { + if (RenderItemHookKt.getSkipGlint()) { + ci.cancel(); + } + } + +} diff --git a/src/main/java/at/lorenz/mod/utils/ItemUtils.kt b/src/main/java/at/lorenz/mod/utils/ItemUtils.kt index 697e57393..44972fb0c 100644 --- a/src/main/java/at/lorenz/mod/utils/ItemUtils.kt +++ b/src/main/java/at/lorenz/mod/utils/ItemUtils.kt @@ -1,5 +1,6 @@ package at.lorenz.mod.utils +import at.lorenz.mod.utils.LorenzUtils.Companion.matchRegex import at.lorenz.mod.utils.LorenzUtils.Companion.removeColorCodes import net.minecraft.client.Minecraft import net.minecraft.client.gui.inventory.GuiChest @@ -35,5 +36,16 @@ class ItemUtils { fun isRecombobulated(stack: ItemStack): Boolean = stack.getLore().any { it.contains("§k") } + fun isPet(name: String): Boolean = name.matchRegex("\\[Lvl (.*)] (.*)") && !listOf( + "Archer", + "Berserk", + "Mage", + "Tank", + "Healer", + "➡", + ).any { name.contains(it) } + + fun maxPetLevel(name: String) = if (name.contains("Golden Dragon")) 200 else 100 + } } \ No newline at end of file diff --git a/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt b/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt index 021c055d7..3bcb630e0 100644 --- a/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt +++ b/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt @@ -87,5 +87,7 @@ class LorenzUtils { repeat(decimals) { multiplier *= 10 } return kotlin.math.round(this * multiplier) / multiplier } + + fun String.between(start: String, end: String): String = this.split(start, end)[1] } } \ No newline at end of file diff --git a/src/main/java/at/lorenz/mod/utils/NumberUtil.kt b/src/main/java/at/lorenz/mod/utils/NumberUtil.kt new file mode 100644 index 000000000..12040bd07 --- /dev/null +++ b/src/main/java/at/lorenz/mod/utils/NumberUtil.kt @@ -0,0 +1,152 @@ +package at.lorenz.mod.utils + +import java.text.NumberFormat +import java.util.* +import kotlin.math.pow +import kotlin.math.roundToInt + +object NumberUtil { + @JvmField + val nf: NumberFormat = NumberFormat.getInstance(Locale.US) + private val suffixes = TreeMap().apply { + this[1000L] = "k" + this[1000000L] = "M" + this[1000000000L] = "B" + this[1000000000000L] = "T" + this[1000000000000000L] = "P" + this[1000000000000000000L] = "E" + } + private val romanSymbols = TreeMap( + mapOf( + 1000 to "M", + 900 to "CM", + 500 to "D", + 400 to "CD", + 100 to "C", + 90 to "XC", + 50 to "L", + 40 to "XL", + 10 to "X", + 9 to "IX", + 5 to "V", + 4 to "IV", + 1 to "I", + ) + ) + + /** + * This code was unmodified and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/30661479 + * @author assylias + */ + @JvmStatic + fun format(value: Number): String { + @Suppress("NAME_SHADOWING") + val value = value.toLong() + //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here + if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1) + if (value < 0) return "-" + format(-value) + if (value < 1000) return value.toString() //deal with easy case + val (divideBy, suffix) = suffixes.floorEntry(value) + val truncated = value / (divideBy / 10) //the number part of the output times 10 + val hasDecimal = truncated < 100 && truncated / 10.0 != (truncated / 10).toDouble() + return if (hasDecimal) (truncated / 10.0).toString() + suffix else (truncated / 10).toString() + suffix + } + + @JvmStatic + fun unformat(value: String): Long { + val suffix = value.filter { !it.isDigit() }.lowercase() + val num = value.filter { it.isDigit() }.toLong() + return num * (suffixes.entries.find { it.value.lowercase() == suffix }?.key ?: 1) + } + + /** + * This code was unmodified and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/22186845 + * @author jpdymond + */ + fun Double.roundToPrecision(precision: Int): Double { + val scale = 10.0.pow(precision).toInt() + return (this * scale).roundToInt().toDouble() / scale + } + + /** + * This code was unmodified and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/22186845 + * @author jpdymond + */ + fun Float.roundToPrecision(precision: Int): Float { + val scale = 10.0.pow(precision).toInt() + return (this * scale).roundToInt().toFloat() / scale + } + + fun Number.addSuffix(): String { + val long = this.toLong() + if (long in 11..13) return "${this}th" + return when (long % 10) { + 1L -> "${this}st" + 2L -> "${this}nd" + 3L -> "${this}rd" + else -> "${this}th" + } + } + + /** + * This code was converted to Kotlin and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/9073310 + */ + fun String.romanToDecimal(): Int { + var decimal = 0 + var lastNumber = 0 + val romanNumeral = this.uppercase() + for (x in romanNumeral.length - 1 downTo 0) { + when (romanNumeral[x]) { + 'M' -> { + decimal = processDecimal(1000, lastNumber, decimal) + lastNumber = 1000 + } + 'D' -> { + decimal = processDecimal(500, lastNumber, decimal) + lastNumber = 500 + } + 'C' -> { + decimal = processDecimal(100, lastNumber, decimal) + lastNumber = 100 + } + 'L' -> { + decimal = processDecimal(50, lastNumber, decimal) + lastNumber = 50 + } + 'X' -> { + decimal = processDecimal(10, lastNumber, decimal) + lastNumber = 10 + } + 'V' -> { + decimal = processDecimal(5, lastNumber, decimal) + lastNumber = 5 + } + 'I' -> { + decimal = processDecimal(1, lastNumber, decimal) + lastNumber = 1 + } + } + } + return decimal + } + + fun Int.toRoman(): String { + if (this <= 0) error("$this must be positive!") + val l = romanSymbols.floorKey(this) + return if (this == l) { + romanSymbols[this]!! + } else romanSymbols[l] + (this - l).toRoman() + } + + private fun processDecimal(decimal: Int, lastNumber: Int, lastDecimal: Int): Int { + return if (lastNumber > decimal) { + lastDecimal - decimal + } else { + lastDecimal + decimal + } + } +} \ No newline at end of file -- cgit