Charts in storage tooltips
This commit is contained in:
parent
693075d600
commit
e7ded02d30
@ -32,6 +32,7 @@ import ru.dbotthepony.mc.otm.client.MatteryGUI;
|
|||||||
import ru.dbotthepony.mc.otm.client.model.ExosuitModel;
|
import ru.dbotthepony.mc.otm.client.model.ExosuitModel;
|
||||||
import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel;
|
import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel;
|
||||||
import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel;
|
import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel;
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.ChartTooltipElement;
|
||||||
import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer;
|
import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer;
|
||||||
import ru.dbotthepony.mc.otm.client.render.blockentity.BatteryBankRenderer;
|
import ru.dbotthepony.mc.otm.client.render.blockentity.BatteryBankRenderer;
|
||||||
import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer;
|
import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer;
|
||||||
@ -159,6 +160,8 @@ public final class OverdriveThatMatters {
|
|||||||
bus.addListener(EventPriority.NORMAL, BatteryBankRenderer.Companion::onRegisterAdditionalModels);
|
bus.addListener(EventPriority.NORMAL, BatteryBankRenderer.Companion::onRegisterAdditionalModels);
|
||||||
bus.addListener(EventPriority.NORMAL, MatterBatteryBankRenderer.Companion::onRegisterAdditionalModels);
|
bus.addListener(EventPriority.NORMAL, MatterBatteryBankRenderer.Companion::onRegisterAdditionalModels);
|
||||||
|
|
||||||
|
bus.addListener(EventPriority.NORMAL, ChartTooltipElement.Companion::register);
|
||||||
|
|
||||||
MBlockColors.INSTANCE.register(bus);
|
MBlockColors.INSTANCE.register(bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,16 @@ import com.mojang.blaze3d.vertex.ByteBufferBuilder
|
|||||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||||
import com.mojang.blaze3d.vertex.PoseStack
|
import com.mojang.blaze3d.vertex.PoseStack
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat
|
import com.mojang.blaze3d.vertex.VertexFormat
|
||||||
import it.unimi.dsi.fastutil.floats.Float2ObjectMap
|
|
||||||
import net.minecraft.client.gui.Font
|
import net.minecraft.client.gui.Font
|
||||||
|
import net.minecraft.client.gui.GuiGraphics
|
||||||
|
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent
|
||||||
import net.minecraft.client.renderer.GameRenderer
|
import net.minecraft.client.renderer.GameRenderer
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||||
|
import net.neoforged.neoforge.client.event.RegisterClientTooltipComponentFactoriesEvent
|
||||||
import org.lwjgl.opengl.GL11.GL_LESS
|
import org.lwjgl.opengl.GL11.GL_LESS
|
||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.acos
|
import kotlin.math.acos
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
@ -40,7 +44,7 @@ data class ChartMouseLabels(
|
|||||||
|
|
||||||
data class ChartLevelLabels(
|
data class ChartLevelLabels(
|
||||||
val labels: Map<Float, Component>,
|
val labels: Map<Float, Component>,
|
||||||
val font: Font,
|
val font: Font? = null,
|
||||||
val lineColor: RGBAColor = RGBAColor.DARK_GREEN,
|
val lineColor: RGBAColor = RGBAColor.DARK_GREEN,
|
||||||
val textColor: RGBAColor = RGBAColor.DARK_GREEN,
|
val textColor: RGBAColor = RGBAColor.DARK_GREEN,
|
||||||
val textGravity: RenderGravity = RenderGravity.TOP_RIGHT,
|
val textGravity: RenderGravity = RenderGravity.TOP_RIGHT,
|
||||||
@ -49,19 +53,44 @@ data class ChartLevelLabels(
|
|||||||
|
|
||||||
private val BYTE_BUFFER_BUILDER = ByteBufferBuilder(786_432)
|
private val BYTE_BUFFER_BUILDER = ByteBufferBuilder(786_432)
|
||||||
|
|
||||||
|
class ChartTooltipElement(
|
||||||
|
private val normalized: List<Pair<FloatArray, RGBAColor>>,
|
||||||
|
private val width: Float,
|
||||||
|
private val height: Float,
|
||||||
|
private val levelLabels: ChartLevelLabels? = null,
|
||||||
|
) : ClientTooltipComponent, TooltipComponent {
|
||||||
|
override fun getHeight(): Int {
|
||||||
|
return this.height.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getWidth(font: Font): Int {
|
||||||
|
return this.width.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderImage(font: Font, x: Int, y: Int, graphics: GuiGraphics) {
|
||||||
|
renderChart(graphics.pose(), normalized, this.width, this.height - 10f, levelLabels = this.levelLabels, x = x.toFloat(), y = y.toFloat() + 10f)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun register(event: RegisterClientTooltipComponentFactoriesEvent) {
|
||||||
|
event.register(ChartTooltipElement::class.java) { it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun renderChart(
|
fun renderChart(
|
||||||
poseStack: PoseStack,
|
poseStack: PoseStack,
|
||||||
normalized: FloatArray,
|
charts: List<Pair<FloatArray, RGBAColor>>,
|
||||||
width: Float,
|
width: Float,
|
||||||
height: Float,
|
height: Float,
|
||||||
color: RGBAColor = RGBAColor.WHITE,
|
|
||||||
labels: ChartMouseLabels? = null,
|
labels: ChartMouseLabels? = null,
|
||||||
levelLabels: ChartLevelLabels? = null,
|
levelLabels: ChartLevelLabels? = null,
|
||||||
x: Float = 0f,
|
x: Float = 0f,
|
||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
) {
|
) {
|
||||||
|
require(charts.all { it.first.size == charts[0].first.size }) { "Provided chart data is not of same width" }
|
||||||
val builder = BufferBuilder(BYTE_BUFFER_BUILDER, VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR)
|
val builder = BufferBuilder(BYTE_BUFFER_BUILDER, VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR)
|
||||||
val step = width / normalized.size
|
val step = width / charts[0].first.size
|
||||||
|
|
||||||
val pose = poseStack.last().pose
|
val pose = poseStack.last().pose
|
||||||
val checkLabels = labels != null && labels.mouseY in 0f .. height && labels.mouseX in 0f .. width
|
val checkLabels = labels != null && labels.mouseY in 0f .. height && labels.mouseX in 0f .. width
|
||||||
@ -81,40 +110,42 @@ fun renderChart(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0 until normalized.size - 1) {
|
for ((normalized, color) in charts) {
|
||||||
val y0 = y + (1f - normalized[i]) * height
|
for (i in 0 until normalized.size - 1) {
|
||||||
val y1 = y + (1f - normalized[i + 1]) * height
|
val y0 = y + (1f - normalized[i]) * height
|
||||||
|
val y1 = y + (1f - normalized[i + 1]) * height
|
||||||
|
|
||||||
val x0 = x + width - (i + 0.5f) * step
|
val x0 = x + width - (i + 0.5f) * step
|
||||||
val x1 = x + width - (i + 1.5f) * step
|
val x1 = x + width - (i + 1.5f) * step
|
||||||
|
|
||||||
val xDiff = x1 - x0
|
val xDiff = x1 - x0
|
||||||
val yDiff = y1 - y0
|
val yDiff = y1 - y0
|
||||||
|
|
||||||
if (yDiff.sign == 0f) {
|
if (yDiff.sign == 0f) {
|
||||||
builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f).color(color)
|
builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f).color(color)
|
||||||
builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f).color(color)
|
builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f).color(color)
|
||||||
builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f).color(color)
|
builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f).color(color)
|
||||||
builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f).color(color)
|
builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f).color(color)
|
||||||
} else {
|
} else {
|
||||||
val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f)
|
val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f)
|
||||||
val angle = acos(xDiff / length) * yDiff.sign - PI / 2f // rotate 90 deg
|
val angle = acos(xDiff / length) * yDiff.sign - PI / 2f // rotate 90 deg
|
||||||
|
|
||||||
val xDisp = cos(angle).toFloat() * LINE_WIDTH / 2f
|
val xDisp = cos(angle).toFloat() * LINE_WIDTH / 2f
|
||||||
val yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f
|
val yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f
|
||||||
|
|
||||||
builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f).color(color)
|
builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f).color(color)
|
||||||
builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f).color(color)
|
builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f).color(color)
|
||||||
builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f).color(color)
|
builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f).color(color)
|
||||||
builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f).color(color)
|
builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f).color(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
//graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH)
|
//graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH)
|
||||||
|
|
||||||
if (checkLabels && drawLabel == -1 && labels!!.mouseX in x1 .. x0) {
|
if (checkLabels && drawLabel == -1 && labels!!.mouseX in x1 .. x0) {
|
||||||
drawLabel = i
|
drawLabel = i
|
||||||
drawPointX = x0 // linearInterpolation(0.5f, x0, x1)
|
drawPointX = x0 // linearInterpolation(0.5f, x0, x1)
|
||||||
drawPointY = y0 // linearInterpolation(0.5f, y0, y1)
|
drawPointY = y0 // linearInterpolation(0.5f, y0, y1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,13 +161,14 @@ fun renderChart(
|
|||||||
RenderSystem.depthFunc(GL_LESS)
|
RenderSystem.depthFunc(GL_LESS)
|
||||||
|
|
||||||
if (levelLabels != null && levelLabels.labels.isNotEmpty()) {
|
if (levelLabels != null && levelLabels.labels.isNotEmpty()) {
|
||||||
|
val font = levelLabels.font ?: minecraft.font
|
||||||
for ((level, label) in levelLabels.labels) {
|
for ((level, label) in levelLabels.labels) {
|
||||||
val y0 = y + (1f - level) * height
|
val y0 = y + (1f - level) * height
|
||||||
|
|
||||||
val tX = x + levelLabels.textGravity.repositionX(width, levelLabels.font.width(label).toFloat()) - 1f
|
val tX = x + levelLabels.textGravity.repositionX(width, font.width(label).toFloat()) - 1f
|
||||||
val tY = y0 - LINE_WIDTH - 1f - levelLabels.font.lineHeight + levelLabels.textGravity.repositionY(levelLabels.font.lineHeight * 2f + LINE_WIDTH + 2f, levelLabels.font.lineHeight.toFloat()) + 1f
|
val tY = y0 - LINE_WIDTH - 1f - font.lineHeight + levelLabels.textGravity.repositionY(font.lineHeight * 2f + LINE_WIDTH + 2f, font.lineHeight.toFloat()) + 1f
|
||||||
|
|
||||||
levelLabels.font.draw(
|
font.draw(
|
||||||
poseStack,
|
poseStack,
|
||||||
label,
|
label,
|
||||||
x = tX,
|
x = tX,
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package ru.dbotthepony.mc.otm.client.render
|
package ru.dbotthepony.mc.otm.client.render
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack
|
import com.mojang.blaze3d.vertex.PoseStack
|
||||||
|
import com.mojang.datafixers.util.Either
|
||||||
import net.minecraft.client.gui.Font
|
import net.minecraft.client.gui.Font
|
||||||
import net.minecraft.client.gui.GuiGraphics
|
import net.minecraft.client.gui.GuiGraphics
|
||||||
import net.minecraft.client.renderer.MultiBufferSource
|
import net.minecraft.client.renderer.MultiBufferSource
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.network.chat.FormattedText
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.util.FormattedCharSequence
|
import net.minecraft.util.FormattedCharSequence
|
||||||
|
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
@ -78,10 +81,15 @@ class MGUIGraphics(val parent: GuiGraphics) {
|
|||||||
renderCheckerboard(pose.last().pose(), x, y, width, height, z, color)
|
renderCheckerboard(pose.last().pose(), x, y, width, height, z, color)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renderComponentTooltip(font: Font, lines: MutableList<Component>, x: Int, y: Int, itemStack: ItemStack = ItemStack.EMPTY) {
|
fun renderComponentTooltip(font: Font, lines: List<FormattedText>, x: Int, y: Int, itemStack: ItemStack = ItemStack.EMPTY) {
|
||||||
parent.renderComponentTooltip(font, lines, x, y, itemStack)
|
parent.renderComponentTooltip(font, lines, x, y, itemStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmName("renderComponentTooltipFromElements")
|
||||||
|
fun renderComponentTooltip(font: Font, lines: List<Either<FormattedText, TooltipComponent>>, x: Int, y: Int, itemStack: ItemStack = ItemStack.EMPTY) {
|
||||||
|
parent.renderComponentTooltipFromElements(font, lines, x, y, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
fun flush() {
|
fun flush() {
|
||||||
parent.flush()
|
parent.flush()
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ open class DecimalHistoryChartPanel<out S : MatteryScreen<*>>(
|
|||||||
|
|
||||||
renderChart(
|
renderChart(
|
||||||
graphics.pose,
|
graphics.pose,
|
||||||
normalized,
|
listOf(normalized to RGBAColor.WHITE),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
labels = ChartMouseLabels(
|
labels = ChartMouseLabels(
|
||||||
|
@ -4,11 +4,14 @@ import com.mojang.blaze3d.systems.RenderSystem
|
|||||||
import com.mojang.blaze3d.vertex.BufferUploader
|
import com.mojang.blaze3d.vertex.BufferUploader
|
||||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat
|
import com.mojang.blaze3d.vertex.VertexFormat
|
||||||
|
import com.mojang.datafixers.util.Either
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.client.gui.screens.Screen
|
import net.minecraft.client.gui.screens.Screen
|
||||||
import net.minecraft.client.renderer.GameRenderer
|
import net.minecraft.client.renderer.GameRenderer
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.network.chat.FormattedText
|
||||||
|
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
import ru.dbotthepony.kommons.util.value
|
import ru.dbotthepony.kommons.util.value
|
||||||
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
|
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
|
||||||
@ -52,13 +55,15 @@ open class MatterGaugePanel<out S : Screen> @JvmOverloads constructor(
|
|||||||
private var lastDraw = nanoTime
|
private var lastDraw = nanoTime
|
||||||
private var lastLevel = 0f
|
private var lastLevel = 0f
|
||||||
|
|
||||||
protected open fun makeTooltip(): MutableList<Component> {
|
protected open fun makeTooltip(): MutableList<Either<FormattedText, TooltipComponent>> {
|
||||||
return mutableListOf(
|
return mutableListOf(
|
||||||
TranslatableComponent(
|
Either.left(
|
||||||
"otm.gui.matter.percentage_level",
|
TranslatableComponent(
|
||||||
String.format("%.2f", widget.percentage * 100.0)
|
"otm.gui.matter.percentage_level",
|
||||||
|
String.format("%.2f", widget.percentage * 100.0)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
formatMatterLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond)
|
Either.left(formatMatterLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +150,7 @@ open class ProfiledMatterGaugePanel<out S : Screen>(
|
|||||||
x: Float = 0f,
|
x: Float = 0f,
|
||||||
y: Float = 0f
|
y: Float = 0f
|
||||||
): MatterGaugePanel<S>(screen, parent, profiledWidget.gauge, x, y) {
|
): MatterGaugePanel<S>(screen, parent, profiledWidget.gauge, x, y) {
|
||||||
override fun makeTooltip(): MutableList<Component> {
|
override fun makeTooltip(): MutableList<Either<FormattedText, TooltipComponent>> {
|
||||||
return super.makeTooltip().also {
|
return super.makeTooltip().also {
|
||||||
formatHistory(
|
formatHistory(
|
||||||
it,
|
it,
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package ru.dbotthepony.mc.otm.client.screen.widget
|
package ru.dbotthepony.mc.otm.client.screen.widget
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Either
|
||||||
import net.minecraft.client.gui.screens.Screen
|
import net.minecraft.client.gui.screens.Screen
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.network.chat.FormattedText
|
||||||
|
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
||||||
import ru.dbotthepony.mc.otm.client.ShiftPressedCond
|
import ru.dbotthepony.mc.otm.client.ShiftPressedCond
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
@ -25,10 +28,10 @@ open class PowerGaugePanel<out S : Screen>(
|
|||||||
scissor = true
|
scissor = true
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun makeTooltip(): MutableList<Component> {
|
protected open fun makeTooltip(): MutableList<Either<FormattedText, TooltipComponent>> {
|
||||||
return mutableListOf(
|
return mutableListOf(
|
||||||
TranslatableComponent("otm.gui.power.percentage_level", String.format("%.2f", widget.percentage * 100.0)),
|
Either.left(TranslatableComponent("otm.gui.power.percentage_level", String.format("%.2f", widget.percentage * 100.0))),
|
||||||
formatPowerLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond)
|
Either.left(formatPowerLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +98,7 @@ open class ProfiledPowerGaugePanel<out S : Screen>(
|
|||||||
width: Float = GAUGE_BACKGROUND.width,
|
width: Float = GAUGE_BACKGROUND.width,
|
||||||
height: Float = GAUGE_BACKGROUND.height
|
height: Float = GAUGE_BACKGROUND.height
|
||||||
) : PowerGaugePanel<S>(screen, parent, profiledWidget.gauge, x, y, width, height) {
|
) : PowerGaugePanel<S>(screen, parent, profiledWidget.gauge, x, y, width, height) {
|
||||||
override fun makeTooltip(): MutableList<Component> {
|
override fun makeTooltip(): MutableList<Either<FormattedText, TooltipComponent>> {
|
||||||
return super.makeTooltip().also {
|
return super.makeTooltip().also {
|
||||||
formatHistory(
|
formatHistory(
|
||||||
it,
|
it,
|
||||||
|
@ -48,6 +48,11 @@ object ClientConfig : AbstractConfig("client", ModConfig.Type.CLIENT) {
|
|||||||
.comment("For those who want it.")
|
.comment("For those who want it.")
|
||||||
.define("REDSTONE_CONTROLS_ITEM_ICONS", false)
|
.define("REDSTONE_CONTROLS_ITEM_ICONS", false)
|
||||||
|
|
||||||
|
var CHARTS_IN_TOOLTIPS: Boolean by builder
|
||||||
|
.comment("Draw charts in storage tooltips instead of list of last 20 values.")
|
||||||
|
.comment("Disable to get EnderIO-like experience")
|
||||||
|
.define("CHARTS_IN_TOOLTIPS", true)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
builder.pop()
|
builder.pop()
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
package ru.dbotthepony.mc.otm.core.util
|
package ru.dbotthepony.mc.otm.core.util
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Either
|
||||||
import it.unimi.dsi.fastutil.chars.CharArrayList
|
import it.unimi.dsi.fastutil.chars.CharArrayList
|
||||||
|
import it.unimi.dsi.fastutil.floats.Float2ObjectArrayMap
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.network.chat.FormattedText
|
||||||
import net.minecraft.network.chat.MutableComponent
|
import net.minecraft.network.chat.MutableComponent
|
||||||
|
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||||
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.ChartLevelLabels
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.ChartTooltipElement
|
||||||
|
import ru.dbotthepony.mc.otm.config.ClientConfig
|
||||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
@ -252,8 +260,179 @@ fun formatTickDuration(ticks: Int, longFormat: Boolean = false): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clientside only function, do not call on shared/server realm.
|
||||||
|
*/
|
||||||
fun formatHistory(
|
fun formatHistory(
|
||||||
result: MutableList<Component>,
|
result: MutableList<Either<FormattedText, TooltipComponent>>,
|
||||||
|
widget: ProfiledLevelGaugeWidget<*>,
|
||||||
|
bias: Int = 0,
|
||||||
|
decimals: Int = 3,
|
||||||
|
verbose: BooleanSupplier = never,
|
||||||
|
suffix: Any = "",
|
||||||
|
) {
|
||||||
|
if (!ClientConfig.GUI.CHARTS_IN_TOOLTIPS) {
|
||||||
|
formatHistoryLines(result, widget, bias, decimals, verbose, suffix)
|
||||||
|
} else {
|
||||||
|
formatHistoryChart(result, widget, bias, decimals, verbose, suffix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun formatHistoryChart(
|
||||||
|
result: MutableList<Either<FormattedText, TooltipComponent>>,
|
||||||
|
widget: ProfiledLevelGaugeWidget<*>,
|
||||||
|
bias: Int = 0,
|
||||||
|
decimals: Int = 3,
|
||||||
|
verbose: BooleanSupplier = never,
|
||||||
|
suffix: Any = "",
|
||||||
|
) {
|
||||||
|
val diff = Array(widget.received.width) { widget.received[it] - widget.transferred[it] }
|
||||||
|
val normalizedDiff: FloatArray
|
||||||
|
val received: FloatArray
|
||||||
|
val transferred: FloatArray
|
||||||
|
val labels: ChartLevelLabels
|
||||||
|
|
||||||
|
val hasPositiveInfinity = diff.any { it.isInfinite && it.isPositive }
|
||||||
|
val hasNegativeInfinity = diff.any { it.isInfinite && it.isNegative }
|
||||||
|
|
||||||
|
if (hasPositiveInfinity && hasNegativeInfinity) {
|
||||||
|
normalizedDiff = FloatArray(diff.size) {
|
||||||
|
if (widget.received[it].isInfinite && widget.transferred[it].isInfinite)
|
||||||
|
0.5f
|
||||||
|
else if (diff[it].isInfinite && diff[it].isNegative)
|
||||||
|
0.1f
|
||||||
|
else if (diff[it].isInfinite && diff[it].isPositive)
|
||||||
|
0.9f
|
||||||
|
else
|
||||||
|
0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
received = FloatArray(diff.size) {
|
||||||
|
if (widget.received[it].isInfinite) 0.9f else 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
transferred = FloatArray(diff.size) {
|
||||||
|
if (widget.transferred[it].isInfinite) 0.1f else 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
labels = ChartLevelLabels(
|
||||||
|
labels = mapOf(
|
||||||
|
0.5f to Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias),
|
||||||
|
0.1f to TextComponent("-∞"),
|
||||||
|
0.9f to TextComponent("∞"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else if (hasPositiveInfinity) {
|
||||||
|
normalizedDiff = FloatArray(diff.size) {
|
||||||
|
if (diff[it].isInfinite)
|
||||||
|
0.9f
|
||||||
|
else
|
||||||
|
0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
received = FloatArray(diff.size) {
|
||||||
|
if (widget.received[it].isInfinite) 0.9f else 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
transferred = FloatArray(diff.size)
|
||||||
|
transferred.fill(0.5f)
|
||||||
|
|
||||||
|
labels = ChartLevelLabels(
|
||||||
|
labels = mapOf(
|
||||||
|
0.5f to Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias),
|
||||||
|
0.9f to TextComponent("∞"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else if (hasNegativeInfinity) {
|
||||||
|
normalizedDiff = FloatArray(diff.size) {
|
||||||
|
if (diff[it].isInfinite)
|
||||||
|
0.1f
|
||||||
|
else
|
||||||
|
0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
received = FloatArray(diff.size)
|
||||||
|
received.fill(0.5f)
|
||||||
|
|
||||||
|
transferred = FloatArray(diff.size) {
|
||||||
|
if (widget.transferred[it].isInfinite) 0.1f else 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
labels = ChartLevelLabels(
|
||||||
|
labels = mapOf(
|
||||||
|
0.5f to Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias),
|
||||||
|
0.9f to TextComponent("-∞"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val max = maxOf(widget.received.max(), widget.transferred.max())
|
||||||
|
val labelNames = Float2ObjectArrayMap<Component>()
|
||||||
|
|
||||||
|
labelNames[0.5f] = Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
||||||
|
|
||||||
|
if (max.isZero) {
|
||||||
|
normalizedDiff = FloatArray(diff.size)
|
||||||
|
normalizedDiff.fill(0.5f)
|
||||||
|
|
||||||
|
received = FloatArray(diff.size)
|
||||||
|
received.fill(0.5f)
|
||||||
|
|
||||||
|
transferred = FloatArray(diff.size)
|
||||||
|
transferred.fill(0.5f)
|
||||||
|
|
||||||
|
labelNames[0.1f] = TextComponent("-∞")
|
||||||
|
labelNames[0.9f] = TextComponent("∞")
|
||||||
|
} else {
|
||||||
|
normalizedDiff = FloatArray(diff.size) {
|
||||||
|
(diff[it] / max).toFloat() * 0.4f + 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
received = FloatArray(diff.size) {
|
||||||
|
(widget.received[it] / max).toFloat() * 0.4f + 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
transferred = FloatArray(diff.size) {
|
||||||
|
(widget.transferred[it] / max).toFloat() * -0.4f + 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
labelNames[0.1f] = (-max).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
||||||
|
if (verbose.asBoolean) labelNames[0.3f] = (-max * Decimal.ONE_HALF).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
||||||
|
labelNames[0.9f] = max.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
||||||
|
if (verbose.asBoolean) labelNames[0.7f] = (max * Decimal.ONE_HALF).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias)
|
||||||
|
}
|
||||||
|
|
||||||
|
labels = ChartLevelLabels(labels = labelNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
val charts: List<Pair<FloatArray, RGBAColor>>
|
||||||
|
val receivedActivity = widget.received.any { it.isNotZero }
|
||||||
|
val transferredActivity = widget.received.any { it.isNotZero }
|
||||||
|
|
||||||
|
if (!receivedActivity && transferredActivity) {
|
||||||
|
charts = listOf(
|
||||||
|
received to RGBAColor.YELLOW,
|
||||||
|
normalizedDiff to RGBAColor.WHITE,
|
||||||
|
transferred to RGBAColor.RED,
|
||||||
|
)
|
||||||
|
} else if (!transferredActivity && receivedActivity) {
|
||||||
|
charts = listOf(
|
||||||
|
transferred to RGBAColor.RED,
|
||||||
|
normalizedDiff to RGBAColor.WHITE,
|
||||||
|
received to RGBAColor.YELLOW,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
charts = listOf(
|
||||||
|
received to RGBAColor.YELLOW,
|
||||||
|
transferred to RGBAColor.RED,
|
||||||
|
normalizedDiff to RGBAColor.WHITE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add(Either.right(ChartTooltipElement(charts, if (verbose.asBoolean) 200f else 100f, if (verbose.asBoolean) 120f else 60f, levelLabels = labels)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun formatHistoryLines(
|
||||||
|
result: MutableList<Either<FormattedText, TooltipComponent>>,
|
||||||
widget: ProfiledLevelGaugeWidget<*>,
|
widget: ProfiledLevelGaugeWidget<*>,
|
||||||
bias: Int = 0,
|
bias: Int = 0,
|
||||||
decimals: Int = 3,
|
decimals: Int = 3,
|
||||||
@ -321,13 +500,13 @@ fun formatHistory(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.add(TextComponent(""))
|
result.add(Either.left(TextComponent("")))
|
||||||
result.add(lines.removeFirst().format())
|
result.add(Either.left(lines.removeFirst().format()))
|
||||||
|
|
||||||
if (verbose.asBoolean) {
|
if (verbose.asBoolean) {
|
||||||
result.add(TextComponent("---"))
|
result.add(Either.left(TextComponent("---")))
|
||||||
result.add(lines.removeFirst().format())
|
result.add(Either.left(lines.removeFirst().format()))
|
||||||
result.add(TextComponent("---"))
|
result.add(Either.left(TextComponent("---")))
|
||||||
lines.forEach { result.add(it.format()) }
|
lines.forEach { result.add(Either.left(it.format())) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user