From fdf8e47e5e68b09989fb1ba1b49c27e8b895d35f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 11 Sep 2024 20:01:54 +0700 Subject: [PATCH] Align power/matter history by biggest values --- .../client/screen/widget/MatterGaugePanel.kt | 45 ++------ .../client/screen/widget/PowerGaugePanel.kt | 45 ++------ .../mc/otm/core/util/Formatting.kt | 104 +++++++++++++++++- .../dbotthepony/mc/otm/core/util/SiPrefix.kt | 16 ++- 4 files changed, 128 insertions(+), 82 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt index 973ef7d45..2327d12b6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt @@ -24,6 +24,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.util.formatHistory import ru.dbotthepony.mc.otm.core.util.formatMatter import ru.dbotthepony.mc.otm.core.util.formatMatterLevel import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget @@ -137,21 +138,6 @@ open class MatterGaugePanel @JvmOverloads constructor( } } -private fun formatLevel(a: Decimal, b: Decimal): Component { - val diff = a - b - - val fa = a.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN) - val fb = b.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED) - - if (diff.isZero) { - return TranslatableComponent("otm.gui.diff", diff.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.GRAY), fa, fb) - } else if (diff.isPositive) { - return TranslatableComponent("otm.gui.diff", diff.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN), fa, fb) - } else { - return TranslatableComponent("otm.gui.diff", (-diff).formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED), fa, fb) - } -} - open class ProfiledMatterGaugePanel( screen: S, parent: EditablePanel<*>? = null, @@ -161,29 +147,12 @@ open class ProfiledMatterGaugePanel( ): MatterGaugePanel(screen, parent, profiledWidget.gauge, x, y) { override fun makeTooltip(): MutableList { return super.makeTooltip().also { - it.add(TextComponent("")) - - if (minecraft.window.isShiftDown) { - it.add(formatLevel(profiledWidget.lastTickReceive, profiledWidget.lastTickTransfer)) - it.add(TextComponent("---")) - } - - it.add(formatLevel( - profiledWidget.weightedReceive, - profiledWidget.weightedTransfer, - )) - - if (minecraft.window.isShiftDown) { - it.add(TextComponent("---")) - val values = IntArrayList() - - values.addAll(profiledWidget.tick downTo 0) - values.addAll(AbstractProfiledStorage.HISTORY_SIZE - 1 downTo profiledWidget.tick + 1) - - for (i in values.intIterator()) { - it.add(formatLevel(profiledWidget.historyReceive[i].value, profiledWidget.historyTransfer[i].value)) - } - } + formatHistory( + it, + profiledWidget, + verbose = ShiftPressedCond, + suffix = TranslatableComponent("otm.gui.matter.name") + ) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt index 0d5b6546b..9d0b7f2cf 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt @@ -15,6 +15,7 @@ import ru.dbotthepony.mc.otm.client.render.* import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.util.formatHistory import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.core.util.formatPowerLevel import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget @@ -94,21 +95,6 @@ fun WidePowerGaugePanel( height: Float = 48f ) = PowerGaugePanel(screen, parent, widget, x, y, width, height) -private fun formatLevel(a: Decimal, b: Decimal): Component { - val diff = a - b - - val fa = a.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN) - val fb = b.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED) - - if (diff.isZero) { - return TranslatableComponent("otm.gui.diff", diff.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.GRAY), fa, fb) - } else if (diff.isPositive) { - return TranslatableComponent("otm.gui.diff", diff.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN), fa, fb) - } else { - return TranslatableComponent("otm.gui.diff", (-diff).formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED), fa, fb) - } -} - open class ProfiledPowerGaugePanel( screen: S, parent: EditablePanel<*>? = null, @@ -120,29 +106,12 @@ open class ProfiledPowerGaugePanel( ) : PowerGaugePanel(screen, parent, profiledWidget.gauge, x, y, width, height) { override fun makeTooltip(): MutableList { return super.makeTooltip().also { - it.add(TextComponent("")) - - if (minecraft.window.isShiftDown) { - it.add(formatLevel(profiledWidget.lastTickReceive, profiledWidget.lastTickTransfer)) - it.add(TextComponent("---")) - } - - it.add(formatLevel( - profiledWidget.weightedReceive, - profiledWidget.weightedTransfer, - )) - - if (minecraft.window.isShiftDown) { - it.add(TextComponent("---")) - val values = IntArrayList() - - values.addAll(profiledWidget.tick downTo 0) - values.addAll(AbstractProfiledStorage.HISTORY_SIZE - 1 downTo profiledWidget.tick + 1) - - for (i in values.intIterator()) { - it.add(formatLevel(profiledWidget.historyReceive[i].value, profiledWidget.historyTransfer[i].value)) - } - } + formatHistory( + it, + profiledWidget, + verbose = ShiftPressedCond, + suffix = TranslatableComponent("otm.gui.power.name") + ) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt index 56339f947..e66de1df1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt @@ -1,15 +1,22 @@ package ru.dbotthepony.mc.otm.core.util import it.unimi.dsi.fastutil.chars.CharArrayList +import it.unimi.dsi.fastutil.ints.IntArrayList +import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component +import net.minecraft.network.chat.MutableComponent +import ru.dbotthepony.kommons.util.value +import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.isNegative import ru.dbotthepony.mc.otm.core.math.isZero +import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import java.math.BigInteger import java.util.function.BooleanSupplier import kotlin.math.absoluteValue +import kotlin.math.max import kotlin.math.roundToInt private fun concat(numbers: String, suffix: Any): Component { @@ -127,7 +134,7 @@ private fun reformat(numbers: String): String { for (i in dot downTo 0) { if (++c == 4) { c = 1 - result.add(' ') + result.add(' ') } result.add(numbers[i]) @@ -138,6 +145,19 @@ private fun reformat(numbers: String): String { }) } +// because minecraft's font 'Figure Space' (FSP) does not match width of numbers +private fun resplice(number: String, decimals: Int): String { + var i = if (decimals != 0) decimals + 4 else 3 + val resplice = number.toCharArray() + + while (i < number.length) { + resplice[resplice.size - i - 1] = ' ' + i += 3 + } + + return String(resplice) +} + fun Long.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 3, formatAsReadable: BooleanSupplier = never, bias: Int = 0): Component { require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } @@ -234,3 +254,85 @@ fun formatTickDuration(ticks: Int, longFormat: Boolean = false): String { return "${padded(minutes)}:$seconds" } } + +fun formatHistory( + result: MutableList, + widget: ProfiledLevelGaugeWidget<*>, + bias: Int = 0, + decimals: Int = 3, + verbose: BooleanSupplier = never, + suffix: Any = "", +) { + data class Part(val formatted: String, val number: Decimal, val prefix: SiPrefix) + data class Line(val delta: Part, val incoming: Part, val outgoing: Part) + + val lines = ArrayList() + + fun part(number: Decimal): Part { + if (verbose.asBoolean && number.absoluteValue >= Decimal.ONE) { + return Part(reformat(number.toString(decimals)), number, SiPrefix.NONE) + } + + val prefix = SiPrefix.determine(number).neighbour(bias) + if (prefix.isEmpty) return Part(number.toString(decimals), number, prefix) + return Part((number / prefix.decimal).toString(decimals), number, prefix) + } + + fun addLine(a: Decimal, b: Decimal) { + lines.add(Line(part(a - b), part(a), part(b))) + } + + if (verbose.asBoolean) { + addLine(widget.lastTickReceive, widget.lastTickTransfer) + + val values = IntArrayList() + values.addAll(widget.tick downTo 0) + values.addAll(AbstractProfiledStorage.HISTORY_SIZE - 1 downTo widget.tick + 1) + + for (i in values.intIterator()) { + addLine(widget.historyReceive[i].value, widget.historyTransfer[i].value) + } + } + + addLine( + widget.weightedReceive, + widget.weightedTransfer + ) + + val maxWidthDeltaNumber = lines.maxOf { it.delta.formatted.length } + val maxWidthInNumber = lines.maxOf { it.incoming.formatted.length } + val maxWidthOutNumber = lines.maxOf { it.outgoing.formatted.length } + + val maxWidthDeltaSi = lines.maxOf { it.delta.prefix.length } + val maxWidthInSi = lines.maxOf { it.incoming.prefix.length } + val maxWidthOutSi = lines.maxOf { it.outgoing.prefix.length } + + fun Part.format(widthNumbers: Int, widthSi: Int): MutableComponent { + return TranslatableComponent( + prefix.formatLocaleKey, + resplice("-".repeat(max(widthNumbers - formatted.length, 0)) + formatted, decimals) + "-".repeat(max(widthSi - prefix.length, 0)), + suffix + ) + } + + fun Line.format(): Component { + val deltaColor = if (delta.number.isZero) ChatFormatting.GRAY else if (delta.number.isPositive) ChatFormatting.DARK_GREEN else ChatFormatting.DARK_RED + + return TranslatableComponent( + "otm.gui.diff", + delta.format(maxWidthDeltaNumber, maxWidthDeltaSi).withStyle(deltaColor), + incoming.format(maxWidthInNumber, maxWidthInSi).withStyle(ChatFormatting.DARK_GREEN), + outgoing.format(maxWidthOutNumber, maxWidthOutSi).withStyle(ChatFormatting.DARK_RED), + ) + } + + result.add(TextComponent("")) + result.add(lines.removeFirst().format()) + + if (verbose.asBoolean) { + result.add(TextComponent("---")) + result.add(lines.removeFirst().format()) + result.add(TextComponent("---")) + lines.forEach { result.add(it.format()) } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt index 4255840f6..0b21620a0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt @@ -1,6 +1,8 @@ package ru.dbotthepony.mc.otm.core.util import com.google.common.collect.ImmutableList +import net.minecraft.network.chat.Component +import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.isZero import java.math.BigInteger @@ -19,6 +21,9 @@ enum class SiPrefix(val power: Int, val symbol: String) { NONE(0, "") { override val isEmpty: Boolean get() = true + + override val length: Int + get() = 0 }, KILO (1, "k"), @@ -35,6 +40,10 @@ enum class SiPrefix(val power: Int, val symbol: String) { val formatLocaleKey = "otm.suffix.${name.lowercase()}".intern() val conciseFormatLocaleKey = "otm.suffix_concise.${name.lowercase()}".intern() val rawLocaleKey = "otm.suffix_raw.${name.lowercase()}".intern() + val rawLocale: Component = TranslatableComponent(rawLocaleKey) + + open val length: Int + get() = rawLocale.string.length val string: String @@ -72,18 +81,15 @@ enum class SiPrefix(val power: Int, val symbol: String) { if (new < 0) { return YOCTO - } else if (new >= VALUES.size) { + } else if (new >= entries.size) { return YOTTA } else { - return VALUES[new] + return entries[new] } } } companion object { - @JvmField - val VALUES: ImmutableList = ImmutableList.copyOf(values()) - @JvmField val MULTIPLIES: ImmutableList = ImmutableList.builder() .add(NONE)