Compare commits

...

4 Commits

37 changed files with 521 additions and 260 deletions

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity.tech package ru.dbotthepony.mc.otm.block.entity.tech
import com.google.common.collect.ImmutableList
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
@ -38,51 +39,32 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
BlockRotation.of(blockState[EnergyCounterBlock.INPUT_DIRECTION]) BlockRotation.of(blockState[EnergyCounterBlock.INPUT_DIRECTION])
} }
private val history = Array(10 * 20) { Decimal.ZERO } val history5s = DecimalHistoryGraph(1, 100)
internal var historyTick = 0 val history15s = DecimalHistoryGraph(3, 100)
val history1m = DecimalHistoryGraph(12, 100)
val history10m = DecimalHistoryGraph(120, 100)
val history1h = DecimalHistoryGraph(720, 100)
val history6h = DecimalHistoryGraph(720 * 6, 100)
val history24h = DecimalHistoryGraph(720 * 24, 100)
private val graphs = ImmutableList.of(
history5s, history15s, history1m, history10m, history1h, history6h, history24h,
)
init {
syncher.add(history5s)
}
private var thisTick = Decimal.ZERO
var lastTick by syncher.decimal() var lastTick by syncher.decimal()
internal set internal set
var ioLimit: Decimal? = null var ioLimit: Decimal? = null
fun resetStats() { fun resetStats() {
historyTick = 0 graphs.forEach { it.clear() }
lastTick = Decimal.ZERO lastTick = Decimal.ZERO
passed = Decimal.ZERO passed = Decimal.ZERO
Arrays.fill(history, Decimal.ZERO)
}
fun getHistory(ticks: Int): Array<Decimal> {
require(!(ticks < 1 || ticks >= history.size)) { "Invalid history length provided" }
val history = Array(ticks) { Decimal.ZERO }
for (i in 0 until ticks) {
var index = (historyTick - i) % this.history.size
if (index < 0) index = this.history.size - 1
history[i] = this.history[index]
}
return history
}
fun calcAverage(ticks: Int): Decimal {
return sumHistory(ticks) / ticks
}
fun sumHistory(ticks: Int): Decimal {
require(!(ticks < 1 || ticks >= history.size)) { "Invalid history length provided" }
var value = Decimal.ZERO
for (i in 0 until ticks) {
var index = (historyTick - i) % history.size
if (index < 0) index = history.size - 1
value += history[index]
}
return value
} }
override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) { override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) {
@ -93,12 +75,14 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) { override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveLevel(nbt, registry) super.saveLevel(nbt, registry)
val list = ListTag()
nbt[POWER_HISTORY_KEY] = list
nbt[POWER_HISTORY_POINTER_KEY] = historyTick
for (num in history) nbt["history5s"] = history5s.serializeNBT(registry)
list.add(num.serializeNBT()) nbt["history15s"] = history15s.serializeNBT(registry)
nbt["history1m"] = history1m.serializeNBT(registry)
nbt["history10m"] = history10m.serializeNBT(registry)
nbt["history1h"] = history1h.serializeNBT(registry)
nbt["history6h"] = history6h.serializeNBT(registry)
nbt["history24h"] = history24h.serializeNBT(registry)
} }
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
@ -107,15 +91,13 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
passed = nbt.getDecimal(PASSED_ENERGY_KEY) passed = nbt.getDecimal(PASSED_ENERGY_KEY)
ioLimit = nbt.mapPresent(IO_LIMIT_KEY, Decimal.Companion::deserializeNBT) ioLimit = nbt.mapPresent(IO_LIMIT_KEY, Decimal.Companion::deserializeNBT)
nbt.map(POWER_HISTORY_POINTER_KEY) { it: IntTag -> nbt.map("history5s") { it: CompoundTag -> history5s.deserializeNBT(registry, it) }
historyTick = it.asInt nbt.map("history15s") { it: CompoundTag -> history15s.deserializeNBT(registry, it) }
} nbt.map("history1m") { it: CompoundTag -> history1m.deserializeNBT(registry, it) }
nbt.map("history10m") { it: CompoundTag -> history10m.deserializeNBT(registry, it) }
Arrays.fill(history, Decimal.ZERO) nbt.map("history1h") { it: CompoundTag -> history1h.deserializeNBT(registry, it) }
nbt.map("history6h") { it: CompoundTag -> history6h.deserializeNBT(registry, it) }
for ((i, bytes) in nbt.getByteArrayList(POWER_HISTORY_KEY).withIndex()) { nbt.map("history24h") { it: CompoundTag -> history24h.deserializeNBT(registry, it) }
history[i] = Decimal.deserializeNBT(bytes)
}
} }
override val defaultDisplayName: Component override val defaultDisplayName: Component
@ -153,7 +135,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
if (!simulate) { if (!simulate) {
passed += diff passed += diff
history[historyTick] += diff thisTick += diff
} }
return diff return diff
@ -181,7 +163,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
if (!simulate) { if (!simulate) {
passed += diff passed += diff
history[historyTick] += diff thisTick += diff
} }
return diff return diff
@ -286,22 +268,21 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override fun tick() { override fun tick() {
super.tick() super.tick()
lastTick = history[historyTick] lastTick = thisTick
historyTick = (historyTick + 1) % history.size graphs.forEach { it.add(thisTick) }
history[historyTick] = Decimal.ZERO thisTick = Decimal.ZERO
} }
fun clientTick() { fun clientTick() {
historyTick = (historyTick + 1) % history.size // TODO
history[historyTick] = lastTick // historyTick = (historyTick + 1) % history.size
passed += lastTick // history[historyTick] = lastTick
// passed += lastTick
} }
companion object { companion object {
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.energy_counter") private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.energy_counter")
const val PASSED_ENERGY_KEY = "passedEnergy" const val PASSED_ENERGY_KEY = "passedEnergy"
const val IO_LIMIT_KEY = "IOLimit" const val IO_LIMIT_KEY = "IOLimit"
const val POWER_HISTORY_KEY = "passHistory"
const val POWER_HISTORY_POINTER_KEY = "passHistoryPointer"
} }
} }

View File

@ -90,9 +90,6 @@ class DynamicBufferSource(
init { init {
if ( if (
type.name == "neoforge_text" ||
type.name == "text_intensity" ||
type.name == "neoforge_text_see_through" ||
type.name.contains("font_") || type.name.contains("font_") ||
type.name.contains("text_") || type.name.contains("text_") ||
type.name.contains("_text") || type.name.contains("_text") ||

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.client.render
import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexSorting import com.mojang.blaze3d.vertex.VertexSorting
import net.minecraft.client.gui.Font import net.minecraft.client.gui.Font
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.renderer.MultiBufferSource import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.util.FormattedCharSequence import net.minecraft.util.FormattedCharSequence
@ -279,6 +278,59 @@ fun Font.draw(
) )
} }
data class TextIcon(
val font: Font,
val text: Component,
val scale: Float = 1f,
val color: RGBAColor = RGBAColor.WHITE,
val drawShadow: Boolean = false,
val displayMode: Font.DisplayMode = Font.DisplayMode.NORMAL,
val packedLightCoords: Int = 15728880,
val effectColor: Int = 0,
val shadowColor: RGBAColor = RGBAColor.BLACK,
val shadowX: Float = 1f,
val shadowY: Float = 1f,
val shadowZ: Float = 0.1f,
val customShadow: Boolean = false,
val drawOutline: Boolean = false,
val outlineColor: RGBAColor = RGBAColor.BLACK,
val outlineZ: Float = 0.1f,
) : IGUIRenderable {
override val width: Float = font.width(text) * scale
override val height: Float = font.lineHeight * scale
override fun render(
guiGraphics: MGUIGraphics,
x: Float,
y: Float,
canvasWidth: Float,
canvasHeight: Float,
winding: UVWindingOrder,
color: RGBAColor
) {
font.draw(
guiGraphics.pose,
text,
RenderGravity.CENTER_CENTER.x(x + canvasWidth / 2f, this.width),
RenderGravity.CENTER_CENTER.y(y + canvasHeight / 2f, this.height),
scale = scale,
gravity = RenderGravity.TOP_LEFT,
color = this.color * color,
drawShadow = drawShadow,
displayMode = displayMode,
packedLightCoords = packedLightCoords,
effectColor = effectColor,
shadowColor = shadowColor,
shadowX = shadowX,
shadowY = shadowY,
shadowZ = shadowZ,
customShadow = customShadow,
drawOutline = drawOutline,
outlineColor = outlineColor,
outlineZ = outlineZ,)
}
}
fun Font.draw( fun Font.draw(
poseStack: PoseStack, poseStack: PoseStack,
text: String, text: String,

View File

@ -0,0 +1,107 @@
package ru.dbotthepony.mc.otm.client.render
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexFormat
import net.minecraft.client.gui.Font
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.network.chat.Component
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.kommons.math.linearInterpolation
import kotlin.math.PI
import kotlin.math.acos
import kotlin.math.cos
import kotlin.math.pow
import kotlin.math.sign
import kotlin.math.sin
private const val LINE_WIDTH = 1f
private const val HIGHLIGHT_WIDTH = 3f
private val TEXT_BACKGROUND = RGBAColor(0f, 0f, 0f, 0.5f)
data class GraphMouseLabels(
val mouseX: Float,
val mouseY: Float,
val labels: (Int) -> Component,
val font: Font,
val color: RGBAColor = RGBAColor.WHITE,
val pillarColor: RGBAColor = RGBAColor.WHITE,
val textColor: RGBAColor = RGBAColor.WHITE,
val textBackgroundColor: RGBAColor = TEXT_BACKGROUND
)
fun renderGraph(
poseStack: PoseStack,
normalized: FloatArray,
width: Float,
height: Float,
color: RGBAColor = RGBAColor.WHITE,
labels: GraphMouseLabels? = null,
x: Float = 0f,
y: Float = 0f,
) {
val builder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION)
val step = width / normalized.size
val pose = poseStack.last().pose
val checkLabels = labels != null && labels.mouseY in 0f .. height && labels.mouseX in 0f .. width
var drawLabel = -1
var drawPointX = 0f
var drawPointY = 0f
for (i in 0 until normalized.size - 1) {
val y0 = y + (1f - normalized[i]) * height
val y1 = y + (1f - normalized[i + 1]) * height
val x0 = x + width - (i + 0.5f) * step
val x1 = x + width - (i + 1.5f) * step
val xDiff = x1 - x0
val yDiff = y1 - y0
val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f)
val angle = acos(xDiff / length) * yDiff.sign - PI / 2f // rotate 90 deg
val xDisp = cos(angle).toFloat() * LINE_WIDTH / 2f
val yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f
builder.vertex(pose, x1 - xDisp, y1 + yDisp, 0f)
builder.vertex(pose, x1 + xDisp, y1 - yDisp, 0f)
builder.vertex(pose, x0 + xDisp, y0 - yDisp, 0f)
builder.vertex(pose, x0 - xDisp, y0 + yDisp, 0f)
//graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH)
if (checkLabels && drawLabel == -1 && labels!!.mouseX in x1 .. x0) {
drawLabel = i
drawPointX = x0 // linearInterpolation(0.5f, x0, x1)
drawPointY = y0 // linearInterpolation(0.5f, y0, y1)
}
}
RenderSystem.setShader(GameRenderer::getPositionShader)
RenderSystem.setShaderColor(color.red, color.green, color.blue, color.alpha)
RenderSystem.disableDepthTest()
RenderSystem.disableBlend()
BufferUploader.drawWithShader(builder.buildOrThrow())
if (drawLabel != -1) {
renderRect(pose, drawPointX - LINE_WIDTH / 2f, y, LINE_WIDTH, height, color = labels!!.pillarColor)
renderRect(pose, drawPointX - HIGHLIGHT_WIDTH / 2f, drawPointY - HIGHLIGHT_WIDTH / 2f, HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, color = labels.color)
val label = labels.labels(drawLabel)
val fWidth = labels.font.width(label).toFloat() + 2f
val fHeight = labels.font.lineHeight.toFloat() + 2f
val anchorX = labels.mouseX // drawPointX
val anchorY = labels.mouseY - fHeight / 2f - 2f
renderRect(pose, anchorX - fWidth / 2f, anchorY - fHeight / 2f, fWidth, fHeight, color = labels.textBackgroundColor)
labels.font.draw(poseStack, label, anchorX, anchorY, gravity = RenderGravity.CENTER_CENTER, color = labels.textColor)
}
}

View File

@ -31,14 +31,14 @@ interface IGUIRenderable {
} }
/** /**
* Render at specified position [x], [y] with size of [width] x [height], optionally with UV [winding], if we are rendering flat texture/sprite * Render at specified position [x], [y] with **canvas** size of [canvasWidth] x [canvasHeight], optionally with UV [winding], if we are rendering flat texture/sprite
*/ */
fun render( fun render(
guiGraphics: MGUIGraphics, guiGraphics: MGUIGraphics,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = this.width, canvasWidth: Float = this.width,
height: Float = this.height, canvasHeight: Float = this.height,
winding: UVWindingOrder = this.winding, winding: UVWindingOrder = this.winding,
color: RGBAColor = RGBAColor.WHITE color: RGBAColor = RGBAColor.WHITE
) )
@ -50,9 +50,9 @@ interface IGUIRenderable {
override val height: Float override val height: Float
get() = this@IGUIRenderable.height.coerceAtLeast(other.height) get() = this@IGUIRenderable.height.coerceAtLeast(other.height)
override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder, color: RGBAColor) { override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, canvasWidth: Float, canvasHeight: Float, winding: UVWindingOrder, color: RGBAColor) {
this@IGUIRenderable.render(guiGraphics, x, y, width, height, winding, color) this@IGUIRenderable.render(guiGraphics, x, y, canvasWidth, canvasHeight, winding, color)
other.render(guiGraphics, x, y, width, height, winding, color) other.render(guiGraphics, x, y, canvasWidth, canvasHeight, winding, color)
} }
} }
} }
@ -68,8 +68,8 @@ interface IGUIRenderable {
override val height: Float override val height: Float
get() = this@IGUIRenderable.height get() = this@IGUIRenderable.height
override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder, color: RGBAColor) { override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, canvasWidth: Float, canvasHeight: Float, winding: UVWindingOrder, color: RGBAColor) {
this@IGUIRenderable.render(guiGraphics, x + left, y + top, width + right + left, height + bottom + top, winding, color) this@IGUIRenderable.render(guiGraphics, x + left, y + top, canvasWidth + right + left, canvasHeight + bottom + top, winding, color)
} }
} }
} }
@ -91,19 +91,19 @@ interface IGUIRenderable {
override val height: Float override val height: Float
get() = this@IGUIRenderable.height get() = this@IGUIRenderable.height
override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder, color: RGBAColor) { override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, canvasWidth: Float, canvasHeight: Float, winding: UVWindingOrder, color: RGBAColor) {
var realX = x var realX = x
var realY = y var realY = y
if (fixedWidth && width > this.width) { if (fixedWidth && canvasWidth > this.width) {
realX += gravity.repositionX(width, this.width) realX += gravity.repositionX(canvasWidth, this.width)
} }
if (fixedHeight && height > this.height) { if (fixedHeight && canvasHeight > this.height) {
realY += gravity.repositionY(height, this.height) realY += gravity.repositionY(canvasHeight, this.height)
} }
this@IGUIRenderable.render(guiGraphics, realX, realY, if (fixedWidth) this.width else width, if (fixedHeight) this.height else height, if (fixedWinding) this.winding else winding, color) this@IGUIRenderable.render(guiGraphics, realX, realY, if (fixedWidth) this.width else canvasWidth, if (fixedHeight) this.height else canvasHeight, if (fixedWinding) this.winding else winding, color)
} }
} }
} }
@ -120,24 +120,24 @@ interface IGUIRenderable {
} }
data class ItemStackIcon(private val itemStack: ItemStack, override val width: Float = 16f, override val height: Float = 16f) : IGUIRenderable { data class ItemStackIcon(private val itemStack: ItemStack, override val width: Float = 16f, override val height: Float = 16f) : IGUIRenderable {
override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder, color: RGBAColor) { override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, canvasWidth: Float, canvasHeight: Float, winding: UVWindingOrder, color: RGBAColor) {
val pose = guiGraphics.pose val pose = guiGraphics.pose
pose.pushPose() pose.pushPose()
pose.translate(x, y, 0f) pose.translate(x, y, 0f)
pose.scale(width / 16f, height / 16f, 1f) pose.scale(canvasWidth / 16f, canvasHeight / 16f, 1f)
guiGraphics.setColor(color.red, color.green, color.blue, color.alpha) guiGraphics.setColor(color.red, color.green, color.blue, color.alpha)
guiGraphics.renderFakeItem(itemStack, 0, 0) guiGraphics.renderFakeItem(itemStack, 0, 0)
pose.popPose() pose.popPose()
clearDepth(pose, x, y, width, height) clearDepth(pose, x, y, canvasWidth, canvasHeight)
} }
} }
data class FlatRectangleIcon(override val width: Float = 1f, override val height: Float = 1f, val color: RGBAColor) : IGUIRenderable { data class FlatRectangleIcon(override val width: Float = 1f, override val height: Float = 1f, val color: RGBAColor) : IGUIRenderable {
override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, width: Float, height: Float, winding: UVWindingOrder, color: RGBAColor) { override fun render(guiGraphics: MGUIGraphics, x: Float, y: Float, canvasWidth: Float, canvasHeight: Float, winding: UVWindingOrder, color: RGBAColor) {
guiGraphics.renderRect(x, y, width, height, color = this.color) guiGraphics.renderRect(x, y, canvasWidth, canvasHeight, color = this.color)
} }
} }

View File

@ -62,6 +62,8 @@ object Widgets18 {
val FORWARD_SLASH = miscGrid.next() val FORWARD_SLASH = miscGrid.next()
val RETURN_ARROW_LEFT = miscGrid.next() val RETURN_ARROW_LEFT = miscGrid.next()
val CURIOS_INVENTORY = miscGrid.next() val CURIOS_INVENTORY = miscGrid.next()
val STATISTICS_TAB = miscGrid.next()
val SETTINGS_TAB = miscGrid.next()
private val slotBgGrid = WidgetLocation.SLOT_BACKGROUNDS.grid(4, 4) private val slotBgGrid = WidgetLocation.SLOT_BACKGROUNDS.grid(4, 4)

View File

@ -57,7 +57,7 @@ class EnergyCounterRenderer(private val context: BlockEntityRendererProvider.Con
poseStack.pushPose() poseStack.pushPose()
poseStack.translate(-0.1, -0.1, -0.1) poseStack.translate(-0.1, -0.1, -0.1)
font.draw(poseStack, buffer = sorse, text = tile.lastTick.toString(0), gravity = RenderGravity.CENTER_RIGHT, x = finalX, y = y, color = RGBAColor.WHITE) font.draw(poseStack, buffer = sorse, text = tile.lastTick.toString(0), gravity = RenderGravity.CENTER_RIGHT, x = finalX, y = y, color = RGBAColor.WHITE)
font.draw(poseStack, buffer = sorse, text = tile.sumHistory(20).toString(0), gravity = RenderGravity.CENTER_RIGHT, x = finalX, y = y + font.lineHeight, color = RGBAColor.WHITE) font.draw(poseStack, buffer = sorse, text = tile.history5s.calculateSum(20).toString(0), gravity = RenderGravity.CENTER_RIGHT, x = finalX, y = y + font.lineHeight, color = RGBAColor.WHITE)
poseStack.popPose() poseStack.popPose()
y += font.lineHeight * 3 y += font.lineHeight * 3

View File

@ -75,12 +75,12 @@ sealed class AbstractMatterySprite : IGUIRenderable, IUVCoords {
guiGraphics: MGUIGraphics, guiGraphics: MGUIGraphics,
x: Float, x: Float,
y: Float, y: Float,
width: Float, canvasWidth: Float,
height: Float, canvasHeight: Float,
winding: UVWindingOrder, winding: UVWindingOrder,
color: RGBAColor color: RGBAColor
) { ) {
guiGraphics.renderTexturedRect(x, y, width, height, uvWinding = winding, color = color, texture = texture, uv = this) guiGraphics.renderTexturedRect(x, y, canvasWidth, canvasHeight, uvWinding = winding, color = color, texture = texture, uv = this)
} }
fun renderPartial( fun renderPartial(

View File

@ -23,8 +23,6 @@ import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.setMousePos import ru.dbotthepony.mc.otm.client.setMousePos
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded
import ru.dbotthepony.mc.otm.compat.curios.openCuriosScreen
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
import ru.dbotthepony.mc.otm.network.ExopackMenuOpen import ru.dbotthepony.mc.otm.network.ExopackMenuOpen
@ -151,7 +149,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
height = topLine.height, centerSprite = true) height = topLine.height, centerSprite = true)
if (menu.capability.isExopackSmeltingInstalled || menu.capability.isExopackEnderAccessInstalled) { if (menu.capability.isExopackSmeltingInstalled || menu.capability.isExopackEnderAccessInstalled) {
val craftingTab = frame.Tab() val craftingTab = frame.CustomTab()
craftingTab.activeIcon = ItemStackIcon(ItemStack(Items.CRAFTING_TABLE)) craftingTab.activeIcon = ItemStackIcon(ItemStack(Items.CRAFTING_TABLE))
craftingTab.inactiveIcon = craftingTab.activeIcon craftingTab.inactiveIcon = craftingTab.activeIcon
@ -161,7 +159,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
} }
if (menu.capability.isExopackSmeltingInstalled) { if (menu.capability.isExopackSmeltingInstalled) {
val tab = frame.Tab() val tab = frame.CustomTab()
tab.activeIcon = ItemStackIcon(ItemStack(Items.FURNACE)) tab.activeIcon = ItemStackIcon(ItemStack(Items.FURNACE))
tab.inactiveIcon = tab.activeIcon tab.inactiveIcon = tab.activeIcon
@ -205,7 +203,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
} }
if (menu.capability.isExopackEnderAccessInstalled) { if (menu.capability.isExopackEnderAccessInstalled) {
val tab = frame.Tab() val tab = frame.CustomTab()
tab.activeIcon = ItemStackIcon(ItemStack(Items.ENDER_CHEST)) tab.activeIcon = ItemStackIcon(ItemStack(Items.ENDER_CHEST))
tab.inactiveIcon = tab.activeIcon tab.inactiveIcon = tab.activeIcon

View File

@ -122,11 +122,11 @@ class MatterPanelScreen(
scrollBar.dock = Dock.RIGHT scrollBar.dock = Dock.RIGHT
frame.Tab(onOpen = { isPatternView = true; scrollBar.scroll = scrollPatterns }, activeIcon = PATTERN_LIST_ACTIVE, inactiveIcon = PATTERN_LIST_INACTIVE).also { frame.CustomTab(onOpen = { isPatternView = true; scrollBar.scroll = scrollPatterns }, activeIcon = PATTERN_LIST_ACTIVE, inactiveIcon = PATTERN_LIST_INACTIVE).also {
it.tooltips.add(TranslatableComponent("otm.gui.matter_panel.patterns")) it.tooltips.add(TranslatableComponent("otm.gui.matter_panel.patterns"))
} }
frame.Tab(onOpen = { isPatternView = false; scrollBar.scroll = scrollTasks }, activeIcon = TASK_LIST_ACTIVE, inactiveIcon = TASK_LIST_INACTIVE).also { frame.CustomTab(onOpen = { isPatternView = false; scrollBar.scroll = scrollTasks }, activeIcon = TASK_LIST_ACTIVE, inactiveIcon = TASK_LIST_INACTIVE).also {
it.tooltips.add(TranslatableComponent("otm.gui.matter_panel.tasks")) it.tooltips.add(TranslatableComponent("otm.gui.matter_panel.tasks"))
} }

View File

@ -0,0 +1,19 @@
package ru.dbotthepony.mc.otm.client.screen.panels
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.core.AbstractHistoryGraph
abstract class AbstractHistoryGraphPanel<out S : MatteryScreen<*>, G : AbstractHistoryGraph<V>, V : Any>(
screen: S,
parent: EditablePanel<*>,
val graph: G,
x: Float = 0f,
y: Float = 0f,
width: Float = 10f,
height: Float = 10f
) : EditablePanel<S>(screen, parent, x, y, width, height) {
data class GraphData<V : Any>(val maximum: V)
protected abstract fun determineGraphData(): GraphData<V>
protected abstract fun ratio(value: V, maximum: V): Float
}

View File

@ -5,7 +5,6 @@ import com.mojang.datafixers.util.Either
import it.unimi.dsi.fastutil.floats.FloatConsumer import it.unimi.dsi.fastutil.floats.FloatConsumer
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.resources.ResourceLocation
import ru.dbotthepony.kommons.math.HSVColor import ru.dbotthepony.kommons.math.HSVColor
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.client.CursorType import ru.dbotthepony.mc.otm.client.CursorType
@ -118,8 +117,8 @@ open class ColorBoxPanel<out S : Screen>(
val x = (1f - markerPos.saturation) * width val x = (1f - markerPos.saturation) * width
val y = (1f - markerPos.value) * height val y = (1f - markerPos.value) * height
LINE_VERTICAL.render(graphics, x = x - 1f, height = height) LINE_VERTICAL.render(graphics, x = x - 1f, canvasHeight = height)
LINE_HORIZONTAL.render(graphics, y = y - 1f, width = width) LINE_HORIZONTAL.render(graphics, y = y - 1f, canvasWidth = width)
LINE_CROSS.render(graphics, x = x - 1f, y = y - 1f) LINE_CROSS.render(graphics, x = x - 1f, y = y - 1f)
} }
@ -216,7 +215,7 @@ abstract class AbstractColorWangPanel<out S : Screen>(
protected fun renderWang(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { protected fun renderWang(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (wangPosition in 0f .. 1f) { if (wangPosition in 0f .. 1f) {
ColorBoxPanel.LINE_VERTICAL.render(graphics, x = wangPosition * width - 1f, height = height) ColorBoxPanel.LINE_VERTICAL.render(graphics, x = wangPosition * width - 1f, canvasHeight = height)
} }
} }

View File

@ -0,0 +1,54 @@
package ru.dbotthepony.mc.otm.client.screen.panels
import net.minecraft.network.chat.Component
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.client.render.GraphMouseLabels
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.renderGraph
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.core.DecimalHistoryGraph
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.math.Decimal
open class DecimalHistoryGraphPanel<out S : MatteryScreen<*>>(
screen: S,
parent: EditablePanel<*>,
val graph: DecimalHistoryGraph,
val formatText: (Decimal) -> Component = { TextComponent(it.toString(2)) },
x: Float = 0f,
y: Float = 0f,
width: Float = 10f,
height: Float = 10f
) : EditablePanel<S>(screen, parent, x, y, width, height) {
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
val maximum = graph.max()
val normalized: FloatArray
if (maximum.isZero || maximum.isInfinite) {
normalized = FloatArray(graph.width) {
if (graph[it].isInfinite) 0.8f else 0.0f
}
} else {
normalized = FloatArray(graph.width) { (graph[it] / maximum).toFloat() * 0.9f }
}
graphics.renderRect(0f, 0f, this.width, this.height, color = RGBAColor.BLACK)
renderGraph(
graphics.pose,
normalized,
width,
height,
labels = GraphMouseLabels(
mouseX - absoluteX,
mouseY - absoluteY,
{ formatText(graph[it]) },
font,
)
)
}
companion object {
}
}

View File

@ -5,7 +5,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.core.Holder import net.minecraft.core.Holder
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.effect.MobEffect import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectInstance import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
@ -110,7 +109,7 @@ open class EffectListPanel<out S : Screen> @JvmOverloads constructor(
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
clearDepth(graphics) clearDepth(graphics)
SQUARE_THIN.render(graphics, width = width, height = height) SQUARE_THIN.render(graphics, canvasWidth = width, canvasHeight = height)
RenderSystem.setShaderColor(1f, 1f, 1f, 0.5f) RenderSystem.setShaderColor(1f, 1f, 1f, 0.5f)
graphics.renderSprite(minecraft.mobEffectTextures.get(effect.effect), x = 3f, y = 3f, width = width - 6f, height = height - 6f) graphics.renderSprite(minecraft.mobEffectTextures.get(effect.effect), x = 3f, y = 3f, width = width - 6f, height = height - 6f)

View File

@ -27,30 +27,10 @@ open class FramePanel<out S : Screen>(
) : EditablePanel<S>(screen, parent, x, y, width, height), NarratableEntry { ) : EditablePanel<S>(screen, parent, x, y, width, height), NarratableEntry {
constructor(screen: S, width: Float, height: Float, title: Component? = null) : this(screen, null, 0f, 0f, width, height, title) constructor(screen: S, width: Float, height: Float, title: Component? = null) : this(screen, null, 0f, 0f, width, height, title)
open inner class Tab( abstract inner class AbstractTab(
var onOpen: Runnable? = null,
var onClose: Runnable? = null,
var activeIcon: IGUIRenderable? = null, var activeIcon: IGUIRenderable? = null,
var inactiveIcon: IGUIRenderable? = activeIcon, var inactiveIcon: IGUIRenderable? = activeIcon,
) : AbstractButtonPanel<S>(this@FramePanel.screen, this@FramePanel, 0f, 0f, 26f, 28f) { ) : AbstractButtonPanel<S>(this@FramePanel.screen, this@FramePanel, 0f, 0f, 26f, 28f) {
constructor(panels: List<EditablePanel<*>>, activeIcon: IGUIRenderable? = null, inactiveIcon: IGUIRenderable? = activeIcon) : this(activeIcon = activeIcon, inactiveIcon = inactiveIcon) {
onOpen = Runnable {
for (panel in panels) {
panel.visible = true
}
}
onClose = Runnable {
for (panel in panels) {
panel.visible = false
}
}
if (!isActive) {
onClose!!.run()
}
}
var isActive = tabs.isEmpty() var isActive = tabs.isEmpty()
protected set protected set
@ -58,24 +38,6 @@ open class FramePanel<out S : Screen>(
tabs.add(this) tabs.add(this)
} }
fun showHidePanels(input: List<EditablePanel<*>>) {
onOpen = Runnable {
for (child in input) {
child.visible = true
}
}
onClose = Runnable {
for (child in input) {
child.visible = false
}
}
}
protected fun tabIndex(): Int {
return tabs.indexOf(this)
}
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (isActive) { if (isActive) {
if (tabIndex() == 0) { if (tabIndex() == 0) {
@ -128,12 +90,16 @@ open class FramePanel<out S : Screen>(
} }
} }
protected open fun onOpen() { protected fun tabIndex(): Int {
onOpen?.run() return tabs.indexOf(this)
} }
protected open fun onClose() { protected abstract fun onOpen()
onClose?.run() protected abstract fun onClose()
override fun onRemoved() {
super.onRemoved()
tabs.remove(this)
} }
fun activate() { fun activate() {
@ -152,13 +118,77 @@ open class FramePanel<out S : Screen>(
} }
} }
override fun onClick(mouseButton: Int) { final override fun onClick(mouseButton: Int) {
activate() if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
activate()
}
}
}
inner class CustomTab(
var onOpen: Runnable? = null,
var onClose: Runnable? = null,
activeIcon: IGUIRenderable? = null,
inactiveIcon: IGUIRenderable? = activeIcon,
) : AbstractTab(activeIcon, inactiveIcon) {
constructor(panels: List<EditablePanel<*>>, activeIcon: IGUIRenderable? = null, inactiveIcon: IGUIRenderable? = activeIcon) : this(activeIcon = activeIcon, inactiveIcon = inactiveIcon) {
onOpen = Runnable {
for (panel in panels) {
panel.visible = true
}
}
onClose = Runnable {
for (panel in panels) {
panel.visible = false
}
}
if (!isActive) {
onClose!!.run()
}
} }
override fun onRemoved() { fun showHidePanels(input: List<EditablePanel<*>>) {
super.onRemoved() onOpen = Runnable {
tabs.remove(this) for (child in input) {
child.visible = true
}
}
onClose = Runnable {
for (child in input) {
child.visible = false
}
}
}
override fun onOpen() {
onOpen?.run()
}
override fun onClose() {
onClose?.run()
}
}
inner class Tab(
activeIcon: IGUIRenderable? = null,
inactiveIcon: IGUIRenderable? = activeIcon,
) : AbstractTab(activeIcon, inactiveIcon) {
val canvas = EditablePanel(screen, this@FramePanel)
init {
canvas.visible = isActive
canvas.dock = Dock.FILL
}
override fun onOpen() {
canvas.visible = true
}
override fun onClose() {
canvas.visible = false
} }
} }
@ -238,7 +268,7 @@ open class FramePanel<out S : Screen>(
} }
} }
protected val tabs: ArrayList<FramePanel<*>.Tab> = ArrayList() protected val tabs: ArrayList<FramePanel<*>.AbstractTab> = ArrayList()
override fun performLayout() { override fun performLayout() {
for ((i, tab) in tabs.withIndex()) { for ((i, tab) in tabs.withIndex()) {

View File

@ -83,9 +83,9 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
super.innerRender(graphics, mouseX, mouseY, partialTick) super.innerRender(graphics, mouseX, mouseY, partialTick)
if (prop.value) { if (prop.value) {
iconActive?.render(graphics, width = width, height = height) iconActive?.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
iconInactive?.render(graphics, width = width, height = height) iconInactive?.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} }

View File

@ -28,28 +28,28 @@ open class CheckBoxPanel<out S : Screen>(
protected fun renderCheckboxBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { protected fun renderCheckboxBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (isDisabled) { if (isDisabled) {
if (isChecked.get()) { if (isChecked.get()) {
DISABLED_CHECKED.render(graphics, width = width, height = height) DISABLED_CHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
DISABLED_UNCHECKED.render(graphics, width = width, height = height) DISABLED_UNCHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} else { } else {
if (isPressed) { if (isPressed) {
if (isChecked.get()) { if (isChecked.get()) {
PRESSED_CHECKED.render(graphics, width = width, height = height) PRESSED_CHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
PRESSED_UNCHECKED.render(graphics, width = width, height = height) PRESSED_UNCHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} else if (isHovered) { } else if (isHovered) {
if (isChecked.get()) { if (isChecked.get()) {
HOVERED_CHECKED.render(graphics, width = width, height = height) HOVERED_CHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
HOVERED_UNCHECKED.render(graphics, width = width, height = height) HOVERED_UNCHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} else { } else {
if (isChecked.get()) { if (isChecked.get()) {
IDLE_CHECKED.render(graphics, width = width, height = height) IDLE_CHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
IDLE_UNCHECKED.render(graphics, width = width, height = height) IDLE_UNCHECKED.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} }
} }

View File

@ -31,9 +31,9 @@ open class LargeRectangleButtonPanel<out S : Screen>(
val color = if (isDisabled || isPressed) RGBAColor.DARK_GRAY else RGBAColor.WHITE val color = if (isDisabled || isPressed) RGBAColor.DARK_GRAY else RGBAColor.WHITE
if (iconWinding != null) { if (iconWinding != null) {
icon?.render(graphics, width = width, height = height, winding = iconWinding!!, color = color) icon?.render(graphics, canvasWidth = width, canvasHeight = height, winding = iconWinding!!, color = color)
} else { } else {
icon?.render(graphics, width = width, height = height, color = color) icon?.render(graphics, canvasWidth = width, canvasHeight = height, color = color)
} }
} }

View File

@ -27,9 +27,9 @@ open class SmallRectangleButtonPanel<out S : Screen>(
super.innerRender(graphics, mouseX, mouseY, partialTick) super.innerRender(graphics, mouseX, mouseY, partialTick)
if (skinElementWinding != null) { if (skinElementWinding != null) {
skinElement?.render(graphics, width = width, height = height, winding = skinElementWinding) skinElement?.render(graphics, canvasWidth = width, canvasHeight = height, winding = skinElementWinding)
} else { } else {
skinElement?.render(graphics, width = width, height = height) skinElement?.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} }

View File

@ -27,7 +27,7 @@ abstract class AbstractSlotPanel<out S : MatteryScreen<*>>(
abstract val itemStack: ItemStack abstract val itemStack: ItemStack
protected open fun renderSlotBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { protected open fun renderSlotBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
SLOT_BACKGROUND.render(graphics, width = width, height = height) SLOT_BACKGROUND.render(graphics, canvasWidth = width, canvasHeight = height)
slotBackground?.render(graphics, 0f, 0f, width, height) slotBackground?.render(graphics, 0f, 0f, width, height)
} }

View File

@ -99,7 +99,7 @@ open class SlotPanel<out S : MatteryScreen<*>, out T : Slot>(
RenderSystem.setShaderTexture(0, texture.atlasLocation()) RenderSystem.setShaderTexture(0, texture.atlasLocation())
graphics.renderSprite(texture, 1f, 1f, 16f, 16f) graphics.renderSprite(texture, 1f, 1f, 16f, 16f)
} else { } else {
slotBackgroundEmpty?.render(graphics, 0f, 0f, width = width, height = height) slotBackgroundEmpty?.render(graphics, 0f, 0f, canvasWidth = width, canvasHeight = height)
} }
} }

View File

@ -33,23 +33,23 @@ open class AnalogScrollBarPanel<out S : Screen>(
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (this@AnalogScrollBarPanel.width == ScrollBarConstants.SLIM_WIDTH) { if (this@AnalogScrollBarPanel.width == ScrollBarConstants.SLIM_WIDTH) {
if (isScrolling) { if (isScrolling) {
ScrollBarConstants.SLIM_BUTTON_PRESS.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON_PRESS.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (maxScroll.invoke(this@AnalogScrollBarPanel) <= 0) { } else if (maxScroll.invoke(this@AnalogScrollBarPanel) <= 0) {
ScrollBarConstants.SLIM_BUTTON_DISABLED.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON_DISABLED.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (isHovered) { } else if (isHovered) {
ScrollBarConstants.SLIM_BUTTON_HOVER.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON_HOVER.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
ScrollBarConstants.SLIM_BUTTON.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} else { } else {
if (isScrolling) { if (isScrolling) {
ScrollBarConstants.BUTTON_PRESS.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON_PRESS.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (maxScroll.invoke(this@AnalogScrollBarPanel) <= 0) { } else if (maxScroll.invoke(this@AnalogScrollBarPanel) <= 0) {
ScrollBarConstants.BUTTON_DISABLED.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON_DISABLED.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (isHovered) { } else if (isHovered) {
ScrollBarConstants.BUTTON_HOVER.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON_HOVER.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
ScrollBarConstants.BUTTON.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} }
} }
@ -104,11 +104,11 @@ open class AnalogScrollBarPanel<out S : Screen>(
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (width == ScrollBarConstants.SLIM_WIDTH) { if (width == ScrollBarConstants.SLIM_WIDTH) {
ScrollBarConstants.SLIM_BODY.render(graphics, y = 2f, height = height - 4f) ScrollBarConstants.SLIM_BODY.render(graphics, y = 2f, canvasHeight = height - 4f)
ScrollBarConstants.SLIM_TOP.render(graphics) ScrollBarConstants.SLIM_TOP.render(graphics)
ScrollBarConstants.SLIM_BOTTOM.render(graphics, y = height - 2f) ScrollBarConstants.SLIM_BOTTOM.render(graphics, y = height - 2f)
} else { } else {
ScrollBarConstants.BODY.render(graphics, y = 2f, height = height - 4f) ScrollBarConstants.BODY.render(graphics, y = 2f, canvasHeight = height - 4f)
ScrollBarConstants.TOP.render(graphics) ScrollBarConstants.TOP.render(graphics)
ScrollBarConstants.BOTTOM.render(graphics, y = height - 2f) ScrollBarConstants.BOTTOM.render(graphics, y = height - 2f)
} }

View File

@ -27,23 +27,23 @@ open class DiscreteScrollBarPanel<out S : Screen>(
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (this@DiscreteScrollBarPanel.width == ScrollBarConstants.SLIM_WIDTH) { if (this@DiscreteScrollBarPanel.width == ScrollBarConstants.SLIM_WIDTH) {
if (isScrolling) { if (isScrolling) {
ScrollBarConstants.SLIM_BUTTON_PRESS.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON_PRESS.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (maxScroll.invoke(this@DiscreteScrollBarPanel) <= 0) { } else if (maxScroll.invoke(this@DiscreteScrollBarPanel) <= 0) {
ScrollBarConstants.SLIM_BUTTON_DISABLED.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON_DISABLED.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (isHovered) { } else if (isHovered) {
ScrollBarConstants.SLIM_BUTTON_HOVER.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON_HOVER.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
ScrollBarConstants.SLIM_BUTTON.render(graphics, width = width, height = height) ScrollBarConstants.SLIM_BUTTON.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} else { } else {
if (isScrolling) { if (isScrolling) {
ScrollBarConstants.BUTTON_PRESS.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON_PRESS.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (maxScroll.invoke(this@DiscreteScrollBarPanel) <= 0) { } else if (maxScroll.invoke(this@DiscreteScrollBarPanel) <= 0) {
ScrollBarConstants.BUTTON_DISABLED.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON_DISABLED.render(graphics, canvasWidth = width, canvasHeight = height)
} else if (isHovered) { } else if (isHovered) {
ScrollBarConstants.BUTTON_HOVER.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON_HOVER.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
ScrollBarConstants.BUTTON.render(graphics, width = width, height = height) ScrollBarConstants.BUTTON.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} }
} }
@ -96,11 +96,11 @@ open class DiscreteScrollBarPanel<out S : Screen>(
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (width == ScrollBarConstants.SLIM_WIDTH) { if (width == ScrollBarConstants.SLIM_WIDTH) {
ScrollBarConstants.SLIM_BODY.render(graphics, y = 2f, height = height - 4f) ScrollBarConstants.SLIM_BODY.render(graphics, y = 2f, canvasHeight = height - 4f)
ScrollBarConstants.SLIM_TOP.render(graphics) ScrollBarConstants.SLIM_TOP.render(graphics)
ScrollBarConstants.SLIM_BOTTOM.render(graphics, y = height - 2f) ScrollBarConstants.SLIM_BOTTOM.render(graphics, y = height - 2f)
} else { } else {
ScrollBarConstants.BODY.render(graphics, y = 2f, height = height - 4f) ScrollBarConstants.BODY.render(graphics, y = 2f, canvasHeight = height - 4f)
ScrollBarConstants.TOP.render(graphics) ScrollBarConstants.TOP.render(graphics)
ScrollBarConstants.BOTTOM.render(graphics, y = height - 2f) ScrollBarConstants.BOTTOM.render(graphics, y = height - 2f)
} }

View File

@ -76,8 +76,8 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
CheckBoxLabelInputPanel(this, it, menu.matchComponents, TranslatableComponent("otm.gui.filter.match_nbt")).also { it.dockTop = 4f; it.dock = Dock.TOP } CheckBoxLabelInputPanel(this, it, menu.matchComponents, TranslatableComponent("otm.gui.filter.match_nbt")).also { it.dockTop = 4f; it.dock = Dock.TOP }
}) })
frame.Tab(view, activeIcon = ItemStackIcon(ItemStack(MItems.PORTABLE_CONDENSATION_DRIVE))) frame.CustomTab(view, activeIcon = ItemStackIcon(ItemStack(MItems.PORTABLE_CONDENSATION_DRIVE)))
frame.Tab(settings, activeIcon = ItemStackIcon(ItemStack(Items.HOPPER))) frame.CustomTab(settings, activeIcon = ItemStackIcon(ItemStack(Items.HOPPER)))
return frame return frame
} }

View File

@ -2,13 +2,18 @@ package ru.dbotthepony.mc.otm.client.screen.tech
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.client.ShiftPressedCond import ru.dbotthepony.mc.otm.client.ShiftPressedCond
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.render.TextIcon
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.input.NetworkNumberInputPanel import ru.dbotthepony.mc.otm.client.screen.panels.input.NetworkNumberInputPanel
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.core.util.formatPower
import ru.dbotthepony.mc.otm.menu.tech.EnergyCounterMenu import ru.dbotthepony.mc.otm.menu.tech.EnergyCounterMenu
@ -17,19 +22,37 @@ class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title:
val frame = super.makeMainFrame()!! val frame = super.makeMainFrame()!!
frame.height = 160f frame.height = 160f
frame.width += 40f frame.width += 60f
val graphs = linkedMapOf(
menu.history5s to "5s",
menu.history15s to "15s",
menu.history1m to "1m",
menu.history1h to "1h",
menu.history6h to "6h",
menu.history24h to "24h",
)
for ((graph, text) in graphs) {
val tab = frame.Tab(activeIcon = TextIcon(color = RGBAColor.BLACK, font = font, text = TextComponent(text)))
val panel = DecimalHistoryGraphPanel(this, tab.canvas, graph, formatText = { it.formatPower(formatAsReadable = ShiftPressedCond) })
panel.dock = Dock.FILL
}
val informationTab = frame.Tab(activeIcon = Widgets18.STATISTICS_TAB)
val limitsTab = frame.Tab(activeIcon = Widgets18.SETTINGS_TAB)
val labels = ArrayList<EditablePanel<*>>() val labels = ArrayList<EditablePanel<*>>()
labels.add(Label(this, frame, text = TranslatableComponent("otm.gui.power.passed"))) labels.add(Label(this, informationTab.canvas, text = TranslatableComponent("otm.gui.power.passed")))
labels.add(DynamicLabel(this, frame, textSupplier = { menu.passed.formatPower(formatAsReadable = ShiftPressedCond) })) labels.add(DynamicLabel(this, informationTab.canvas, textSupplier = { menu.passed.formatPower(formatAsReadable = ShiftPressedCond) }))
labels.add(Label(this, frame, text = TranslatableComponent("otm.gui.power.average"))) labels.add(Label(this, informationTab.canvas, text = TranslatableComponent("otm.gui.power.average")))
labels.add(DynamicLabel(this, frame, textSupplier = { menu.average.formatPower(formatAsReadable = ShiftPressedCond) })) labels.add(DynamicLabel(this, informationTab.canvas, textSupplier = { menu.history5s.calculateAverage(20).formatPower(formatAsReadable = ShiftPressedCond) }))
labels.add(Label(this, frame, text = TranslatableComponent("otm.gui.power.last_20_ticks"))) labels.add(Label(this, informationTab.canvas, text = TranslatableComponent("otm.gui.power.last_20_ticks")))
labels.add(DynamicLabel(this, frame, textSupplier = { menu.last20Ticks.formatPower(formatAsReadable = ShiftPressedCond) })) labels.add(DynamicLabel(this, informationTab.canvas, textSupplier = { menu.history5s.calculateSum(20).formatPower(formatAsReadable = ShiftPressedCond) }))
labels.add(Label(this, frame, text = TranslatableComponent("otm.gui.power.last_tick"))) labels.add(Label(this, informationTab.canvas, text = TranslatableComponent("otm.gui.power.last_tick")))
labels.add(DynamicLabel(this, frame, textSupplier = { menu.lastTick.formatPower(formatAsReadable = ShiftPressedCond) })) labels.add(DynamicLabel(this, informationTab.canvas, textSupplier = { menu.lastTick.formatPower(formatAsReadable = ShiftPressedCond) }))
labels.add(DynamicLabel(this, frame, textSupplier = { TranslatableComponent("block.overdrive_that_matters.energy_counter.facing", menu.inputDirection) })) labels.add(DynamicLabel(this, informationTab.canvas, textSupplier = { TranslatableComponent("block.overdrive_that_matters.energy_counter.facing", menu.inputDirection) }))
for ((i, label) in labels.withIndex()) { for ((i, label) in labels.withIndex()) {
if (i == 0) { if (i == 0) {
@ -42,33 +65,21 @@ class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title:
} }
if (!menu.player.isSpectator) { if (!menu.player.isSpectator) {
val button = ButtonPanel(this, frame, 0f, 0f, 0f, 20f, TranslatableComponent("block.overdrive_that_matters.energy_counter.switch"), onPress = Runnable { menu.switchDirection.accept(null) }) val button = ButtonPanel(this, informationTab.canvas, 0f, 0f, 0f, 20f, TranslatableComponent("block.overdrive_that_matters.energy_counter.switch"), onPress = Runnable { menu.switchDirection.accept(null) })
button.dock = Dock.TOP button.dock = Dock.TOP
button.setDockMargin(4f, 5f, 4f, 0f) button.setDockMargin(4f, 5f, 4f, 0f)
} }
val infoPanels = frame.fetchChildren() Label(this, limitsTab.canvas, TranslatableComponent("block.overdrive_that_matters.energy_counter.limit")).also {
Label(this, frame, TranslatableComponent("block.overdrive_that_matters.energy_counter.limit")).also {
it.dock = Dock.TOP it.dock = Dock.TOP
it.dockTop = 10f it.dockTop = 10f
} }
NetworkNumberInputPanel(this, frame, widget = menu.maxIOInput, networkValue = menu::maxIO).also { NetworkNumberInputPanel(this, limitsTab.canvas, widget = menu.maxIOInput, networkValue = menu::maxIO).also {
it.dock = Dock.TOP it.dock = Dock.TOP
it.dockTop = 4f it.dockTop = 4f
} }
val limitsPanels = frame.fetchChildren().filter { !infoPanels.contains(it) }
val informationTab = frame.Tab()
val limitsTab = frame.Tab()
informationTab.showHidePanels(infoPanels)
limitsTab.showHidePanels(limitsPanels)
limitsTab.onClose!!.run()
makeDeviceControls(this, frame, redstoneConfig = menu.redstone) makeDeviceControls(this, frame, redstoneConfig = menu.redstone)
return frame return frame

View File

@ -2,9 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen.tech
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.enchantment.Enchantments
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.isShiftDown import ru.dbotthepony.mc.otm.client.isShiftDown
@ -59,7 +57,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
} }
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
BAR_BACKGROUND.render(graphics, width = width, height = height) BAR_BACKGROUND.render(graphics, canvasWidth = width, canvasHeight = height)
val level = getLevelFromXp(menu.experienceStored) val level = getLevelFromXp(menu.experienceStored)
val progress = (menu.experienceStored - getTotalXpRequiredForLevel(level)).toDouble() / getXpRequiredForLevelUp(level).toDouble() val progress = (menu.experienceStored - getTotalXpRequiredForLevel(level)).toDouble() / getXpRequiredForLevelUp(level).toDouble()
BAR_FOREGROUND.renderPartial(graphics, width = width * progress.toFloat(), height = height) BAR_FOREGROUND.renderPartial(graphics, width = width * progress.toFloat(), height = height)

View File

@ -105,7 +105,7 @@ open class FluidGaugePanel<out S : Screen>(
RenderSystem.depthFunc(GL11.GL_LESS) RenderSystem.depthFunc(GL11.GL_LESS)
} }
GAUGE.render(graphics, 0f, 0f, width = width, height = height) GAUGE.render(graphics, 0f, 0f, canvasWidth = width, canvasHeight = height)
} }
companion object { companion object {

View File

@ -11,21 +11,21 @@ import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
private fun PowerGaugePanel<*>.doRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float, flop: Boolean) { private fun PowerGaugePanel<*>.doRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float, flop: Boolean) {
if (height >= 18f) { if (height >= 18f) {
if (flop) { if (flop) {
HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.render(graphics, height = height, width = this.width, winding = UVWindingOrder.U1_V0_U0_V1) HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.render(graphics, canvasHeight = height, canvasWidth = this.width, winding = UVWindingOrder.U1_V0_U0_V1)
val width = this.width * widget.percentage val width = this.width * widget.percentage
HorizontalPowerGaugePanel.GAUGE_FOREGROUND_TALL.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1) HorizontalPowerGaugePanel.GAUGE_FOREGROUND_TALL.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1)
} else { } else {
HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.render(graphics, height = height, width = this.width) HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.render(graphics, canvasHeight = height, canvasWidth = this.width)
val width = this.width * widget.percentage val width = this.width * widget.percentage
HorizontalPowerGaugePanel.GAUGE_FOREGROUND_TALL.renderPartial(graphics, height = height, width = width) HorizontalPowerGaugePanel.GAUGE_FOREGROUND_TALL.renderPartial(graphics, height = height, width = width)
} }
} else { } else {
if (flop) { if (flop) {
HorizontalPowerGaugePanel.GAUGE_BACKGROUND.render(graphics, height = height, width = this.width, winding = UVWindingOrder.U1_V0_U0_V1) HorizontalPowerGaugePanel.GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width, winding = UVWindingOrder.U1_V0_U0_V1)
val width = this.width * widget.percentage val width = this.width * widget.percentage
HorizontalPowerGaugePanel.GAUGE_FOREGROUND.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1) HorizontalPowerGaugePanel.GAUGE_FOREGROUND.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1)
} else { } else {
HorizontalPowerGaugePanel.GAUGE_BACKGROUND.render(graphics, height = height, width = this.width) HorizontalPowerGaugePanel.GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width)
val width = this.width * widget.percentage val width = this.width * widget.percentage
HorizontalPowerGaugePanel.GAUGE_FOREGROUND.renderPartial(graphics, height = height, width = width) HorizontalPowerGaugePanel.GAUGE_FOREGROUND.renderPartial(graphics, height = height, width = width)
} }

View File

@ -1,22 +1,13 @@
package ru.dbotthepony.mc.otm.client.screen.widget package ru.dbotthepony.mc.otm.client.screen.widget
import it.unimi.dsi.fastutil.ints.IntArrayList
import net.minecraft.ChatFormatting
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 ru.dbotthepony.kommons.util.value
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
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.client.isShiftDown
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.render.* import ru.dbotthepony.mc.otm.client.render.*
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel 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.formatHistory
import ru.dbotthepony.mc.otm.core.util.formatPower
import ru.dbotthepony.mc.otm.core.util.formatPowerLevel import ru.dbotthepony.mc.otm.core.util.formatPowerLevel
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
@ -45,7 +36,7 @@ open class PowerGaugePanel<out S : Screen>(
val height = this.height * widget.percentage val height = this.height * widget.percentage
if (width >= 18f) { if (width >= 18f) {
GAUGE_BACKGROUND_WIDE.render(graphics, width = width, height = this.height) GAUGE_BACKGROUND_WIDE.render(graphics, canvasWidth = width, canvasHeight = this.height)
GAUGE_FOREGROUND_WIDE.renderPartial( GAUGE_FOREGROUND_WIDE.renderPartial(
graphics, graphics,
y = this.height - height, y = this.height - height,
@ -53,7 +44,7 @@ open class PowerGaugePanel<out S : Screen>(
width = width, width = width,
winding = UVWindingOrder.U0_V1_U1_V0) winding = UVWindingOrder.U0_V1_U1_V0)
} else { } else {
GAUGE_BACKGROUND.render(graphics, width = width, height = this.height) GAUGE_BACKGROUND.render(graphics, canvasWidth = width, canvasHeight = this.height)
GAUGE_FOREGROUND.renderPartial( GAUGE_FOREGROUND.renderPartial(
graphics, graphics,
y = this.height - height, y = this.height - height,

View File

@ -14,7 +14,6 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.AbstractButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.AbstractButtonPanel
import ru.dbotthepony.mc.otm.compat.jei.JEIPlugin import ru.dbotthepony.mc.otm.compat.jei.JEIPlugin
import ru.dbotthepony.mc.otm.compat.jei.isJeiLoaded import ru.dbotthepony.mc.otm.compat.jei.isJeiLoaded
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.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import java.util.function.Supplier import java.util.function.Supplier
@ -63,11 +62,11 @@ open class ProgressGaugePanel<out S : Screen>(
} }
if (flop) { if (flop) {
GAUGE_BACKGROUND.render(graphics, height = height, width = this.width, winding = UVWindingOrder.U1_V0_U0_V1) GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width, winding = UVWindingOrder.U1_V0_U0_V1)
val width = (this.width * widget.percentage).roundToInt().toFloat() val width = (this.width * widget.percentage).roundToInt().toFloat()
GAUGE_FOREGROUND.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1) GAUGE_FOREGROUND.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1)
} else { } else {
GAUGE_BACKGROUND.render(graphics, height = height, width = this.width) GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width)
val width = (this.width * widget.percentage).roundToInt().toFloat() val width = (this.width * widget.percentage).roundToInt().toFloat()
GAUGE_FOREGROUND.renderPartial(graphics, height = height, width = width) GAUGE_FOREGROUND.renderPartial(graphics, height = height, width = width)
} }

View File

@ -182,9 +182,9 @@ class CosmeticToggleButton<out S : Screen>(
val color = if (isHovered) RGBAColor.WHITE else RGBAColor.HALF_TRANSPARENT val color = if (isHovered) RGBAColor.WHITE else RGBAColor.HALF_TRANSPARENT
if (inv.isSkinArmor(index)) { if (inv.isSkinArmor(index)) {
BUTTON_ACTIVE.render(graphics, width = width, height = height, color = color) BUTTON_ACTIVE.render(graphics, canvasWidth = width, canvasHeight = height, color = color)
} else { } else {
BUTTON_INACTIVE.render(graphics, width = width, height = height, color = color) BUTTON_INACTIVE.render(graphics, canvasWidth = width, canvasHeight = height, color = color)
} }
} }
@ -219,9 +219,9 @@ class CosmeticToggleRenderButton<out S : Screen>(
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
if (PlayerRenderHandler.Disabled) { if (PlayerRenderHandler.Disabled) {
BUTTON_ACTIVE.render(graphics, width = width, height = height) BUTTON_ACTIVE.render(graphics, canvasWidth = width, canvasHeight = height)
} else { } else {
BUTTON_INACTIVE.render(graphics, width = width, height = height) BUTTON_INACTIVE.render(graphics, canvasWidth = width, canvasHeight = height)
} }
} }
} }

View File

@ -12,7 +12,6 @@ import net.neoforged.fml.ModList
import net.neoforged.fml.loading.FMLEnvironment import net.neoforged.fml.loading.FMLEnvironment
import net.neoforged.neoforge.network.PacketDistributor import net.neoforged.neoforge.network.PacketDistributor
import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.sprites.MatterySprite import ru.dbotthepony.mc.otm.client.render.sprites.MatterySprite
@ -217,9 +216,9 @@ class CurioToggleButton<out S : Screen>(
val color = if (isHovered) RGBAColor.WHITE else RGBAColor.HALF_TRANSPARENT val color = if (isHovered) RGBAColor.WHITE else RGBAColor.HALF_TRANSPARENT
if ((slot as CurioSlot).getRenderStatus()) { if ((slot as CurioSlot).getRenderStatus()) {
BUTTON_ACTIVE.render(graphics, width = width, height = height, color = color) BUTTON_ACTIVE.render(graphics, canvasWidth = width, canvasHeight = height, color = color)
} else { } else {
BUTTON_INACTIVE.render(graphics, width = width, height = height, color = color) BUTTON_INACTIVE.render(graphics, canvasWidth = width, canvasHeight = height, color = color)
} }
} }

View File

@ -22,7 +22,7 @@ abstract class AbstractHistoryGraph<V : Any>(
/** /**
* Limit on how many graph values to store * Limit on how many graph values to store
*/ */
val width: Int = 100, val width: Int,
) : Iterable<V>, INBTSerializable<CompoundTag>, ISynchable { ) : Iterable<V>, INBTSerializable<CompoundTag>, ISynchable {
constructor(ticks: Int) : this(1, ticks) constructor(ticks: Int) : this(1, ticks)
@ -36,8 +36,27 @@ abstract class AbstractHistoryGraph<V : Any>(
protected abstract fun calculateAverage(input: List<V>): V protected abstract fun calculateAverage(input: List<V>): V
protected abstract fun sum(a: V, b: V): V protected abstract fun sum(a: V, b: V): V
protected abstract fun sum(input: List<V>): V
protected abstract fun identity(): V protected abstract fun identity(): V
fun calculateAverage(width: Int = this.width): V {
require(width >= 0) { "Invalid time frame: $width" }
if (width == 0 || this.values.isEmpty())
return identity()
return calculateAverage(this.values.subList(0, width.coerceAtMost(this.values.size)))
}
fun calculateSum(width: Int = this.width): V {
require(width >= 0) { "Invalid time frame: $width" }
if (width == 0 || this.values.isEmpty())
return identity()
return sum(this.values.subList(0, width.coerceAtMost(this.values.size)))
}
abstract val codec: Codec<V> abstract val codec: Codec<V>
abstract val streamCodec: MatteryStreamCodec<RegistryFriendlyByteBuf, V> abstract val streamCodec: MatteryStreamCodec<RegistryFriendlyByteBuf, V>
@ -48,7 +67,7 @@ abstract class AbstractHistoryGraph<V : Any>(
remotes.add(this) remotes.add(this)
} }
private var shouldFullyNetwork = false private var shouldFullyNetwork = true
private val networkValues = ArrayList<V>() private val networkValues = ArrayList<V>()
override fun write(stream: RegistryFriendlyByteBuf) { override fun write(stream: RegistryFriendlyByteBuf) {
@ -117,10 +136,6 @@ abstract class AbstractHistoryGraph<V : Any>(
private val accumulator = ArrayList<V>(this.resolution) private val accumulator = ArrayList<V>(this.resolution)
private val values = ArrayDeque<V>() private val values = ArrayDeque<V>()
init {
values.fill(identity())
}
/** /**
* Calculates sum of values provided by calls to [add] and writes it to graph history or graph value accumulator * Calculates sum of values provided by calls to [add] and writes it to graph history or graph value accumulator
*/ */

View File

@ -7,7 +7,6 @@ import ru.dbotthepony.mc.otm.core.collect.reduce
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.data.DecimalCodec import ru.dbotthepony.mc.otm.data.DecimalCodec
import ru.dbotthepony.mc.otm.network.MatteryStreamCodec import ru.dbotthepony.mc.otm.network.MatteryStreamCodec
import kotlin.math.pow
class DecimalHistoryGraph : AbstractHistoryGraph<Decimal> { class DecimalHistoryGraph : AbstractHistoryGraph<Decimal> {
constructor(resolution: Int, width: Int) : super(resolution, width) constructor(resolution: Int, width: Int) : super(resolution, width)
@ -17,6 +16,10 @@ class DecimalHistoryGraph : AbstractHistoryGraph<Decimal> {
return input.iterator().reduce(Decimal.ZERO, Decimal::plus) / Decimal(input.size) return input.iterator().reduce(Decimal.ZERO, Decimal::plus) / Decimal(input.size)
} }
override fun sum(input: List<Decimal>): Decimal {
return input.iterator().reduce(Decimal.ZERO, Decimal::plus)
}
override fun sum(a: Decimal, b: Decimal): Decimal { override fun sum(a: Decimal, b: Decimal): Decimal {
return a + b return a + b
} }

View File

@ -9,6 +9,7 @@ import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity
import ru.dbotthepony.mc.otm.core.DecimalHistoryGraph
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.toDecimal import ru.dbotthepony.mc.otm.core.math.toDecimal
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
@ -22,11 +23,27 @@ class EnergyCounterMenu(
tile: EnergyCounterBlockEntity? = null tile: EnergyCounterBlockEntity? = null
) : MatteryMenu(MMenus.ENERGY_COUNTER, p_38852_, inventory, tile) { ) : MatteryMenu(MMenus.ENERGY_COUNTER, p_38852_, inventory, tile) {
var passed by mSynchronizer.decimal() var passed by mSynchronizer.decimal()
var average by mSynchronizer.decimal()
var last20Ticks by mSynchronizer.decimal()
var lastTick by mSynchronizer.decimal() var lastTick by mSynchronizer.decimal()
var maxIO by mSynchronizer.decimal() var maxIO by mSynchronizer.decimal()
val history5s = tile?.history5s ?: DecimalHistoryGraph(1, 100)
val history15s = tile?.history15s ?: DecimalHistoryGraph(3, 100)
val history1m = tile?.history1m ?: DecimalHistoryGraph(12, 100)
val history10m = tile?.history10m ?: DecimalHistoryGraph(120, 100)
val history1h = tile?.history1h ?: DecimalHistoryGraph(720, 100)
val history6h = tile?.history6h ?: DecimalHistoryGraph(720 * 6, 100)
val history24h = tile?.history24h ?: DecimalHistoryGraph(720 * 24, 100)
init {
mSynchronizer.add(history5s)
mSynchronizer.add(history15s)
mSynchronizer.add(history1m)
mSynchronizer.add(history10m)
mSynchronizer.add(history1h)
mSynchronizer.add(history6h)
mSynchronizer.add(history24h)
}
val switchDirection = oneWayInput { val switchDirection = oneWayInput {
if (tile is EnergyCounterBlockEntity) if (tile is EnergyCounterBlockEntity)
tile.level?.setBlock(tile.blockPos, tile.blockState.setValue(EnergyCounterBlock.INPUT_DIRECTION, tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION).opposite), Block.UPDATE_ALL) tile.level?.setBlock(tile.blockPos, tile.blockState.setValue(EnergyCounterBlock.INPUT_DIRECTION, tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION).opposite), Block.UPDATE_ALL)
@ -52,22 +69,12 @@ class EnergyCounterMenu(
} }
} }
// TODO: Graph and proper networking for it
private var ticksPassed = 0
override fun beforeBroadcast() { override fun beforeBroadcast() {
super.beforeBroadcast() super.beforeBroadcast()
if (tile is EnergyCounterBlockEntity) { if (tile is EnergyCounterBlockEntity) {
passed = tile.passed passed = tile.passed
average = tile.calcAverage(20)
lastTick = tile.lastTick lastTick = tile.lastTick
if (ticksPassed == 0) {
last20Ticks = tile.sumHistory(20)
}
ticksPassed = (ticksPassed + 1) % 20
inputDirection = tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION) inputDirection = tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION)
maxIO = tile.ioLimit?.toDecimal() ?: -Decimal.ONE maxIO = tile.ioLimit?.toDecimal() ?: -Decimal.ONE

Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 B

After

Width:  |  Height:  |  Size: 951 B