Profiled energy storage!
This commit is contained in:
parent
8c32a2cd7a
commit
8afa21ae16
@ -264,6 +264,7 @@ private fun misc(provider: MatteryLanguageProvider) {
|
||||
|
||||
gui("power.percentage_level", "Energy level: %s%%")
|
||||
gui("level", "%s / %s")
|
||||
gui("diff", "%s (%s / %s)")
|
||||
gui("power.name", "MtJ")
|
||||
gui("fluid.name", "B")
|
||||
gui("fluid.level", "%s / %s of %s")
|
||||
|
@ -270,7 +270,6 @@ private fun misc(provider: MatteryLanguageProvider) {
|
||||
misc("pill.message_finish", "§kОДИН ИЗ НАС ОДИН ИЗ НАС ОДИН ИЗ НАС ОДИН ИЗ НАС ОДИН ИЗ НАС")
|
||||
|
||||
gui("power.percentage_level", "Уровень энергии: %s%%")
|
||||
gui("level", "%s / %s")
|
||||
gui("power.name", "МтДж")
|
||||
gui("fluid.name", "В")
|
||||
gui("fluid.level", "%s / %s с %s")
|
||||
|
@ -15,6 +15,7 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||
import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
@ -39,7 +40,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
||||
val residueItemHandler = residueContainer.handler(HandlerFilter.OnlyOut)
|
||||
val fuelItemHandler = fuelContainer.handler(HandlerFilter.ChemicalFuel)
|
||||
|
||||
val energy = GeneratorEnergyStorage(::setChangedLight, CAPACITY, THROUGHPUT)
|
||||
val energy = ProfiledEnergyStorage(GeneratorEnergyStorage(::setChangedLight, CAPACITY, THROUGHPUT))
|
||||
|
||||
val itemConfig = ConfigurableItemHandler(
|
||||
input = fuelItemHandler,
|
||||
@ -77,6 +78,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
energy.tick()
|
||||
|
||||
if (workTicks > 0) {
|
||||
workTicks--
|
||||
|
@ -0,0 +1,169 @@
|
||||
package ru.dbotthepony.mc.otm.capability.energy
|
||||
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.NumericTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.set
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.ITickable
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class ProfiledEnergyStorage<E : IMatteryEnergyStorage>(val parent: E) : IMatteryEnergyStorage, ITickable, INBTSerializable<CompoundTag?> {
|
||||
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return recordTransfer(parent.extractEnergy(howMuch, simulate), simulate)
|
||||
}
|
||||
|
||||
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return recordReceive(parent.receiveEnergy(howMuch, simulate), simulate)
|
||||
}
|
||||
|
||||
override fun extractEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return recordTransfer(parent.extractEnergyChecked(howMuch, simulate), simulate)
|
||||
}
|
||||
|
||||
override fun receiveEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return recordReceive(parent.receiveEnergyChecked(howMuch, simulate), simulate)
|
||||
}
|
||||
|
||||
override val canSetBatteryLevel: Boolean get() = parent.canSetBatteryLevel
|
||||
override val missingPower: Decimal get() = parent.missingPower
|
||||
|
||||
override fun drainBattery(): Boolean {
|
||||
return parent.drainBattery()
|
||||
}
|
||||
|
||||
override fun fillBattery(): Boolean {
|
||||
return parent.fillBattery()
|
||||
}
|
||||
|
||||
override var batteryLevel: Decimal
|
||||
get() = parent.batteryLevel
|
||||
set(value) { parent.batteryLevel = value }
|
||||
override val maxBatteryLevel: Decimal get() = parent.maxBatteryLevel
|
||||
override val energyFlow: FlowDirection get() = parent.energyFlow
|
||||
|
||||
var lastTickReceive = Decimal.ZERO
|
||||
private set
|
||||
|
||||
var lastTickTransfer = Decimal.ZERO
|
||||
private set
|
||||
|
||||
var tick = 0
|
||||
private set
|
||||
|
||||
private val historyReceiveInternal = ArrayList<Decimal>()
|
||||
private val historyTransferInternal = ArrayList<Decimal>()
|
||||
|
||||
val historyReceive: List<Decimal> = Collections.unmodifiableList(historyReceiveInternal)
|
||||
val historyTransfer: List<Decimal> = Collections.unmodifiableList(historyTransferInternal)
|
||||
|
||||
init {
|
||||
for (i in 0 until HISTORY_SIZE) {
|
||||
historyReceiveInternal.add(Decimal.ZERO)
|
||||
historyTransferInternal.add(Decimal.ZERO)
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordTransfer(value: Decimal, simulate: Boolean): Decimal {
|
||||
if (!simulate) {
|
||||
lastTickTransfer += value
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
private fun recordReceive(value: Decimal, simulate: Boolean): Decimal {
|
||||
if (!simulate) {
|
||||
lastTickReceive += value
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
tick = (tick + 1) % HISTORY_SIZE
|
||||
historyReceiveInternal[tick] = lastTickReceive
|
||||
historyTransferInternal[tick] = lastTickTransfer
|
||||
|
||||
lastTickReceive = Decimal.ZERO
|
||||
lastTickTransfer = Decimal.ZERO
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
val tag: CompoundTag
|
||||
|
||||
if (parent is INBTSerializable<*>) {
|
||||
tag = (parent as INBTSerializable<CompoundTag?>).serializeNBT() ?: CompoundTag()
|
||||
} else {
|
||||
tag = CompoundTag()
|
||||
}
|
||||
|
||||
tag["historyReceive"] = ListTag().also {
|
||||
for (value in historyReceiveInternal) {
|
||||
it.add(value.serializeNBT())
|
||||
}
|
||||
}
|
||||
|
||||
tag["historyTransfer"] = ListTag().also {
|
||||
for (value in historyTransferInternal) {
|
||||
it.add(value.serializeNBT())
|
||||
}
|
||||
}
|
||||
|
||||
tag["historyTick"] = tick
|
||||
tag["lastTickReceive"] = lastTickReceive
|
||||
tag["lastTickTransfer"] = lastTickTransfer
|
||||
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun deserializeNBT(nbt: CompoundTag?) {
|
||||
if (parent is INBTSerializable<*>) {
|
||||
(parent as INBTSerializable<CompoundTag?>).deserializeNBT(nbt)
|
||||
}
|
||||
|
||||
if (nbt != null) {
|
||||
historyReceiveInternal.clear()
|
||||
historyTransferInternal.clear()
|
||||
|
||||
for (i in 0 until HISTORY_SIZE) {
|
||||
historyReceiveInternal.add(Decimal.ZERO)
|
||||
historyTransferInternal.add(Decimal.ZERO)
|
||||
}
|
||||
|
||||
nbt.map("historyTick") { it: NumericTag ->
|
||||
tick = it.asInt
|
||||
}
|
||||
|
||||
nbt.map("lastTickReceive") { it: Tag ->
|
||||
lastTickReceive = Decimal.deserializeNBT(it)
|
||||
}
|
||||
|
||||
nbt.map("lastTickTransfer") { it: Tag ->
|
||||
lastTickReceive = Decimal.deserializeNBT(it)
|
||||
}
|
||||
|
||||
nbt.map("historyReceive") { it: ListTag ->
|
||||
for (i in 0 until HISTORY_SIZE.coerceAtMost(it.size)) {
|
||||
historyReceiveInternal[i] = Decimal.deserializeNBT(it[i])
|
||||
}
|
||||
}
|
||||
|
||||
nbt.map("historyTransfer") { it: ListTag ->
|
||||
for (i in 0 until HISTORY_SIZE.coerceAtMost(it.size)) {
|
||||
historyTransferInternal[i] = Decimal.deserializeNBT(it[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HISTORY_SIZE = 20
|
||||
}
|
||||
}
|
@ -9,18 +9,17 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel
|
||||
import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu
|
||||
|
||||
class ChemicalGeneratorScreen(menu: ChemicalGeneratorMenu, inventory: Inventory, title: Component) : MatteryScreen<ChemicalGeneratorMenu>(menu, inventory, title) {
|
||||
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
||||
val frame = super.makeMainFrame()!!
|
||||
|
||||
WidePowerGaugePanel(this, frame, menu.energy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
|
||||
WideProfiledPowerGaugePanel(this, frame, menu.energy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
|
||||
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
|
||||
|
||||
val self = this
|
||||
val progress = object : ProgressGaugePanel<ChemicalGeneratorScreen>(self, frame, menu.progress, 78f, PROGRESS_ARROW_TOP) {
|
||||
val progress = object : ProgressGaugePanel<ChemicalGeneratorScreen>(this@ChemicalGeneratorScreen, frame, menu.progress, 78f, PROGRESS_ARROW_TOP) {
|
||||
override fun makeTooltip(): MutableList<Component> {
|
||||
val list = super.makeTooltip()
|
||||
|
||||
|
@ -1,16 +1,26 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.widget
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.network.chat.Component
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
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.client.render.*
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.stream
|
||||
import ru.dbotthepony.mc.otm.core.util.formatPower
|
||||
import ru.dbotthepony.mc.otm.core.util.formatPowerLevel
|
||||
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
||||
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget
|
||||
|
||||
open class PowerGaugePanel<out S : Screen> @JvmOverloads constructor(
|
||||
open class PowerGaugePanel<out S : Screen>(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val widget: LevelGaugeWidget,
|
||||
@ -73,6 +83,7 @@ open class PowerGaugePanel<out S : Screen> @JvmOverloads constructor(
|
||||
/**
|
||||
* Shortcut to [PowerGaugePanel] with doubled width
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
fun <S : Screen> WidePowerGaugePanel(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
@ -82,3 +93,78 @@ fun <S : Screen> WidePowerGaugePanel(
|
||||
width: Float = 18f,
|
||||
height: Float = 48f
|
||||
) = PowerGaugePanel(screen, parent, widget, x, y, width, height)
|
||||
|
||||
private fun formatLevel(a: Decimal, b: Decimal): Component {
|
||||
val diff = a - b
|
||||
|
||||
val fa = a.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN)
|
||||
val fb = b.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED)
|
||||
|
||||
if (diff.isZero) {
|
||||
return TranslatableComponent("otm.gui.diff", diff.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.GRAY), fa, fb)
|
||||
} else if (diff.isPositive) {
|
||||
return TranslatableComponent("otm.gui.diff", diff.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN), fa, fb)
|
||||
} else {
|
||||
return TranslatableComponent("otm.gui.diff", (-diff).formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED), fa, fb)
|
||||
}
|
||||
}
|
||||
|
||||
open class ProfiledPowerGaugePanel<out S : Screen>(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val profiledWidget: ProfiledEnergyGaugeWidget,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
width: Float = GAUGE_BACKGROUND.width,
|
||||
height: Float = GAUGE_BACKGROUND.height
|
||||
) : PowerGaugePanel<S>(screen, parent, profiledWidget.gauge, x, y, width, height) {
|
||||
override fun makeTooltip(): MutableList<Component> {
|
||||
return super.makeTooltip().also {
|
||||
it.add(TextComponent(""))
|
||||
|
||||
if (minecraft.window.isShiftDown) {
|
||||
it.add(formatLevel(profiledWidget.lastTickReceive, profiledWidget.lastTickTransfer))
|
||||
it.add(TextComponent("---"))
|
||||
}
|
||||
|
||||
it.add(formatLevel(
|
||||
profiledWidget.historyReceive
|
||||
.stream()
|
||||
.map { it.value }
|
||||
.reduce(Decimal.ZERO) { a, b -> a + b }
|
||||
.div(profiledWidget.historyReceive.size),
|
||||
|
||||
profiledWidget.historyTransfer.stream()
|
||||
.map { it.value }
|
||||
.reduce(Decimal.ZERO) { a, b -> a + b }
|
||||
.div(profiledWidget.historyReceive.size),
|
||||
))
|
||||
|
||||
if (minecraft.window.isShiftDown && minecraft.options.advancedItemTooltips) {
|
||||
it.add(TextComponent("---"))
|
||||
val values = IntArrayList()
|
||||
|
||||
values.addAll(profiledWidget.tick downTo 0)
|
||||
values.addAll(ProfiledEnergyStorage.HISTORY_SIZE - 1 downTo profiledWidget.tick + 1)
|
||||
|
||||
for (i in values.intIterator()) {
|
||||
it.add(formatLevel(profiledWidget.historyReceive[i].value, profiledWidget.historyTransfer[i].value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to [ProfiledPowerGaugePanel] with doubled width
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
fun <S : Screen> WideProfiledPowerGaugePanel(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
widget: ProfiledEnergyGaugeWidget,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
width: Float = 18f,
|
||||
height: Float = 48f
|
||||
) = ProfiledPowerGaugePanel(screen, parent, widget, x, y, width, height)
|
||||
|
@ -14,6 +14,7 @@ import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
|
||||
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
|
||||
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
||||
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget
|
||||
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
|
||||
import ru.dbotthepony.mc.otm.registry.MMenus
|
||||
|
||||
@ -53,7 +54,7 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t
|
||||
}
|
||||
|
||||
val progress = ProgressGaugeWidget(this)
|
||||
val energy = LevelGaugeWidget(this, tile?.energy)
|
||||
val energy = ProfiledEnergyGaugeWidget(this, tile?.energy)
|
||||
var burnTime by mSynchronizer.int().property
|
||||
|
||||
init {
|
||||
|
@ -0,0 +1,44 @@
|
||||
package ru.dbotthepony.mc.otm.menu.widget
|
||||
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
|
||||
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
|
||||
|
||||
class ProfiledEnergyGaugeWidget(synchronizer: FieldSynchronizer, val gauge: LevelGaugeWidget = LevelGaugeWidget(synchronizer)) {
|
||||
var parent: ProfiledEnergyStorage<*>? = null
|
||||
private set
|
||||
|
||||
val historyReceive = immutableList(ProfiledEnergyStorage.HISTORY_SIZE) {
|
||||
synchronizer.ComputedField({ parent?.historyReceive?.get(it) ?: Decimal.ZERO }, DecimalValueCodec)
|
||||
}
|
||||
|
||||
val historyTransfer = immutableList(ProfiledEnergyStorage.HISTORY_SIZE) {
|
||||
synchronizer.ComputedField({ parent?.historyTransfer?.get(it) ?: Decimal.ZERO }, DecimalValueCodec)
|
||||
}
|
||||
|
||||
val tick by synchronizer.ComputedIntField({ parent?.tick ?: 0 }).property
|
||||
val lastTickReceive by synchronizer.ComputedField({ parent?.lastTickReceive ?: Decimal.ZERO }, DecimalValueCodec)
|
||||
val lastTickTransfer by synchronizer.ComputedField({ parent?.lastTickTransfer ?: Decimal.ZERO }, DecimalValueCodec)
|
||||
|
||||
constructor(synchronizer: FieldSynchronizer, storage: ProfiledEnergyStorage<*>?, gauge: LevelGaugeWidget = LevelGaugeWidget(synchronizer)) : this(synchronizer, gauge = gauge) {
|
||||
if (storage != null) {
|
||||
with(storage)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(menu: MatteryMenu, storage: ProfiledEnergyStorage<*>?, gauge: LevelGaugeWidget = LevelGaugeWidget(menu)) : this(menu.mSynchronizer, storage, gauge = gauge)
|
||||
constructor(menu: MatteryMenu, gauge: LevelGaugeWidget = LevelGaugeWidget(menu)) : this(menu.mSynchronizer, gauge = gauge)
|
||||
|
||||
constructor(menu: MatteryPoweredMenu, storage: ProfiledEnergyStorage<*>?) : this(menu.mSynchronizer, storage, menu.powerWidget)
|
||||
constructor(menu: MatteryPoweredMenu) : this(menu.mSynchronizer, menu.powerWidget)
|
||||
|
||||
fun with(storage: ProfiledEnergyStorage<*>): ProfiledEnergyGaugeWidget {
|
||||
gauge.with(storage)
|
||||
parent = storage
|
||||
return this
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user