Update matter interface to match energy one, add profiled matter storage

Add weighted average to profiled storage to make "transferred last second" display less stiff
This commit is contained in:
DBotThePony 2023-06-10 20:18:21 +07:00
parent 0db20bc389
commit 87e2c8d1d8
Signed by: DBot
GPG Key ID: DCC23B5715498507
34 changed files with 495 additions and 306 deletions

View File

@ -15,6 +15,7 @@ import net.minecraftforge.event.server.ServerStoppedEvent
import net.minecraftforge.event.server.ServerStoppingEvent import net.minecraftforge.event.server.ServerStoppingEvent
import net.minecraftforge.fml.loading.FMLLoader import net.minecraftforge.fml.loading.FMLLoader
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
@ -149,7 +150,7 @@ fun onServerTick(event: ServerTickEvent) {
postServerTick.tick() postServerTick.tick()
// чтоб не плодить кучу подписчиков, вызовем напрямую отсюда // чтоб не плодить кучу подписчиков, вызовем напрямую отсюда
Abstract6Graph.tick() Abstract6Graph.tick()
ProfiledEnergyStorage.onServerPostTick() AbstractProfiledStorage.onServerPostTick()
} }
} }

View File

@ -21,6 +21,7 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
@ -99,11 +100,11 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
}) })
val matter: MatterStorageImpl = object : MatterStorageImpl(this::setChangedLight, FlowDirection.BI_DIRECTIONAL, ::CAPACITY) { val matter: ProfiledMatterStorage<MatterStorageImpl> = ProfiledMatterStorage(object : MatterStorageImpl(this::setChangedLight, FlowDirection.BI_DIRECTIONAL, ::CAPACITY) {
override val matterFlow: FlowDirection get() { override val matterFlow: FlowDirection get() {
return if (this@MatterBottlerBlockEntity.isBottling) FlowDirection.INPUT else FlowDirection.OUTPUT return if (this@MatterBottlerBlockEntity.isBottling) FlowDirection.INPUT else FlowDirection.OUTPUT
} }
} })
val matterNode = SimpleMatterNode(matter = matter) val matterNode = SimpleMatterNode(matter = matter)
@ -232,7 +233,7 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
energy.extractEnergy(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE, false) energy.extractEnergy(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE, false)
capability.receiveMatter(matter, false) capability.receiveMatter(matter, false)
this.matter.extractMatterInner(matter, false) this.matter.extractMatter(matter, false)
if (capability.missingMatter.isZero) { if (capability.missingMatter.isZero) {
for (i in 3..5) { for (i in 3..5) {
@ -256,7 +257,7 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
this.energy.extractEnergy(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE,false) this.energy.extractEnergy(ENERGY_CONSUMPTION * matter / MATTER_EXCHANGE_RATE,false)
capability.extractMatter(matter, false) capability.extractMatter(matter, false)
this.matter.receiveMatterInner(matter, false) this.matter.receiveMatter(matter, false)
if (capability.storedMatter.isZero) { if (capability.storedMatter.isZero) {
for (i in 2 downTo 0) { for (i in 2 downTo 0) {
@ -275,9 +276,9 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
if (!isBottling && !matter.storedMatter.isZero && graph != null) { if (!isBottling && !matter.storedMatter.isZero && graph != null) {
val diff = matter.extractMatterInner(matter.storedMatter, true) val diff = matter.extractMatter(matter.storedMatter, true)
val diff2 = graph.receiveMatter(diff, true) val diff2 = graph.receiveMatter(diff, true)
matter.extractMatterInner(diff2, false) matter.extractMatter(diff2, false)
graph.receiveMatter(diff2, false) graph.receiveMatter(diff2, false)
} }
} }

View File

@ -70,7 +70,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
for (stack in container) { for (stack in container) {
if (!stack.isEmpty) { if (!stack.isEmpty) {
stack.getCapability(MatteryCapability.MATTER).ifPresent { stack.getCapability(MatteryCapability.MATTER).ifPresent {
val diff = it.receiveMatter(howMuch, simulate) val diff = it.receiveMatterChecked(howMuch, simulate)
summ += diff summ += diff
howMuch -= diff howMuch -= diff
} }
@ -99,7 +99,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
for (stack in container) { for (stack in container) {
if (!stack.isEmpty) { if (!stack.isEmpty) {
stack.getCapability(MatteryCapability.MATTER).ifPresent { stack.getCapability(MatteryCapability.MATTER).ifPresent {
val diff = it.extractMatter(howMuch, simulate) val diff = it.extractMatterChecked(howMuch, simulate)
summ += diff summ += diff
howMuch -= diff howMuch -= diff
} }

View File

@ -16,6 +16,7 @@ import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
@ -125,7 +126,7 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::energy, ENERGY_KEY)
} }
val matter = MatterStorageImpl(::setChangedLight, FlowDirection.OUTPUT, ::CAPACITY) val matter = ProfiledMatterStorage(MatterStorageImpl(::setChangedLight, FlowDirection.OUTPUT, ::CAPACITY))
val matterNode = SimpleMatterNode(matter = matter) val matterNode = SimpleMatterNode(matter = matter)
init { init {
@ -172,7 +173,7 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
return Status.SUCCESS return Status.SUCCESS
} }
job.matterValue -= matter.receiveMatterInner(job.matterValue, false) job.matterValue -= matter.receiveMatter(job.matterValue, false)
if (job.matterValue.isPositive) { if (job.matterValue.isPositive) {
return Status.FAILURE_MATTER return Status.FAILURE_MATTER
@ -215,10 +216,10 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
val grid = matterNode.graph as MatterGraph? ?: return val grid = matterNode.graph as MatterGraph? ?: return
if (!matter.storedMatter.isZero) { if (!matter.storedMatter.isZero) {
val diff = matter.extractMatterInner(matter.storedMatter, true) val diff = matter.extractMatter(matter.storedMatter, true)
val diff2 = grid.receiveMatter(diff, true) val diff2 = grid.receiveMatter(diff, true)
matter.extractMatterInner(diff2, false) matter.extractMatter(diff2, false)
grid.receiveMatter(diff2, false) grid.receiveMatter(diff2, false)
} }
} }

View File

@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
import ru.dbotthepony.mc.otm.capability.matter.IPatternState import ru.dbotthepony.mc.otm.capability.matter.IPatternState
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
@ -54,7 +55,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
var isUnableToProcess = false var isUnableToProcess = false
private set private set
val matter = MatterStorageImpl(::setChangedLight, FlowDirection.INPUT, ::CAPACITY) val matter = ProfiledMatterStorage(MatterStorageImpl(::setChangedLight, FlowDirection.INPUT, ::CAPACITY))
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::setChangedLight, ENERGY_VALUES)) val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::setChangedLight, ENERGY_VALUES))
val matterNode = object : MatterNode() { val matterNode = object : MatterNode() {
@ -232,12 +233,12 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
if (graph != null) { if (graph != null) {
val toDrain = (matterPerTick * EXTRACT_TICKS.coerceAtMost(item.damageValue) - matter.storedMatter).coerceAtLeast(Decimal.ZERO).coerceAtMost(matter.missingMatter) val toDrain = (matterPerTick * EXTRACT_TICKS.coerceAtMost(item.damageValue) - matter.storedMatter).coerceAtLeast(Decimal.ZERO).coerceAtMost(matter.missingMatter)
matter.receiveMatterInner(graph.extractMatter(toDrain, false), false) matter.receiveMatter(graph.extractMatter(toDrain, false), false)
} }
} }
val toDrain = matterPerTick * (progressPerTick / this.progressPerTick) val toDrain = matterPerTick * (progressPerTick / this.progressPerTick)
val drain = matter.extractMatterInner(toDrain, true) val drain = matter.extractMatter(toDrain, true)
if (!drain.isPositive) { if (!drain.isPositive) {
isUnableToProcess = true isUnableToProcess = true
return return
@ -253,7 +254,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
repairProgress += progressPerTick repairProgress += progressPerTick
energy.extractEnergy(ENERGY_CONSUMPTION * (progressPerTick / this.progressPerTick), false) energy.extractEnergy(ENERGY_CONSUMPTION * (progressPerTick / this.progressPerTick), false)
matter.extractMatterInner(matterPerTick * (progressPerTick / this.progressPerTick), false) matter.extractMatter(matterPerTick * (progressPerTick / this.progressPerTick), false)
if (repairProgress >= 1.0) { if (repairProgress >= 1.0) {
item.damageValue = (item.damageValue - repairProgress.toInt()).coerceAtLeast(0) item.damageValue = (item.damageValue - repairProgress.toInt()).coerceAtLeast(0)

View File

@ -18,6 +18,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
@ -62,7 +63,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
} }
} }
val matter = MatterStorageImpl(::matterLevelUpdated, FlowDirection.OUTPUT, ::CAPACITY) val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.OUTPUT, ::CAPACITY))
val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer) val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer)
val matterNode = SimpleMatterNode(matter = matter) val matterNode = SimpleMatterNode(matter = matter)
@ -130,12 +131,12 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
if (receive.isZero) if (receive.isZero)
return Status.SUCCESS return Status.SUCCESS
val received = matter.receiveMatterInner(receive, true) val received = matter.receiveMatter(receive, true)
if (receive != received) if (receive != received)
return Status.FAILURE_MATTER return Status.FAILURE_MATTER
matter.receiveMatterInner(receive, false) matter.receiveMatter(receive, false)
job.totalMatter -= received job.totalMatter -= received
return Status.SUCCESS return Status.SUCCESS
} }
@ -147,7 +148,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
val received = graph.receiveMatter(matter.storedMatter, false) val received = graph.receiveMatter(matter.storedMatter, false)
if (!received.isZero) { if (!received.isZero) {
matter.extractMatterInner(received, false) matter.extractMatter(received, false)
} }
} }

View File

@ -20,6 +20,7 @@ import ru.dbotthepony.mc.otm.capability.matter.IPatternState
import ru.dbotthepony.mc.otm.capability.matter.IReplicationTask import ru.dbotthepony.mc.otm.capability.matter.IReplicationTask
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.capability.matter.ReplicationTask import ru.dbotthepony.mc.otm.capability.matter.ReplicationTask
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
@ -101,7 +102,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::powerLevelUpdated, ENERGY_VALUES)) val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::powerLevelUpdated, ENERGY_VALUES))
val matter = MatterStorageImpl(::matterLevelUpdated, FlowDirection.INPUT, ::MATTER_CAPACITY) val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.INPUT, ::MATTER_CAPACITY))
val container = MatteryContainer(::itemContainerUpdated, 5).also(::addDroppableContainer) val container = MatteryContainer(::itemContainerUpdated, 5).also(::addDroppableContainer)
val energyConfig = ConfigurableEnergy(energy) val energyConfig = ConfigurableEnergy(energy)
@ -217,12 +218,12 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: ReplicatorJob): Status { override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: ReplicatorJob): Status {
val drainPerTick = job.matterPerTick * ticksAdvanced val drainPerTick = job.matterPerTick * ticksAdvanced
if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) { if (matter.extractMatter(drainPerTick, true) < drainPerTick) {
// в машине недостаточно материи // в машине недостаточно материи
if (drainPerTick > matter.maxStoredMatter) { if (drainPerTick > matter.maxStoredMatter) {
// в тик требуется больше материи, чем её может хранить репликатор // в тик требуется больше материи, чем её может хранить репликатор
val toExtract = drainPerTick - matter.extractMatterInner(drainPerTick, true) val toExtract = drainPerTick - matter.extractMatter(drainPerTick, true)
val drain = matterNode.graph.extractMatter(toExtract, true) val drain = matterNode.graph.extractMatter(toExtract, true)
if (drain != toExtract) { if (drain != toExtract) {
@ -231,7 +232,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
// достаточно материи в сети + внутри машины // достаточно материи в сети + внутри машины
matter.extractMatterInner(drainPerTick, false) matter.extractMatter(drainPerTick, false)
matterNode.graph.extractMatter(drain, false) matterNode.graph.extractMatter(drain, false)
return Status.SUCCESS return Status.SUCCESS
} else { } else {
@ -250,8 +251,8 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matter.receiveMatter(drain, false) matter.receiveMatter(drain, false)
// получили материю, проверяем возможность работы // получили материю, проверяем возможность работы
if (matter.extractMatterInner(drainPerTick, true) >= drainPerTick) { if (matter.extractMatter(drainPerTick, true) >= drainPerTick) {
matter.extractMatterInner(drainPerTick, false) matter.extractMatter(drainPerTick, false)
return Status.SUCCESS return Status.SUCCESS
} else { } else {
// :( // :(
@ -261,7 +262,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
// в машине достаточно материи // в машине достаточно материи
matter.extractMatterInner(drainPerTick, false) matter.extractMatter(drainPerTick, false)
visualProgress = workProgress visualProgress = workProgress
return Status.SUCCESS return Status.SUCCESS
} }

View File

@ -0,0 +1,206 @@
package ru.dbotthepony.mc.otm.capability
import com.google.common.collect.ImmutableList
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.NumericTag
import net.minecraftforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.core.forValidRefs
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.core.nbt.set
import java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.ArrayList
abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<CompoundTag?> {
init {
storages.add(WeakReference(this))
}
private val historyReceiveInternal = ArrayList<Decimal>(HISTORY_SIZE)
private val historyTransferInternal = ArrayList<Decimal>(HISTORY_SIZE)
val historyReceive: List<Decimal> = Collections.unmodifiableList(historyReceiveInternal)
val historyTransfer: List<Decimal> = Collections.unmodifiableList(historyTransferInternal)
val lastTickReceive
get() = historyReceiveInternal[tick]
val lastTickTransfer
get() = historyTransferInternal[tick]
private var thisTickReceive = Decimal.ZERO
private var thisTickTransfer = Decimal.ZERO
var tick = 0
private set
init {
for (i in 0 until HISTORY_SIZE) {
historyReceiveInternal.add(Decimal.ZERO)
historyTransferInternal.add(Decimal.ZERO)
}
}
protected fun recordTransfer(value: Decimal, simulate: Boolean): Decimal {
if (!simulate) {
thisTickTransfer += value
}
return value
}
protected fun recordReceive(value: Decimal, simulate: Boolean): Decimal {
if (!simulate) {
thisTickReceive += value
}
return value
}
private fun tick() {
tick = (tick + 1) % HISTORY_SIZE
historyReceiveInternal[tick] = thisTickReceive
historyTransferInternal[tick] = thisTickTransfer
thisTickReceive = Decimal.ZERO
thisTickTransfer = Decimal.ZERO
}
val savedata: INBTSerializable<CompoundTag?> = object : INBTSerializable<CompoundTag?> {
override fun serializeNBT(): CompoundTag {
return CompoundTag().also { tag ->
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
}
}
override fun deserializeNBT(nbt: CompoundTag?) {
tick = 0
thisTickReceive = Decimal.ZERO
thisTickTransfer = Decimal.ZERO
for (i in 0 until HISTORY_SIZE) {
historyReceiveInternal[i] = Decimal.ZERO
historyTransferInternal[i] = Decimal.ZERO
}
nbt ?: return
nbt.map("historyTick") { it: NumericTag ->
tick = it.asInt
}
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])
}
}
}
}
override fun serializeNBT(): CompoundTag {
val tag: CompoundTag
if (parent is INBTSerializable<*>) {
tag = (parent as INBTSerializable<CompoundTag?>).serializeNBT() ?: CompoundTag()
} else {
tag = CompoundTag()
}
val tag2 = savedata.serializeNBT()!!
for (k in tag2.allKeys) {
tag[k] = tag2[k]!!
}
return tag
}
val weightedTransfer: Decimal get() {
return calcWeightedAverage(historyTransfer, tick)
}
val weightedReceive: Decimal get() {
return calcWeightedAverage(historyReceive, tick)
}
override fun deserializeNBT(nbt: CompoundTag?) {
if (parent is INBTSerializable<*>) {
(parent as INBTSerializable<CompoundTag?>).deserializeNBT(nbt)
}
savedata.deserializeNBT(nbt)
}
companion object {
const val HISTORY_SIZE = 20
private val storages = ArrayList<WeakReference<AbstractProfiledStorage<*>>>()
val HISTORY_WEIGHTERS: ImmutableList<Decimal> = ImmutableList.of(
Decimal("0.313335967"),
Decimal("0.146176397"),
Decimal("0.09357867"),
Decimal("0.068193701"),
Decimal("0.053351084"),
Decimal("0.043655993"),
Decimal("0.036847023"),
Decimal("0.031813486"),
Decimal("0.027947534"),
Decimal("0.024889161"),
Decimal("0.02241188"),
Decimal("0.020366241"),
Decimal("0.018649731"),
Decimal("0.017189744"),
Decimal("0.015933452"),
Decimal("0.014841516"),
Decimal("0.013884059"),
Decimal("0.013037985"),
Decimal("0.012285173"),
Decimal("0.011611204"),
)
fun calcWeightedAverage(inputs: List<Decimal>, pointer: Int): Decimal {
require(inputs.size == HISTORY_WEIGHTERS.size) { "Expected list of size ${HISTORY_WEIGHTERS.size}, got ${inputs.size}" }
require(pointer in 0 until HISTORY_WEIGHTERS.size) { "Invalid pointer position: $pointer" }
var result = Decimal.ZERO
var i = 0
for (i2 in pointer downTo 0)
result += inputs[i2] * HISTORY_WEIGHTERS[i++]
for (i2 in HISTORY_WEIGHTERS.size - 1 downTo pointer + 1)
result += inputs[i2] * HISTORY_WEIGHTERS[i++]
return result
}
// после раздумий, наиболее корректное место для обновления состояния профилированных
// хранилищ энергии и материи будет после всех остальных хуков на тики после тика сервера
// разумеется, такое решение может несколько снизить производительность сервера,
// но ничего страшного произойти не должно
internal fun onServerPostTick() {
storages.forValidRefs { it.tick() }
}
}
}

View File

@ -1,25 +1,10 @@
package ru.dbotthepony.mc.otm.capability.energy package ru.dbotthepony.mc.otm.capability.energy
import net.minecraft.nbt.CompoundTag import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
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.capability.FlowDirection
import ru.dbotthepony.mc.otm.core.forValidRefs
import ru.dbotthepony.mc.otm.core.math.Decimal 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 java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.ArrayList
class ProfiledEnergyStorage<E : IMatteryEnergyStorage>(val parent: E) : IMatteryEnergyStorage, INBTSerializable<CompoundTag?> {
init {
storages.add(WeakReference(this))
}
class ProfiledEnergyStorage<out E : IMatteryEnergyStorage>(parent: E) : AbstractProfiledStorage<E>(parent), IMatteryEnergyStorage {
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return recordTransfer(parent.extractEnergy(howMuch, simulate), simulate) return recordTransfer(parent.extractEnergy(howMuch, simulate), simulate)
} }
@ -53,143 +38,4 @@ class ProfiledEnergyStorage<E : IMatteryEnergyStorage>(val parent: E) : IMattery
override val maxBatteryLevel: Decimal get() = parent.maxBatteryLevel override val maxBatteryLevel: Decimal get() = parent.maxBatteryLevel
override val energyFlow: FlowDirection get() = parent.energyFlow override val energyFlow: FlowDirection get() = parent.energyFlow
private val historyReceiveInternal = ArrayList<Decimal>(HISTORY_SIZE)
private val historyTransferInternal = ArrayList<Decimal>(HISTORY_SIZE)
val historyReceive: List<Decimal> = Collections.unmodifiableList(historyReceiveInternal)
val historyTransfer: List<Decimal> = Collections.unmodifiableList(historyTransferInternal)
val lastTickReceive
get() = historyReceiveInternal[tick]
val lastTickTransfer
get() = historyTransferInternal[tick]
private var thisTickReceive = Decimal.ZERO
private var thisTickTransfer = Decimal.ZERO
var tick = 0
private set
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) {
thisTickTransfer += value
}
return value
}
private fun recordReceive(value: Decimal, simulate: Boolean): Decimal {
if (!simulate) {
thisTickReceive += value
}
return value
}
private fun tick() {
tick = (tick + 1) % HISTORY_SIZE
historyReceiveInternal[tick] = thisTickReceive
historyTransferInternal[tick] = thisTickTransfer
thisTickReceive = Decimal.ZERO
thisTickTransfer = Decimal.ZERO
}
val savedata: INBTSerializable<CompoundTag?> = object : INBTSerializable<CompoundTag?> {
override fun serializeNBT(): CompoundTag {
return CompoundTag().also { tag ->
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
}
}
override fun deserializeNBT(nbt: CompoundTag?) {
tick = 0
thisTickReceive = Decimal.ZERO
thisTickTransfer = Decimal.ZERO
for (i in 0 until HISTORY_SIZE) {
historyReceiveInternal[i] = Decimal.ZERO
historyTransferInternal[i] = Decimal.ZERO
}
nbt ?: return
nbt.map("historyTick") { it: NumericTag ->
tick = it.asInt
}
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])
}
}
}
}
override fun serializeNBT(): CompoundTag {
val tag: CompoundTag
if (parent is INBTSerializable<*>) {
tag = (parent as INBTSerializable<CompoundTag?>).serializeNBT() ?: CompoundTag()
} else {
tag = CompoundTag()
}
val tag2 = savedata.serializeNBT()!!
for (k in tag2.allKeys) {
tag[k] = tag2[k]!!
}
return tag
}
override fun deserializeNBT(nbt: CompoundTag?) {
if (parent is INBTSerializable<*>) {
(parent as INBTSerializable<CompoundTag?>).deserializeNBT(nbt)
}
savedata.deserializeNBT(nbt)
}
companion object {
const val HISTORY_SIZE = 20
private val storages = ArrayList<WeakReference<ProfiledEnergyStorage<*>>>()
// после раздумий, наиболее корректное место для обновления состояния профилированных
// хранилищ энергии будет после всех остальных хуков на тики после тика сервера
// разумеется, такое решение может несколько снизить производительность сервера,
// но ничего страшного произойти не должно
internal fun onServerPostTick() {
storages.forValidRefs { it.tick() }
}
}
} }

View File

@ -6,10 +6,13 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.orNull import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import kotlin.math.roundToInt import kotlin.math.roundToInt
/** /**
* Matter interface in Overdrive That Matters * Matter interface in Overdrive That Matters
*
* Contracts of this interface follow the ones of [IMatteryEnergyStorage]
*/ */
interface IMatterStorage { interface IMatterStorage {
/** /**
@ -37,7 +40,7 @@ interface IMatterStorage {
val maxStoredMatter: Decimal val maxStoredMatter: Decimal
/** /**
* Empties matter stored of this matter storage * Empties matter stored of this matter storage, if possible
* *
* @throws [UnsupportedOperationException] * @throws [UnsupportedOperationException]
* @see storedMatter * @see storedMatter
@ -47,7 +50,7 @@ interface IMatterStorage {
} }
/** /**
* Fully fills matter stored in this matter storage * Fully fills matter stored, if possible
* *
* @throws [UnsupportedOperationException] * @throws [UnsupportedOperationException]
* @see storedMatter * @see storedMatter
@ -57,19 +60,45 @@ interface IMatterStorage {
} }
/** /**
* Fill matter into this object * Fill matter into this object, ignoring [matterFlow]
* *
* @return matter accepted * @return matter accepted
*/ */
fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal
/** /**
* Extract matter from this matter storage * Extract matter from this matter storage, ignoring [matterFlow]
* *
* @return matter extracted * @return matter extracted
*/ */
fun extractMatter(howMuch: Decimal, simulate: Boolean): Decimal fun extractMatter(howMuch: Decimal, simulate: Boolean): Decimal
/**
* Fill matter into this object, accounting for [matterFlow]
*
* @return matter accepted
*/
fun receiveMatterChecked(howMuch: Decimal, simulate: Boolean): Decimal {
if (matterFlow.input) {
return receiveMatter(howMuch, simulate)
}
return Decimal.ZERO
}
/**
* Extract matter from this matter storage, accounting for [matterFlow]
*
* @return matter extracted
*/
fun extractMatterChecked(howMuch: Decimal, simulate: Boolean): Decimal {
if (matterFlow.output) {
return extractMatter(howMuch, simulate)
}
return Decimal.ZERO
}
/** /**
* How much matter (estimated) is missing in this matter storage. Why estimated? Because some objects can be bottomless. * How much matter (estimated) is missing in this matter storage. Why estimated? Because some objects can be bottomless.
* *

View File

@ -63,13 +63,6 @@ open class MatterStorageImpl @JvmOverloads constructor(
} }
override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal { override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal {
if (!canReceiveMatter)
return Decimal.ZERO
return receiveMatterInner(howMuch, simulate)
}
fun receiveMatterInner(howMuch: Decimal, simulate: Boolean): Decimal {
val new: Decimal val new: Decimal
if (maxReceive == null) { if (maxReceive == null) {
@ -89,13 +82,6 @@ open class MatterStorageImpl @JvmOverloads constructor(
} }
override fun extractMatter(howMuch: Decimal, simulate: Boolean): Decimal { override fun extractMatter(howMuch: Decimal, simulate: Boolean): Decimal {
if (canExtractMatter)
return Decimal.ZERO
return extractMatterInner(howMuch, simulate)
}
fun extractMatterInner(howMuch: Decimal, simulate: Boolean): Decimal {
val new: Decimal val new: Decimal
if (maxExtract == null) { if (maxExtract == null) {

View File

@ -0,0 +1,45 @@
package ru.dbotthepony.mc.otm.capability.matter
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.core.math.Decimal
class ProfiledMatterStorage<out M : IMatterStorage>(parent: M) : AbstractProfiledStorage<M>(parent), IMatterStorage {
override var storedMatter by parent::storedMatter
override val maxStoredMatter: Decimal
get() = parent.maxStoredMatter
override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal {
return recordReceive(parent.receiveMatter(howMuch, simulate), simulate)
}
override fun extractMatter(howMuch: Decimal, simulate: Boolean): Decimal {
return recordTransfer(parent.extractMatter(howMuch, simulate), simulate)
}
override fun receiveMatterChecked(howMuch: Decimal, simulate: Boolean): Decimal {
return recordReceive(parent.receiveMatterChecked(howMuch, simulate), simulate)
}
override fun extractMatterChecked(howMuch: Decimal, simulate: Boolean): Decimal {
return recordTransfer(parent.extractMatterChecked(howMuch, simulate), simulate)
}
override val matterFlow: FlowDirection
get() = parent.matterFlow
override val canSetMatterLevel: Boolean
get() = parent.canSetMatterLevel
override fun drainMatter() {
parent.drainMatter()
}
override fun fillMatter() {
parent.fillMatter()
}
override val missingMatter: Decimal
get() = parent.missingMatter
}

View File

@ -11,6 +11,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.MatterCapacitorSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.MatterCapacitorSlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu
@ -24,7 +25,7 @@ class MatterBottlerScreen(menu: MatterBottlerMenu, inventory: Inventory, title:
val frame = super.makeMainFrame()!! val frame = super.makeMainFrame()!!
val p = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) val p = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + p.width, GAUGE_TOP_WITH_SLOT) ProfiledMatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + p.width, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)

View File

@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
@ -20,7 +21,7 @@ class MatterDecomposerScreen(p_97741_: MatterDecomposerMenu, p_97742_: Inventory
val frame = super.makeMainFrame()!! val frame = super.makeMainFrame()!!
val m = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) val m = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT) ProfiledMatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)

View File

@ -13,6 +13,7 @@ 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.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.menu.matter.MatterReconstructorMenu import ru.dbotthepony.mc.otm.menu.matter.MatterReconstructorMenu
@ -22,7 +23,7 @@ class MatterReconstructorScreen(menu: MatterReconstructorMenu, inventory: Invent
val frame = super.makeMainFrame()!! val frame = super.makeMainFrame()!!
val p = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) val p = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + p.width, GAUGE_TOP_WITH_SLOT) ProfiledMatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + p.width, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)

View File

@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.menu.matter.MatterRecyclerMenu import ru.dbotthepony.mc.otm.menu.matter.MatterRecyclerMenu
@ -18,7 +19,7 @@ class MatterRecyclerScreen(menu: MatterRecyclerMenu, inventory: Inventory, title
val frame = super.makeMainFrame()!! val frame = super.makeMainFrame()!!
val m = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) val m = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matter, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT) ProfiledMatterGaugePanel(this, frame, menu.matter, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)

View File

@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.menu.matter.MatterReplicatorMenu import ru.dbotthepony.mc.otm.menu.matter.MatterReplicatorMenu
@ -19,7 +20,7 @@ class MatterReplicatorScreen(p_97741_: MatterReplicatorMenu, p_97742_: Inventory
val frame = super.makeMainFrame()!! val frame = super.makeMainFrame()!!
val m = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) val m = ProfiledPowerGaugePanel(this, frame, menu.profiledEnergy, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matter, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT) ProfiledMatterGaugePanel(this, frame, menu.matter, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)

View File

@ -1,13 +1,12 @@
package ru.dbotthepony.mc.otm.client.screen.widget package ru.dbotthepony.mc.otm.client.screen.widget
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.WidgetLocation import ru.dbotthepony.mc.otm.client.render.WidgetLocation
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
private fun PowerGaugePanel<*>.doRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float, flop: Boolean) { private fun PowerGaugePanel<*>.doRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float, flop: Boolean) {
if (height >= 18f) { if (height >= 18f) {
@ -74,7 +73,7 @@ fun <S : Screen> TallHorizontalPowerGaugePanel(
open class HorizontalProfiledPowerGaugePanel<out S : Screen>( open class HorizontalProfiledPowerGaugePanel<out S : Screen>(
screen: S, screen: S,
parent: EditablePanel<*>? = null, parent: EditablePanel<*>? = null,
widget: ProfiledEnergyGaugeWidget, widget: ProfiledLevelGaugeWidget<*>,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = HorizontalPowerGaugePanel.GAUGE_BACKGROUND.width, width: Float = HorizontalPowerGaugePanel.GAUGE_BACKGROUND.width,
@ -94,7 +93,7 @@ open class HorizontalProfiledPowerGaugePanel<out S : Screen>(
fun <S : Screen> TallHorizontalProfiledPowerGaugePanel( fun <S : Screen> TallHorizontalProfiledPowerGaugePanel(
screen: S, screen: S,
parent: EditablePanel<*>? = null, parent: EditablePanel<*>? = null,
widget: ProfiledEnergyGaugeWidget, widget: ProfiledLevelGaugeWidget<*>,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width, width: Float = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width,

View File

@ -5,18 +5,29 @@ import com.mojang.blaze3d.vertex.BufferUploader
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.ints.IntArrayList
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
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 org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
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.client.render.WidgetLocation import ru.dbotthepony.mc.otm.client.render.WidgetLocation
import ru.dbotthepony.mc.otm.client.render.tesselator import ru.dbotthepony.mc.otm.client.render.tesselator
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.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.formatMatter
import ru.dbotthepony.mc.otm.core.util.formatMatterLevel import ru.dbotthepony.mc.otm.core.util.formatMatterLevel
import ru.dbotthepony.mc.otm.core.util.formatPower
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.nanoTime import ru.dbotthepony.mc.otm.nanoTime
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.math.cos import kotlin.math.cos
@ -121,3 +132,54 @@ open class MatterGaugePanel<out S : Screen> @JvmOverloads constructor(
val GAUGE_FOREGROUND = WidgetLocation.VERTICAL_GAUGES.sprite(x = 27f, width = 9f) val GAUGE_FOREGROUND = WidgetLocation.VERTICAL_GAUGES.sprite(x = 27f, width = 9f)
} }
} }
private fun formatLevel(a: Decimal, b: Decimal): Component {
val diff = a - b
val fa = a.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN)
val fb = b.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED)
if (diff.isZero) {
return TranslatableComponent("otm.gui.diff", diff.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.GRAY), fa, fb)
} else if (diff.isPositive) {
return TranslatableComponent("otm.gui.diff", diff.formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN), fa, fb)
} else {
return TranslatableComponent("otm.gui.diff", (-diff).formatMatter(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_RED), fa, fb)
}
}
open class ProfiledMatterGaugePanel<out S : Screen>(
screen: S,
parent: EditablePanel<*>? = null,
val profiledWidget: ProfiledLevelGaugeWidget<*>,
x: Float = 0f,
y: Float = 0f
): MatterGaugePanel<S>(screen, parent, profiledWidget.gauge, x, y) {
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.weightedReceive,
profiledWidget.weightedTransfer,
))
if (minecraft.window.isShiftDown && minecraft.options.advancedItemTooltips) {
it.add(TextComponent("---"))
val values = IntArrayList()
values.addAll(profiledWidget.tick downTo 0)
values.addAll(AbstractProfiledStorage.HISTORY_SIZE - 1 downTo profiledWidget.tick + 1)
for (i in values.intIterator()) {
it.add(formatLevel(profiledWidget.historyReceive[i].value, profiledWidget.historyTransfer[i].value))
}
}
}
}
}

View File

@ -1,11 +1,11 @@
package ru.dbotthepony.mc.otm.client.screen.widget package ru.dbotthepony.mc.otm.client.screen.widget
import com.mojang.blaze3d.vertex.PoseStack
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.GuiGraphics import net.minecraft.client.gui.GuiGraphics
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.mc.otm.capability.AbstractProfiledStorage
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
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.isShiftDown
@ -19,7 +19,7 @@ import ru.dbotthepony.mc.otm.core.stream
import ru.dbotthepony.mc.otm.core.util.formatPower 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.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
open class PowerGaugePanel<out S : Screen>( open class PowerGaugePanel<out S : Screen>(
screen: S, screen: S,
@ -113,7 +113,7 @@ private fun formatLevel(a: Decimal, b: Decimal): Component {
open class ProfiledPowerGaugePanel<out S : Screen>( open class ProfiledPowerGaugePanel<out S : Screen>(
screen: S, screen: S,
parent: EditablePanel<*>? = null, parent: EditablePanel<*>? = null,
val profiledWidget: ProfiledEnergyGaugeWidget, val profiledWidget: ProfiledLevelGaugeWidget<*>,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = GAUGE_BACKGROUND.width, width: Float = GAUGE_BACKGROUND.width,
@ -129,16 +129,8 @@ open class ProfiledPowerGaugePanel<out S : Screen>(
} }
it.add(formatLevel( it.add(formatLevel(
profiledWidget.historyReceive profiledWidget.weightedReceive,
.stream() profiledWidget.weightedTransfer,
.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) { if (minecraft.window.isShiftDown && minecraft.options.advancedItemTooltips) {
@ -146,7 +138,7 @@ open class ProfiledPowerGaugePanel<out S : Screen>(
val values = IntArrayList() val values = IntArrayList()
values.addAll(profiledWidget.tick downTo 0) values.addAll(profiledWidget.tick downTo 0)
values.addAll(ProfiledEnergyStorage.HISTORY_SIZE - 1 downTo profiledWidget.tick + 1) values.addAll(AbstractProfiledStorage.HISTORY_SIZE - 1 downTo profiledWidget.tick + 1)
for (i in values.intIterator()) { for (i in values.intIterator()) {
it.add(formatLevel(profiledWidget.historyReceive[i].value, profiledWidget.historyTransfer[i].value)) it.add(formatLevel(profiledWidget.historyReceive[i].value, profiledWidget.historyTransfer[i].value))
@ -163,7 +155,7 @@ open class ProfiledPowerGaugePanel<out S : Screen>(
fun <S : Screen> WideProfiledPowerGaugePanel( fun <S : Screen> WideProfiledPowerGaugePanel(
screen: S, screen: S,
parent: EditablePanel<*>? = null, parent: EditablePanel<*>? = null,
widget: ProfiledEnergyGaugeWidget, widget: ProfiledLevelGaugeWidget<*>,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = 18f, width: Float = 18f,

View File

@ -110,7 +110,7 @@ class MatterGraph : Abstract6Graph<MatterNode, MatterGraph>(), IMatterGraphListe
val matter = node.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null) { if (matter != null) {
val value = matter.extractMatter(howMuch, simulate) val value = matter.extractMatterChecked(howMuch, simulate)
howMuch -= value howMuch -= value
extracted += value extracted += value
@ -134,7 +134,7 @@ class MatterGraph : Abstract6Graph<MatterNode, MatterGraph>(), IMatterGraphListe
val matter = node.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) { if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) {
val value = matter.receiveMatter(howMuch, simulate) val value = matter.receiveMatterChecked(howMuch, simulate)
howMuch -= value howMuch -= value
received += value received += value
@ -158,7 +158,7 @@ class MatterGraph : Abstract6Graph<MatterNode, MatterGraph>(), IMatterGraphListe
val matter = node.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null && matter.matterFlow != FlowDirection.OUTPUT) { if (matter != null && matter.matterFlow != FlowDirection.OUTPUT) {
val value = matter.receiveMatter(howMuch, simulate) val value = matter.receiveMatterChecked(howMuch, simulate)
howMuch -= value howMuch -= value
received += value received += value

View File

@ -6,6 +6,7 @@ import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.capability.matter.canExtractMatter import ru.dbotthepony.mc.otm.capability.matter.canExtractMatter
import ru.dbotthepony.mc.otm.capability.matter.canReceiveMatter import ru.dbotthepony.mc.otm.capability.matter.canReceiveMatter
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
@ -14,7 +15,7 @@ import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.core.orNull import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class MatterBottlerMenu @JvmOverloads constructor( class MatterBottlerMenu @JvmOverloads constructor(
@ -26,16 +27,15 @@ class MatterBottlerMenu @JvmOverloads constructor(
) { ) {
val workFlow = BooleanInputWithFeedback(this) val workFlow = BooleanInputWithFeedback(this)
val progressWidget = ProgressGaugeWidget(this) val progressWidget = ProgressGaugeWidget(this)
val matterWidget = LevelGaugeWidget(this) val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter))
val storageSlots: List<MatterySlot> val storageSlots: List<MatterySlot>
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
val container = tile?.container ?: SimpleContainer(6) val container = tile?.container ?: SimpleContainer(6)
if (tile != null) { if (tile != null) {
progressWidget.with(tile::getWorkProgress) progressWidget.with(tile::getWorkProgress)
matterWidget.with(tile.matter)
workFlow.with(tile::isBottling) workFlow.with(tile::isBottling)
} }

View File

@ -15,7 +15,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class MatterDecomposerMenu @JvmOverloads constructor( class MatterDecomposerMenu @JvmOverloads constructor(
@ -30,10 +30,10 @@ class MatterDecomposerMenu @JvmOverloads constructor(
val outputMain: MachineOutputSlot val outputMain: MachineOutputSlot
val outputStacking: MachineOutputSlot val outputStacking: MachineOutputSlot
val progressWidget = ProgressGaugeWidget(this, tile) val progressWidget = ProgressGaugeWidget(this, tile)
val matterWidget = LevelGaugeWidget(this, tile?.getCapability(MatteryCapability.MATTER)?.orNull()) val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter))
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
val container = tile?.outputContainer ?: SimpleContainer(2) val container = tile?.outputContainer ?: SimpleContainer(2)

View File

@ -9,7 +9,7 @@ import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
@ -18,7 +18,7 @@ class MatterReconstructorMenu(
inventory: Inventory, inventory: Inventory,
tile: MatterReconstructorBlockEntity? = null tile: MatterReconstructorBlockEntity? = null
) : MatteryPoweredMenu(MMenus.ITEM_REPAIER, containerId, inventory, tile) { ) : MatteryPoweredMenu(MMenus.ITEM_REPAIER, containerId, inventory, tile) {
val matterWidget = LevelGaugeWidget(this, tile?.matter) val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter))
val slot = object : MatterySlot(tile?.repairContainer ?: SimpleContainer(1), 0) { val slot = object : MatterySlot(tile?.repairContainer ?: SimpleContainer(1), 0) {
override fun mayPlace(itemStack: ItemStack): Boolean { override fun mayPlace(itemStack: ItemStack): Boolean {
return itemStack.isRepairable && itemStack.isDamaged && super.mayPlace(itemStack) return itemStack.isRepairable && itemStack.isDamaged && super.mayPlace(itemStack)
@ -30,7 +30,7 @@ class MatterReconstructorMenu(
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
addStorageSlot(slot) addStorageSlot(slot)

View File

@ -10,7 +10,7 @@ import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
@ -26,10 +26,10 @@ class MatterRecyclerMenu @JvmOverloads constructor(
} }
val progress = ProgressGaugeWidget(this, tile) val progress = ProgressGaugeWidget(this, tile)
val matter = LevelGaugeWidget(this, tile?.matter) val matter = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter))
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
addStorageSlot(input) addStorageSlot(input)

View File

@ -11,7 +11,7 @@ import ru.dbotthepony.mc.otm.menu.MachineOutputSlot
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class MatterReplicatorMenu @JvmOverloads constructor( class MatterReplicatorMenu @JvmOverloads constructor(
@ -19,12 +19,12 @@ class MatterReplicatorMenu @JvmOverloads constructor(
inventory: Inventory, inventory: Inventory,
tile: MatterReplicatorBlockEntity? = null tile: MatterReplicatorBlockEntity? = null
) : MatteryPoweredMenu(MMenus.MATTER_REPLICATOR, p_38852_, inventory, tile) { ) : MatteryPoweredMenu(MMenus.MATTER_REPLICATOR, p_38852_, inventory, tile) {
val matter = LevelGaugeWidget(this, tile?.matter) val matter = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter))
val progress = ProgressGaugeWidget(this, tile) val progress = ProgressGaugeWidget(this, tile)
val storageSlots: List<MachineOutputSlot> val storageSlots: List<MachineOutputSlot>
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
val container = tile?.container ?: SimpleContainer(5) val container = tile?.container ?: SimpleContainer(5)

View File

@ -13,7 +13,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class MatterScannerMenu @JvmOverloads constructor( class MatterScannerMenu @JvmOverloads constructor(
@ -26,7 +26,7 @@ class MatterScannerMenu @JvmOverloads constructor(
val patterns = LevelGaugeWidget(this) val patterns = LevelGaugeWidget(this)
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
val container = tile?.container ?: SimpleContainer(1) val container = tile?.container ?: SimpleContainer(1)

View File

@ -13,7 +13,7 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KMutableProperty0
@ -113,7 +113,7 @@ class AndroidStationMenu @JvmOverloads constructor(
val equipment = makeEquipmentSlots() val equipment = makeEquipmentSlots()
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
addInventorySlots() addInventorySlots()

View File

@ -7,16 +7,13 @@ import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.menu.BatterySlot import ru.dbotthepony.mc.otm.menu.BatterySlot
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class BatteryBankMenu @JvmOverloads constructor( class BatteryBankMenu @JvmOverloads constructor(
@ -24,7 +21,7 @@ class BatteryBankMenu @JvmOverloads constructor(
inventory: Inventory, inventory: Inventory,
tile: BatteryBankBlockEntity? = null, tile: BatteryBankBlockEntity? = null,
) : MatteryMenu(MMenus.BATTERY_BANK, p_38852_, inventory, tile) { ) : MatteryMenu(MMenus.BATTERY_BANK, p_38852_, inventory, tile) {
val powerLevel = ProfiledEnergyGaugeWidget(this, tile?.energyConfig?.capability) val powerLevel = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.capability)
val storageSlots: List<MatterySlot> val storageSlots: List<MatterySlot>
val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java) val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java)
val energyConfig = EnergyConfigPlayerInput(this, allowPull = false, allowPush = true) val energyConfig = EnergyConfigPlayerInput(this, allowPull = false, allowPush = true)

View File

@ -13,8 +13,7 @@ import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
@ -54,7 +53,7 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t
} }
val progress = ProgressGaugeWidget(this) val progress = ProgressGaugeWidget(this)
val energy = ProfiledEnergyGaugeWidget(this, tile?.energy) val energy = ProfiledLevelGaugeWidget(this, tile?.energy)
var burnTime by mSynchronizer.int().property var burnTime by mSynchronizer.int().property
init { init {

View File

@ -11,8 +11,7 @@ import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class EnergyServoMenu @JvmOverloads constructor( class EnergyServoMenu @JvmOverloads constructor(
@ -34,7 +33,7 @@ class EnergyServoMenu @JvmOverloads constructor(
val equipment = makeEquipmentSlots(mapMoveToExternal = true) val equipment = makeEquipmentSlots(mapMoveToExternal = true)
val powerGauge = ProfiledEnergyGaugeWidget(this, tile?.energy) val powerGauge = ProfiledLevelGaugeWidget(this, tile?.energy)
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig, allowPull = true, allowPush = true) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig, allowPull = true, allowPush = true)
val redstoneConfig = EnumInputWithFeedback<RedstoneSetting>(this) val redstoneConfig = EnumInputWithFeedback<RedstoneSetting>(this)

View File

@ -9,7 +9,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledEnergyGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
@ -24,7 +24,7 @@ class PlatePressMenu @JvmOverloads constructor(
val progressGauge = ProgressGaugeWidget(this, tile) val progressGauge = ProgressGaugeWidget(this, tile)
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true)
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig, allowPull = true) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig, allowPull = true)
val profiledEnergy = ProfiledEnergyGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
init { init {
addStorageSlot(inputSlot) addStorageSlot(inputSlot)

View File

@ -1,44 +0,0 @@
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.energyWidget)
constructor(menu: MatteryPoweredMenu) : this(menu.mSynchronizer, menu.energyWidget)
fun with(storage: ProfiledEnergyStorage<*>): ProfiledEnergyGaugeWidget {
gauge.with(storage)
parent = storage
return this
}
}

View File

@ -0,0 +1,62 @@
package ru.dbotthepony.mc.otm.menu.widget
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
import ru.dbotthepony.mc.otm.core.collect.SupplierList
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 ProfiledLevelGaugeWidget<P : AbstractProfiledStorage<*>>(synchronizer: FieldSynchronizer, val gauge: LevelGaugeWidget = LevelGaugeWidget(synchronizer)) {
var parent: P? = null
private set
val historyReceive = immutableList(AbstractProfiledStorage.HISTORY_SIZE) {
synchronizer.ComputedField({ parent?.historyReceive?.get(it) ?: Decimal.ZERO }, DecimalValueCodec)
}
val historyTransfer = immutableList(AbstractProfiledStorage.HISTORY_SIZE) {
synchronizer.ComputedField({ parent?.historyTransfer?.get(it) ?: Decimal.ZERO }, DecimalValueCodec)
}
val directHistoryReceive = SupplierList(historyReceive)
val directHistoryTransfer = SupplierList(historyTransfer)
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: P?, gauge: LevelGaugeWidget = LevelGaugeWidget(synchronizer)) : this(synchronizer, gauge = gauge) {
if (storage != null) {
with(storage)
}
}
constructor(menu: MatteryMenu, storage: P?, 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: P?) : this(menu.mSynchronizer, storage, menu.energyWidget)
constructor(menu: MatteryPoweredMenu) : this(menu.mSynchronizer, menu.energyWidget)
fun with(storage: P): ProfiledLevelGaugeWidget<P> {
if (storage is IMatterStorage)
gauge.with(storage)
else if (storage is IMatteryEnergyStorage)
gauge.with(storage)
parent = storage
return this
}
val weightedTransfer: Decimal get() {
return AbstractProfiledStorage.calcWeightedAverage(directHistoryTransfer, tick)
}
val weightedReceive: Decimal get() {
return AbstractProfiledStorage.calcWeightedAverage(directHistoryReceive, tick)
}
}