From 1efe50bff3fbb0e6a782aaf5284fab3fd60ec637 Mon Sep 17 00:00:00 2001 From: HiZe_ Date: Thu, 10 Aug 2023 12:23:02 +0200 Subject: Merge pull request #348 * Chest Value --- .../at/hannibal2/skyhanni/utils/LorenzUtils.kt | 33 +++- .../java/at/hannibal2/skyhanni/utils/NumberUtil.kt | 50 ++++- .../utils/renderables/RenderLineTooltips.kt | 217 +++++++++++++++++++++ .../skyhanni/utils/renderables/Renderable.kt | 63 ++---- 4 files changed, 304 insertions(+), 59 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderLineTooltips.kt (limited to 'src/main/java/at/hannibal2/skyhanni/utils') diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt index 6a2dd34fc..a2bcc4020 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt @@ -57,6 +57,7 @@ object LorenzUtils { const val DEBUG_PREFIX = "[SkyHanni Debug] §7" private val log = LorenzLogger("chat/mod_sent") + var lastButtonClicked = 0L fun debug(message: String) { if (SkyHanniMod.feature.dev.debugEnabled) { @@ -333,6 +334,31 @@ object LorenzUtils { }) } + inline fun MutableList>.addButton( + prefix: String, + getName: String, + crossinline onChange: () -> Unit, + tips: List = emptyList(), + ) { + val onClick = { + if ((System.currentTimeMillis() - lastButtonClicked) > 150) { // funny thing happen if I don't do that + onChange() + SoundUtils.playClickSound() + lastButtonClicked = System.currentTimeMillis() + } + } + add(buildList { + add(prefix) + add("§a[") + if (tips.isEmpty()) { + add(Renderable.link("§e$getName", false, onClick)) + } else { + add(Renderable.clickAndHover("§e$getName", tips, false, onClick)) + } + add("§a]") + }) + } + // TODO nea? // fun dynamic(block: () -> KMutableProperty0?): ReadWriteProperty { // return object : ReadWriteProperty { @@ -383,8 +409,8 @@ object LorenzUtils { val tileSign = (this as AccessorGuiEditSign).tileSign return (tileSign.signText[1].unformattedText.removeColor() == "^^^^^^" - && tileSign.signText[2].unformattedText.removeColor() == "Set your" - && tileSign.signText[3].unformattedText.removeColor() == "speed cap!") + && tileSign.signText[2].unformattedText.removeColor() == "Set your" + && tileSign.signText[3].unformattedText.removeColor() == "speed cap!") } fun inIsland(island: IslandType) = inSkyBlock && skyBlockIsland == island @@ -448,4 +474,7 @@ object LorenzUtils { javaClass.getDeclaredField("modifiers").makeAccessible().set(this, modifiers and (Modifier.FINAL.inv())) return this } + + fun Int.toBoolean() = this != 0 + fun Boolean.toInt() = if (!this) 0 else 1 } \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt b/src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt index efdb545d2..5e40a2daf 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt @@ -39,19 +39,57 @@ object NumberUtil { * @link https://stackoverflow.com/a/30661479 * @author assylias */ + @JvmStatic - fun format(value: Number): String { + fun format(value: Number, preciseBillions: Boolean = false): 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) + //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here + if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1, preciseBillions) + if (value < 0) return "-" + format(-value, preciseBillions) + if (value < 1000) return value.toString() //deal with small numbers + val (divideBy, suffix) = suffixes.floorEntry(value) + val truncated = value / (divideBy / 10) //the number part of the output times 10 - val truncatedAt = if (suffix == "M") 1000 else 100 + + val truncatedAt = if (suffix == "M") 1000 else if (suffix == "B") 1000000 else 100 + + val hasDecimal = truncated < truncatedAt && truncated / 10.0 != (truncated / 10).toDouble() + + return if (value > 1_000_000_000 && hasDecimal && preciseBillions) { + val decimalPart = (value % 1_000_000_000) / 1_000_000 + "${truncated / 10}.$decimalPart$suffix" + } else { + if (hasDecimal) (truncated / 10.0).toString() + suffix else (truncated / 10).toString() + suffix + } + } + + @JvmStatic + fun format3(value: Number, digit: Int): 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 format3(Long.MIN_VALUE + 1, digit) + if (value < 0) return "-" + format3(-value, digit) + if (value < 1000) return value.toString() //deal with small numbers + + val (divideBy, suffix) = suffixes.floorEntry(value) + + var truncated = value / (divideBy / 10) //the number part of the output times 10 + + val truncatedAt = if (suffix == "M") 1000 else if (suffix == "B") 1000000 else 100 + val hasDecimal = truncated < truncatedAt && truncated / 10.0 != (truncated / 10).toDouble() - return if (hasDecimal) (truncated / 10.0).toString() + suffix else (truncated / 10).toString() + suffix + + // Add check for value greater than 1000000000 (1 Billion) + return if (value > 1000000000 && hasDecimal) { + val decimalPart = (value % 1000000000) / 1000000 // Extract 3 digits after the decimal point + "${(truncated / 10).toDouble().toString().take(digit + 2)}$suffix" + } else { + if (hasDecimal) (truncated / 10.0).toString().take(digit + 2) + suffix else (truncated / 10).toString() + suffix + } } /** diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderLineTooltips.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderLineTooltips.kt new file mode 100644 index 000000000..2cf20ee72 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderLineTooltips.kt @@ -0,0 +1,217 @@ +package at.hannibal2.skyhanni.utils.renderables + +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import io.github.moulberry.notenoughupdates.util.Utils +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.ScaledResolution +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.client.renderer.Tessellator +import net.minecraft.client.renderer.vertex.DefaultVertexFormats +import net.minecraft.item.ItemStack +import java.awt.Color + +object RenderLineTooltips { + + fun drawHoveringText(posX: Int, posY: Int, tips: List, stack: ItemStack? = null) { + if (tips.isNotEmpty()) { + var textLines = tips + val x = Utils.getMouseX() + 12 - posX + val y = Utils.getMouseY() - 10 - posY + val color: Char = stack?.getLore()?.lastOrNull()?.take(4)?.get(1) + ?: Utils.getPrimaryColourCode(textLines[0]) + val colourInt = Minecraft.getMinecraft().fontRendererObj.getColorCode(color) + val borderColorStart = Color(colourInt).darker().rgb and 0x00FFFFFF or (200 shl 24) + val font = Minecraft.getMinecraft().fontRendererObj + val scaled = ScaledResolution(Minecraft.getMinecraft()) + GlStateManager.disableRescaleNormal() + RenderHelper.disableStandardItemLighting() + GlStateManager.disableLighting() + GlStateManager.enableDepth() + var tooltipTextWidth = 0 + for (textLine in textLines) { + val textLineWidth = font.getStringWidth(textLine) + if (textLineWidth > tooltipTextWidth) { + tooltipTextWidth = textLineWidth + } + } + var needsWrap = false + var titleLinesCount = 1 + var tooltipX = x + if (tooltipX + tooltipTextWidth + 4 > scaled.scaledWidth) { + tooltipX = x - 16 - tooltipTextWidth + if (tooltipX < 4) { + tooltipTextWidth = if (x > scaled.scaledWidth / 2) { + x - 12 - 8 + } else { + scaled.scaledWidth - 16 - x + } + needsWrap = true + } + } + if (needsWrap) { + var wrappedTooltipWidth = 0 + val wrappedTextLines: MutableList = ArrayList() + for (i in textLines.indices) { + val textLine = textLines[i] + val wrappedLine = font.listFormattedStringToWidth(textLine, tooltipTextWidth) + if (i == 0) { + titleLinesCount = wrappedLine.size + } + for (line in wrappedLine) { + val lineWidth = font.getStringWidth(line) + if (lineWidth > wrappedTooltipWidth) { + wrappedTooltipWidth = lineWidth + } + wrappedTextLines.add(line) + } + } + tooltipTextWidth = wrappedTooltipWidth + textLines = wrappedTextLines.toList() + tooltipX = if (x > scaled.scaledWidth / 2) { + x - 16 - tooltipTextWidth + } else { + x + 12 + } + } + var tooltipY = y - 12 + var tooltipHeight = 8 + if (textLines.size > 1) { + tooltipHeight += (textLines.size - 1) * 10 + if (textLines.size > titleLinesCount) { + tooltipHeight += 2 + } + } + + if (tooltipY + tooltipHeight + 6 > scaled.scaledHeight) { + tooltipY = scaled.scaledHeight - tooltipHeight - 6 + } + val zLevel = 300 + val backgroundColor = -0xfeffff0 + drawGradientRect( + zLevel, + tooltipX - 3, + tooltipY - 4, + tooltipX + tooltipTextWidth + 3, + tooltipY - 3, + backgroundColor, + backgroundColor + ) + drawGradientRect( + zLevel, + tooltipX - 3, + tooltipY + tooltipHeight + 3, + tooltipX + tooltipTextWidth + 3, + tooltipY + tooltipHeight + 4, + backgroundColor, + backgroundColor + ) + drawGradientRect( + zLevel, + tooltipX - 3, + tooltipY - 3, + tooltipX + tooltipTextWidth + 3, + tooltipY + tooltipHeight + 3, + backgroundColor, + backgroundColor + ) + drawGradientRect( + zLevel, + tooltipX - 4, + tooltipY - 3, + tooltipX - 3, + tooltipY + tooltipHeight + 3, + backgroundColor, + backgroundColor + ) + drawGradientRect( + zLevel, + tooltipX + tooltipTextWidth + 3, + tooltipY - 3, + tooltipX + tooltipTextWidth + 4, + tooltipY + tooltipHeight + 3, + backgroundColor, + backgroundColor + ) + val borderColorEnd = borderColorStart and 0xFEFEFE shr 1 or (borderColorStart and -0x1000000) + drawGradientRect( + zLevel, + tooltipX - 3, + tooltipY - 3 + 1, + tooltipX - 3 + 1, + tooltipY + tooltipHeight + 3 - 1, + borderColorStart, + borderColorEnd + ) + drawGradientRect( + zLevel, + tooltipX + tooltipTextWidth + 2, + tooltipY - 3 + 1, + tooltipX + tooltipTextWidth + 3, + tooltipY + tooltipHeight + 3 - 1, + borderColorStart, + borderColorEnd + ) + drawGradientRect( + zLevel, + tooltipX - 3, + tooltipY - 3, + tooltipX + tooltipTextWidth + 3, + tooltipY - 3 + 1, + borderColorStart, + borderColorStart + ) + drawGradientRect( + zLevel, + tooltipX - 3, + tooltipY + tooltipHeight + 2, + tooltipX + tooltipTextWidth + 3, + tooltipY + tooltipHeight + 3, + borderColorEnd, + borderColorEnd + ) + GlStateManager.disableDepth() + for (lineNumber in textLines.indices) { + val line = textLines[lineNumber] + font.drawStringWithShadow(line, 1f + tooltipX.toFloat(), 1f + tooltipY.toFloat(), -1) + if (lineNumber + 1 == titleLinesCount) { + tooltipY += 2 + } + tooltipY += 10 + } + GlStateManager.enableLighting() + GlStateManager.enableDepth() + RenderHelper.enableStandardItemLighting() + GlStateManager.enableRescaleNormal() + } + GlStateManager.disableLighting() + } + + private fun drawGradientRect(zLevel: Int, left: Int, top: Int, right: Int, bottom: Int, startColor: Int, endColor: Int) { + val startAlpha = (startColor shr 24 and 255).toFloat() / 255.0f + val startRed = (startColor shr 16 and 255).toFloat() / 255.0f + val startGreen = (startColor shr 8 and 255).toFloat() / 255.0f + val startBlue = (startColor and 255).toFloat() / 255.0f + val endAlpha = (endColor shr 24 and 255).toFloat() / 255.0f + val endRed = (endColor shr 16 and 255).toFloat() / 255.0f + val endGreen = (endColor shr 8 and 255).toFloat() / 255.0f + val endBlue = (endColor and 255).toFloat() / 255.0f + GlStateManager.disableTexture2D() + GlStateManager.enableBlend() + GlStateManager.disableAlpha() + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0) + GlStateManager.shadeModel(7425) + val tessellator = Tessellator.getInstance() + val worldrenderer = tessellator.worldRenderer + worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR) + worldrenderer.pos(right.toDouble(), top.toDouble(), zLevel.toDouble()).color(startRed, startGreen, startBlue, startAlpha).endVertex() + worldrenderer.pos(left.toDouble(), top.toDouble(), zLevel.toDouble()).color(startRed, startGreen, startBlue, startAlpha).endVertex() + worldrenderer.pos(left.toDouble(), bottom.toDouble(), zLevel.toDouble()).color(endRed, endGreen, endBlue, endAlpha).endVertex() + worldrenderer.pos(right.toDouble(), bottom.toDouble(), zLevel.toDouble()).color(endRed, endGreen, endBlue, endAlpha).endVertex() + tessellator.draw() + GlStateManager.shadeModel(7424) + GlStateManager.disableBlend() + GlStateManager.enableAlpha() + GlStateManager.enableTexture2D() + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt index c554b8bde..dabf428d4 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -2,14 +2,12 @@ package at.hannibal2.skyhanni.utils.renderables import at.hannibal2.skyhanni.config.core.config.gui.GuiPositionEditor import at.hannibal2.skyhanni.data.ToolTipData -import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzLogger import at.hannibal2.skyhanni.utils.NEUItems.renderOnScreen import io.github.moulberry.moulconfig.gui.GuiScreenElementWrapper import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.client.Minecraft import net.minecraft.client.gui.Gui -import net.minecraft.client.gui.GuiScreen import net.minecraft.client.gui.inventory.GuiEditSign import net.minecraft.client.renderer.GlStateManager import net.minecraft.item.ItemStack @@ -21,7 +19,7 @@ interface Renderable { val height: Int fun isHovered(posX: Int, posY: Int) = Utils.getMouseX() in (posX..posX + width) - && Utils.getMouseY() in (posY..posY + height) // TODO: adjust for variable height? + && Utils.getMouseY() in (posY..posY + height) // TODO: adjust for variable height? /** * N.B.: the offset is absolute, not relative to the position and shouldn't be used for rendering @@ -31,6 +29,7 @@ interface Renderable { companion object { val logger = LorenzLogger("debug/renderable") + val list = mutableMapOf, List>() fun fromAny(any: Any?, itemScale: Double = 1.0): Renderable? = when (any) { null -> placeholder(12) @@ -101,12 +100,8 @@ interface Renderable { } } - fun hoverTips( - text: String, - tips: List, - bypassChecks: Boolean = false, - condition: () -> Boolean = { true } - ): Renderable { + fun hoverTips(text: String, tips: List, indexes: List = listOf(), stack: ItemStack? = null, bypassChecks: Boolean = false, condition: () -> Boolean = { true }): Renderable { + val render = string(text) return object : Renderable { override val width: Int @@ -117,53 +112,18 @@ interface Renderable { render.render(posX, posY) if (isHovered(posX, posY)) { if (condition() && shouldAllowLink(true, bypassChecks)) { - renderToolTips(posX, posY, tips) + list[Pair(posX, posY)] = indexes + RenderLineTooltips.drawHoveringText(posX, posY, tips, stack) + } + } else { + if (list.contains(Pair(posX, posY))) { + list.remove(Pair(posX, posY)) } } } } } - private fun renderToolTips(posX: Int, posY: Int, tips: List, border: Int = 1) { - GlStateManager.pushMatrix() -// GlStateManager.translate(0f, 0f, 2f) -// GuiRenderUtils.drawTooltip(tips, posX, posY, 0) -// GlStateManager.translate(0f, 0f, -2f) - - val x = Utils.getMouseX() - posX + 10 - val startY = Utils.getMouseY() - posY - 10 - var maxX = 0 - var y = startY - val renderer = Minecraft.getMinecraft().fontRendererObj - - GlStateManager.translate(0f, 0f, 2f) - for (line in tips) { - renderer.drawStringWithShadow( - "§f$line", - 1f + x, - 1f + y, - 0 - ) - val currentX = renderer.getStringWidth(line) - if (currentX > maxX) { - maxX = currentX - } - y += 10 - } - GlStateManager.translate(0f, 0f, -1f) - - GuiScreen.drawRect( - x - border, - startY - border, - x + maxX + 10 + border, - y + border, - LorenzColor.DARK_GRAY.toColor().rgb - ) - GlStateManager.translate(0f, 0f, -1f) - - GlStateManager.popMatrix() - } - private fun shouldAllowLink(debug: Boolean = false, bypassChecks: Boolean): Boolean { val isGuiScreen = Minecraft.getMinecraft().currentScreen != null if (bypassChecks) { @@ -252,4 +212,5 @@ interface Renderable { } } } -} \ No newline at end of file +} + -- cgit