idling machines are now faster than ever

Rotate faaaster banan-a
This commit is contained in:
DBotThePony 2023-08-17 12:16:59 +07:00
parent a6eb0ca7f1
commit 90348d5789
Signed by: DBot
GPG Key ID: DCC23B5715498507
33 changed files with 331 additions and 116 deletions

View File

@ -54,6 +54,7 @@ import ru.dbotthepony.mc.otm.core.math.BlockRotation
import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.math.minus import ru.dbotthepony.mc.otm.core.math.minus
import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.util.IntCounter
import ru.dbotthepony.mc.otm.core.util.Savetables import ru.dbotthepony.mc.otm.core.util.Savetables
import ru.dbotthepony.mc.otm.core.util.TickList import ru.dbotthepony.mc.otm.core.util.TickList
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
@ -106,6 +107,8 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
private data class SidelessCap<T : Any>(val cap: T, var optional: LazyOptional<T>) private data class SidelessCap<T : Any>(val cap: T, var optional: LazyOptional<T>)
private val sidelessCaps = Reference2ObjectOpenHashMap<Capability<*>, SidelessCap<*>>() private val sidelessCaps = Reference2ObjectOpenHashMap<Capability<*>, SidelessCap<*>>()
protected val tickList = TickList() protected val tickList = TickList()
protected val blockStateChangesCounter = IntCounter()
protected val dirtyListeners = ISubscriptable.Impl<Unit>()
/** /**
* Shared savetables, written both to level storage and to item tag * Shared savetables, written both to level storage and to item tag
@ -484,6 +487,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
@Suppress("OVERRIDE_DEPRECATION") @Suppress("OVERRIDE_DEPRECATION")
override fun setBlockState(pBlockState: BlockState) { override fun setBlockState(pBlockState: BlockState) {
blockStateChangesCounter.increment()
val old = blockRotation val old = blockRotation
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
super.setBlockState(pBlockState) super.setBlockState(pBlockState)
@ -513,14 +517,23 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
} }
} }
override fun setChanged() {
super.setChanged()
dirtyListeners.accept(Unit)
}
// Just to mark chunk unsaved // Just to mark chunk unsaved
open fun setChangedLight() { open fun markDirtyFast() {
val level = level val level = level
if (level is ServerLevel) { if (level is ServerLevel) {
level.chunkSource.getChunkNow( level.chunkSource.getChunkNow(
SectionPos.blockToSectionCoord(blockPos.x), SectionPos.blockToSectionCoord(blockPos.x),
SectionPos.blockToSectionCoord(blockPos.z))?.isUnsaved = true SectionPos.blockToSectionCoord(blockPos.z))?.isUnsaved = true
} }
dirtyListeners.accept(Unit)
} }
val synchronizer = FieldSynchronizer { val synchronizer = FieldSynchronizer {

View File

@ -44,7 +44,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
var customDisplayName: Component? = null var customDisplayName: Component? = null
override val redstoneControl: AbstractRedstoneControl = RedstoneControl { new, old -> override val redstoneControl: AbstractRedstoneControl = RedstoneControl { new, old ->
setChangedLight() markDirtyFast()
if (new != old) if (new != old)
redstoneStatusUpdated(new, old) redstoneStatusUpdated(new, old)
@ -149,7 +149,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (access.read() != value) { if (access.read() != value) {
access.write(value) access.write(value)
setChangedLight() markDirtyFast()
if (value == FlowDirection.NONE) { if (value == FlowDirection.NONE) {
controller.close() controller.close()
@ -166,7 +166,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
var automatePull = false var automatePull = false
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
updateTickerState() updateTickerState()
} }
@ -174,7 +174,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
var automatePush = false var automatePush = false
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
updateTickerState() updateTickerState()
} }
@ -281,6 +281,11 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
val rightDefault: FlowDirection = modesRight, val rightDefault: FlowDirection = modesRight,
val topDefault: FlowDirection = modesTop, val topDefault: FlowDirection = modesTop,
val bottomDefault: FlowDirection = modesBottom, val bottomDefault: FlowDirection = modesBottom,
/**
* If battery level can update without calling [markDirtyFast]/[setChanged]
*/
val volatileEnergyValues: Boolean = false
) { ) {
constructor( constructor(
energy: T, energy: T,
@ -291,6 +296,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
rightDefault: FlowDirection = possibleModes, rightDefault: FlowDirection = possibleModes,
topDefault: FlowDirection = possibleModes, topDefault: FlowDirection = possibleModes,
bottomDefault: FlowDirection = possibleModes, bottomDefault: FlowDirection = possibleModes,
volatileEnergyValues: Boolean = false
) : this( ) : this(
energy, energy,
modesFront = possibleModes, frontDefault = frontDefault, modesFront = possibleModes, frontDefault = frontDefault,
@ -299,6 +305,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
modesRight = possibleModes, rightDefault = rightDefault, modesRight = possibleModes, rightDefault = rightDefault,
modesTop = possibleModes, topDefault = topDefault, modesTop = possibleModes, topDefault = topDefault,
modesBottom = possibleModes, bottomDefault = bottomDefault, modesBottom = possibleModes, bottomDefault = bottomDefault,
volatileEnergyValues = volatileEnergyValues,
) )
init { init {
@ -349,14 +356,18 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
private val ticker = tickList.Ticker(this) private val ticker = tickList.Ticker(this)
private fun updateTickerState() { private fun updateTickerState() {
ticker.isEnabled = (automatePull || automatePush) && energyFlow != FlowDirection.NONE && !redstoneControl.isBlockedByRedstone && neighbour.get().isPresent ticker.isEnabled = (automatePull || automatePush) &&
energyFlow != FlowDirection.NONE &&
!redstoneControl.isBlockedByRedstone &&
neighbour.get().isPresent &&
(volatileEnergyValues || energy.batteryLevel.isPositive)
} }
// var automatePull by synchronizer.bool().property // var automatePull by synchronizer.bool().property
var automatePull = false var automatePull = false
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
updateTickerState() updateTickerState()
} }
@ -364,7 +375,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
var automatePush = false var automatePush = false
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
updateTickerState() updateTickerState()
} }
@ -373,6 +384,10 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
savetables.bool(::automatePull, "energy_${side}_pull") savetables.bool(::automatePull, "energy_${side}_pull")
savetables.bool(::automatePush, "energy_${side}_push") savetables.bool(::automatePush, "energy_${side}_push")
dirtyListeners.addListener {
updateTickerState()
}
tickList.once { tickList.once {
redstoneControl.addListener { redstoneControl.addListener {
updateTickerState() updateTickerState()
@ -417,9 +432,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
} }
override fun tick() { override fun tick() {
if (energyFlow == FlowDirection.NONE || !automatePull && !automatePush || redstoneControl.isBlockedByRedstone)
return
neighbour.get().ifPresentK { neighbour.get().ifPresentK {
if (energyFlow.input && automatePull) { if (energyFlow.input && automatePull) {
moveEnergy(source = it, destination = energy, simulate = false) moveEnergy(source = it, destination = energy, simulate = false)
@ -436,7 +448,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (access.read() != value) { if (access.read() != value) {
access.write(value) access.write(value)
setChangedLight() markDirtyFast()
if (value == FlowDirection.NONE) { if (value == FlowDirection.NONE) {
for (controller in capControllers) for (controller in capControllers)
@ -604,7 +616,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (access.read() != value) { if (access.read() != value) {
access.write(value) access.write(value)
setChangedLight() markDirtyFast()
if (value == ItemHandlerMode.DISABLED) { if (value == ItemHandlerMode.DISABLED) {
capController.close() capController.close()
@ -627,7 +639,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
set(value) { set(value) {
if (field != value) { if (field != value) {
field = value field = value
setChangedLight() markDirtyFast()
if (value) { if (value) {
innerSlotPush = 0 innerSlotPush = 0
@ -642,7 +654,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
set(value) { set(value) {
if (field != value) { if (field != value) {
field = value field = value
setChangedLight() markDirtyFast()
if (value) { if (value) {
innerSlotPush = 0 innerSlotPush = 0

View File

@ -12,6 +12,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ForgeCapabilities
import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.ItemEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.energy.ItemEnergyStorageImpl
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
@ -21,8 +22,10 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.map
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) { abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) {
val batteryContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val batteryContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val batteryItemHandler = batteryContainer.handler(HandlerFilter.Dischargeable) val batteryItemHandler = batteryContainer.handler(HandlerFilter.Dischargeable)
open val energy: IMatteryEnergyStorage?
get() = null
init { init {
savetables.stateful(::batteryContainer, BATTERY_KEY) savetables.stateful(::batteryContainer, BATTERY_KEY)
@ -31,10 +34,9 @@ abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229
override fun tick() { override fun tick() {
super.tick() super.tick()
val energy = matteryEnergy if (batteryContainer.isEmpty) return
if (energy == null || batteryContainer.isEmpty)
return
val energy = energy ?: return
var demand = energy.receiveEnergy(energy.missingPower, true) var demand = energy.receiveEnergy(energy.missingPower, true)
if (demand.isZero) return if (demand.isZero) return

View File

@ -16,10 +16,10 @@ import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matteryEnergy
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.util.countingLazy
/** /**
* Simple machine, which can work on only one job type. * Simple machine, which can work on only one job type.
@ -36,7 +36,7 @@ abstract class MatteryWorkerBlockEntity<JobType : IJob>(
val jobEventLoops: ImmutableList<MachineJobEventLoop<JobType>> = immutableList(maxJobs) { id -> val jobEventLoops: ImmutableList<MachineJobEventLoop<JobType>> = immutableList(maxJobs) { id ->
object : MachineJobEventLoop<JobType>(jobCodec) { object : MachineJobEventLoop<JobType>(jobCodec) {
override val energy: IMatteryEnergyStorage? override val energy: IMatteryEnergyStorage?
get() = matteryEnergy get() = this@MatteryWorkerBlockEntity.energy
override val isBlockedByRedstone: Boolean override val isBlockedByRedstone: Boolean
get() = redstoneControl.isBlockedByRedstone get() = redstoneControl.isBlockedByRedstone
override val upgrades: IMatteryUpgrade? override val upgrades: IMatteryUpgrade?
@ -55,7 +55,7 @@ abstract class MatteryWorkerBlockEntity<JobType : IJob>(
} }
override fun onJobTick(status: JobStatus<JobType>) { override fun onJobTick(status: JobStatus<JobType>) {
super@MatteryWorkerBlockEntity.setChangedLight() super@MatteryWorkerBlockEntity.markDirtyFast()
return this@MatteryWorkerBlockEntity.onJobTick(status, id) return this@MatteryWorkerBlockEntity.onJobTick(status, id)
} }
} }
@ -105,13 +105,13 @@ abstract class MatteryWorkerBlockEntity<JobType : IJob>(
jobEventLoops.forEach { it.isIdling = false } jobEventLoops.forEach { it.isIdling = false }
} }
override fun setChangedLight() { override fun markDirtyFast() {
super.setChangedLight() super.markDirtyFast()
jobEventLoops.forEach { it.isIdling = false } jobEventLoops.forEach { it.isIdling = false }
} }
protected fun energyLevelUpdated() { protected fun energyLevelUpdated() {
super.setChangedLight() super.markDirtyFast()
jobEventLoops.forEach { it.notify(MachineJobEventLoop.IdleReason.POWER) } jobEventLoops.forEach { it.notify(MachineJobEventLoop.IdleReason.POWER) }
} }
@ -121,7 +121,7 @@ abstract class MatteryWorkerBlockEntity<JobType : IJob>(
} }
protected fun matterLevelUpdated() { protected fun matterLevelUpdated() {
super.setChangedLight() super.markDirtyFast()
jobEventLoops.forEach { it.notify(MachineJobEventLoop.IdleReason.MATTER) } jobEventLoops.forEach { it.notify(MachineJobEventLoop.IdleReason.MATTER) }
} }
@ -130,18 +130,36 @@ abstract class MatteryWorkerBlockEntity<JobType : IJob>(
jobEventLoops.forEach { it.isIdling = newBlocked } jobEventLoops.forEach { it.isIdling = newBlocked }
} }
private val hasWorkerState by countingLazy(blockStateChangesCounter) {
this.blockState.hasProperty(WorkerState.WORKER_STATE)
}
private val isWorkingState by countingLazy(blockStateChangesCounter) {
hasWorkerState && this.blockState.getValue(WorkerState.WORKER_STATE) == WorkerState.WORKING
}
private val isErrorState by countingLazy(blockStateChangesCounter) {
hasWorkerState && this.blockState.getValue(WorkerState.WORKER_STATE) == WorkerState.ERROR
}
private val isIdleState by countingLazy(blockStateChangesCounter) {
hasWorkerState && this.blockState.getValue(WorkerState.WORKER_STATE) == WorkerState.IDLE
}
override fun tick() { override fun tick() {
super.tick() super.tick()
jobEventLoops.forEach { it.think() } jobEventLoops.forEach { it.think() }
if (jobEventLoops.any { it.workingTicksAnim > 20 } && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.WORKING) { if (hasWorkerState) {
if (jobEventLoops.any { it.workingTicksAnim > 20 } && !isWorkingState) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS) level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
} else if (jobEventLoops.any { it.errorTicksAnim > 20 } && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.ERROR) { } else if (jobEventLoops.any { it.errorTicksAnim > 20 } && !isErrorState) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.ERROR), Block.UPDATE_CLIENTS) level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.ERROR), Block.UPDATE_CLIENTS)
} else if (jobEventLoops.all { it.idleTicksAnim > 20 } && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.IDLE) { } else if (jobEventLoops.all { it.idleTicksAnim > 20 } && !isIdleState) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
} }
} }
}
companion object { companion object {
private val LOGGER = LogManager.getLogger() private val LOGGER = LogManager.getLogger()

View File

@ -34,9 +34,9 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
level?.lightEngine?.checkBlock(blockPos) level?.lightEngine?.checkBlock(blockPos)
}) })
val fillInput = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val fillInput = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val drainInput = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val drainInput = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val output = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val output = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val itemConfig = ConfigurableItemHandler( val itemConfig = ConfigurableItemHandler(
input = CombinedItemHandler( input = CombinedItemHandler(
@ -75,7 +75,7 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
private fun onChanged(new: FluidStack, old: FluidStack) { private fun onChanged(new: FluidStack, old: FluidStack) {
synchronizedFluid = new.copy() synchronizedFluid = new.copy()
setChangedLight() markDirtyFast()
} }
private fun drainItem() { private fun drainItem() {

View File

@ -26,7 +26,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
return PainterMenu(containerID, inventory, this) return PainterMenu(containerID, inventory, this)
} }
val dyeInput = MatteryContainer(this::setChangedLight, 1) val dyeInput = MatteryContainer(this::markDirtyFast, 1)
private val dyeStored = EnumMap<DyeColor, Int>(DyeColor::class.java) private val dyeStored = EnumMap<DyeColor, Int>(DyeColor::class.java)
val dyeStoredView: Map<DyeColor, Int> = Collections.unmodifiableMap(dyeStored) val dyeStoredView: Map<DyeColor, Int> = Collections.unmodifiableMap(dyeStored)
@ -46,7 +46,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
} }
} }
setChangedLight() markDirtyFast()
} }
val config = ConfigurableItemHandler(input = dyeInput.handler(object : HandlerFilter { val config = ConfigurableItemHandler(input = dyeInput.handler(object : HandlerFilter {

View File

@ -31,7 +31,7 @@ import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, blockPos, blockState) { MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, blockPos, blockState) {
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.MatterBottler.VALUES)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.MatterBottler.VALUES))
val energyConfig = ConfigurableEnergy(energy) val energyConfig = ConfigurableEnergy(energy)
private inner class Container : MatteryContainer(3) { private inner class Container : MatteryContainer(3) {
@ -44,7 +44,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
} }
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
setChangedLight() markDirtyFast()
updateBlockState() updateBlockState()
} }
} }
@ -57,7 +57,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
field = value field = value
initialCapacity = null initialCapacity = null
workProgress = 0f workProgress = 0f
this.setChangedLight() this.markDirtyFast()
if (value) { if (value) {
inputHandler.parent = bottlingHandler inputHandler.parent = bottlingHandler
@ -73,7 +73,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
var spitItemsWhenCantWork = false var spitItemsWhenCantWork = false
set(value) { set(value) {
field = value field = value
this.setChangedLight() this.markDirtyFast()
} }
val bottlingHandler = bottling.handler(object : HandlerFilter { val bottlingHandler = bottling.handler(object : HandlerFilter {
@ -97,7 +97,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
battery = batteryItemHandler battery = batteryItemHandler
) )
val matter: ProfiledMatterStorage<MatterStorageImpl> = ProfiledMatterStorage(object : MatterStorageImpl(this::setChangedLight, FlowDirection.BI_DIRECTIONAL, MachinesConfig.MatterBottler.VALUES::matterCapacity) { val matter: ProfiledMatterStorage<MatterStorageImpl> = ProfiledMatterStorage(object : MatterStorageImpl(this::markDirtyFast, FlowDirection.BI_DIRECTIONAL, MachinesConfig.MatterBottler.VALUES::matterCapacity) {
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
} }

View File

@ -120,7 +120,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
override val matterFlow: FlowDirection override val matterFlow: FlowDirection
get() = FlowDirection.BI_DIRECTIONAL get() = FlowDirection.BI_DIRECTIONAL
val container = object : MatteryContainer(this::setChangedLight, BatteryBankBlockEntity.CAPACITY) { val container = object : MatteryContainer(this::markDirtyFast, BatteryBankBlockEntity.CAPACITY) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old) super.setChanged(slot, new, old)
capacitorStatus[slot].boolean = new.getCapability(MatteryCapability.MATTER).isPresent capacitorStatus[slot].boolean = new.getCapability(MatteryCapability.MATTER).isPresent

View File

@ -54,15 +54,15 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
} }
} }
override val upgrades = UpgradeContainer(this::setChangedLight, 4, UpgradeType.REPLICATOR) override val upgrades = UpgradeContainer(this::markDirtyFast, 4, UpgradeType.REPLICATOR)
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, upgrades.transform(MachinesConfig.MATTER_DECOMPOSER))) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, upgrades.transform(MachinesConfig.MATTER_DECOMPOSER)))
val energyConfig = ConfigurableEnergy(energy) val energyConfig = ConfigurableEnergy(energy)
init { init {
savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::energy, ENERGY_KEY)
} }
val matter = ProfiledMatterStorage(MatterStorageImpl(::setChangedLight, FlowDirection.OUTPUT, upgrades.matterCapacity(MachinesConfig.MATTER_DECOMPOSER::matterCapacity))) val matter = ProfiledMatterStorage(MatterStorageImpl(::markDirtyFast, FlowDirection.OUTPUT, upgrades.matterCapacity(MachinesConfig.MATTER_DECOMPOSER::matterCapacity)))
val matterNode = SimpleMatterNode(matter = matter) val matterNode = SimpleMatterNode(matter = matter)
init { init {
@ -72,8 +72,8 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
} }
// вход, выход // вход, выход
val inputContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val inputContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val outputContainer = MatteryContainer(::setChangedLight, 2).also(::addDroppableContainer) val outputContainer = MatteryContainer(::markDirtyFast, 2).also(::addDroppableContainer)
val itemConfig = ConfigurableItemHandler( val itemConfig = ConfigurableItemHandler(
input = inputContainer.handler(object : HandlerFilter { input = inputContainer.handler(object : HandlerFilter {

View File

@ -52,9 +52,9 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
var isUnableToProcess = false var isUnableToProcess = false
private set private set
val upgrades = UpgradeContainer(this::setChangedLight, 3, UpgradeType.REPLICATOR) val upgrades = UpgradeContainer(this::markDirtyFast, 3, UpgradeType.REPLICATOR)
val matter = ProfiledMatterStorage(MatterStorageImpl(::setChangedLight, FlowDirection.INPUT, upgrades.matterCapacity(MachinesConfig.MatterReconstructor.VALUES::matterCapacity))) val matter = ProfiledMatterStorage(MatterStorageImpl(::markDirtyFast, FlowDirection.INPUT, upgrades.matterCapacity(MachinesConfig.MatterReconstructor.VALUES::matterCapacity)))
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::setChangedLight, upgrades.transform(MachinesConfig.MatterReconstructor.VALUES))) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::markDirtyFast, upgrades.transform(MachinesConfig.MatterReconstructor.VALUES)))
val matterNode = object : MatterNode() { val matterNode = object : MatterNode() {
override fun getMatterHandler(): IMatterStorage { override fun getMatterHandler(): IMatterStorage {

View File

@ -48,7 +48,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer) val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer)
val matterNode = SimpleMatterNode(matter = matter) val matterNode = SimpleMatterNode(matter = matter)
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, MachinesConfig.MatterRecycler.VALUES)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, MachinesConfig.MatterRecycler.VALUES))
val itemConfig = ConfigurableItemHandler(input = container.handler(object : HandlerFilter { val itemConfig = ConfigurableItemHandler(input = container.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean { override fun canInsert(slot: Int, stack: ItemStack): Boolean {

View File

@ -65,8 +65,8 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
} }
override val upgrades = UpgradeContainer(this::setChangedLight, 3, UpgradeType.REPLICATOR) override val upgrades = UpgradeContainer(this::markDirtyFast, 3, UpgradeType.REPLICATOR)
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_REPLICATOR))) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_REPLICATOR)))
val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.INPUT, upgrades.matterCapacity(MachinesConfig.MATTER_REPLICATOR::matterCapacity))) val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.INPUT, upgrades.matterCapacity(MachinesConfig.MATTER_REPLICATOR::matterCapacity)))
val outputContainer = MatteryContainer(::itemContainerUpdated, 3).also(::addDroppableContainer) val outputContainer = MatteryContainer(::itemContainerUpdated, 3).also(::addDroppableContainer)
val dustContainer = MatteryContainer(::itemContainerUpdated, 2).also(::addDroppableContainer) val dustContainer = MatteryContainer(::itemContainerUpdated, 2).also(::addDroppableContainer)

View File

@ -31,9 +31,9 @@ import kotlin.math.pow
class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryWorkerBlockEntity<ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ItemJob.CODEC) { MatteryWorkerBlockEntity<ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ItemJob.CODEC) {
override val upgrades = UpgradeContainer(this::setChangedLight, 2, UpgradeType.BASIC) override val upgrades = UpgradeContainer(this::markDirtyFast, 2, UpgradeType.BASIC)
val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer) val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer)
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_SCANNER))) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_SCANNER)))
val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(object : HandlerFilter { val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean { override fun canInsert(slot: Int, stack: ItemStack): Boolean {

View File

@ -23,26 +23,26 @@ import ru.dbotthepony.mc.otm.storage.optics.powered
import ru.dbotthepony.mc.otm.storage.optics.flow import ru.dbotthepony.mc.otm.storage.optics.flow
class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_RACK, blockPos, blockState) { class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_RACK, blockPos, blockState) {
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.DRIVE_RACK)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.DRIVE_RACK))
val cell = StorageNode(energy) val cell = StorageNode(energy)
val energyConfig = ConfigurableEnergy(energy) val energyConfig = ConfigurableEnergy(energy)
var insertPriority = 0 var insertPriority = 0
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
var extractPriority = 0 var extractPriority = 0
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
var mode = FlowDirection.BI_DIRECTIONAL var mode = FlowDirection.BI_DIRECTIONAL
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
val container: MatteryContainer = object : MatteryContainer(this::setChanged, 4) { val container: MatteryContainer = object : MatteryContainer(this::setChanged, 4) {

View File

@ -26,10 +26,10 @@ import ru.dbotthepony.mc.otm.menu.storage.DriveViewerMenu
import java.util.UUID import java.util.UUID
class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_VIEWER, blockPos, blockState) { class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_VIEWER, blockPos, blockState) {
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER))
val energyConfig = ConfigurableEnergy(energy) val energyConfig = ConfigurableEnergy(energy)
val container: MatteryContainer = object : MatteryContainer(this::setChangedLight, 1) { val container: MatteryContainer = object : MatteryContainer(this::markDirtyFast, 1) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old) super.setChanged(slot, new, old)
@ -63,13 +63,13 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
override var sorting: ItemStorageStackSorter = ItemStorageStackSorter.DEFAULT override var sorting: ItemStorageStackSorter = ItemStorageStackSorter.DEFAULT
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
override var isAscending: Boolean = true override var isAscending: Boolean = true
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
} }
@ -85,7 +85,7 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
if (state != blockState) { if (state != blockState) {
level?.setBlock(blockPos, state, Block.UPDATE_CLIENTS) level?.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
} else { } else {
setChangedLight() markDirtyFast()
} }
} }

View File

@ -45,7 +45,6 @@ import ru.dbotthepony.mc.otm.client.render.Widgets8
import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.CombinedContainer
import ru.dbotthepony.mc.otm.container.addItem import ru.dbotthepony.mc.otm.container.addItem
import ru.dbotthepony.mc.otm.container.fullIterator import ru.dbotthepony.mc.otm.container.fullIterator
import ru.dbotthepony.mc.otm.container.iterator
import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.toList import ru.dbotthepony.mc.otm.core.collect.toList
import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.isNotEmpty
@ -173,7 +172,7 @@ class ItemMonitorPlayerSettings : INBTSerializable<CompoundTag>, IItemMonitorPla
} }
class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ITEM_MONITOR, blockPos, blockState), IStorageEventConsumer<ItemStorageStack> { class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ITEM_MONITOR, blockPos, blockState), IStorageEventConsumer<ItemStorageStack> {
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.ITEM_MONITOR)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.ITEM_MONITOR))
val energyConfig = ConfigurableEnergy(energy) val energyConfig = ConfigurableEnergy(energy)
init { init {
@ -213,7 +212,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
// hence we are forced to work around this by providing proxy container // hence we are forced to work around this by providing proxy container
val craftingGrid = object : MatteryContainer(3 * 3) { val craftingGrid = object : MatteryContainer(3 * 3) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
setChangedLight() markDirtyFast()
craftingGridVanilla[slot] = new craftingGridVanilla[slot] = new
if (!inProcessOfCraft) { if (!inProcessOfCraft) {

View File

@ -52,7 +52,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
return StorageBusMenu(containerID, inventory, this) return StorageBusMenu(containerID, inventory, this)
} }
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.STORAGE_INTERFACES)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.STORAGE_INTERFACES))
val energyConfig = ConfigurableEnergy(energy, modesFront = FlowDirection.NONE) val energyConfig = ConfigurableEnergy(energy, modesFront = FlowDirection.NONE)
val cell: StorageNode = object : StorageNode(energy) { val cell: StorageNode = object : StorageNode(energy) {
@ -80,19 +80,19 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
var insertPriority = 0 var insertPriority = 0
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
var extractPriority = 0 var extractPriority = 0
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
var mode: FlowDirection = FlowDirection.BI_DIRECTIONAL var mode: FlowDirection = FlowDirection.BI_DIRECTIONAL
set(value) { set(value) {
field = value field = value
setChangedLight() markDirtyFast()
} }
init { init {
@ -123,7 +123,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
val filter = ItemFilter(MAX_FILTERS) { val filter = ItemFilter(MAX_FILTERS) {
component?.scan() component?.scan()
setChangedLight() markDirtyFast()
} }
init { init {

View File

@ -47,7 +47,7 @@ abstract class AbstractStorageImportExport(
blockState: BlockState, blockState: BlockState,
energyValues: EnergyBalanceValues = MachinesConfig.STORAGE_INTERFACES energyValues: EnergyBalanceValues = MachinesConfig.STORAGE_INTERFACES
) : MatteryPoweredBlockEntity(blockType, blockPos, blockState) { ) : MatteryPoweredBlockEntity(blockType, blockPos, blockState) {
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::setChangedLight, energyValues)) final override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::markDirtyFast, energyValues))
val energyConfig = ConfigurableEnergy(energy, modesFront = FlowDirection.NONE) val energyConfig = ConfigurableEnergy(energy, modesFront = FlowDirection.NONE)
val cell: StorageNode = object : StorageNode(energy) { val cell: StorageNode = object : StorageNode(energy) {
@ -115,7 +115,7 @@ class StorageImporterBlockEntity(
blockPos: BlockPos, blockState: BlockState blockPos: BlockPos, blockState: BlockState
) : AbstractStorageImportExport(MBlockEntities.STORAGE_IMPORTER, blockPos, blockState), IItemHandler { ) : AbstractStorageImportExport(MBlockEntities.STORAGE_IMPORTER, blockPos, blockState), IItemHandler {
override val filter = ItemFilter(MAX_FILTERS) { override val filter = ItemFilter(MAX_FILTERS) {
setChangedLight() markDirtyFast()
} }
private var lastSlot = 0 private var lastSlot = 0
@ -264,7 +264,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
lastSlot = 0 lastSlot = 0
setChangedLight() markDirtyFast()
}.also { it.isWhitelist = true } }.also { it.isWhitelist = true }
private var lastSlot = 0 private var lastSlot = 0

View File

@ -22,7 +22,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState
} }
val cell = StorageNode() val cell = StorageNode()
val energy = WorkerEnergyStorage(this::setChangedLight, MachinesConfig.STORAGE_POWER_SUPPLIER) override val energy = WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.STORAGE_POWER_SUPPLIER)
init { init {
savetable(::energy, ENERGY_KEY) savetable(::energy, ENERGY_KEY)

View File

@ -25,7 +25,7 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
return AndroidChargerMenu(containerID, inventory, this) return AndroidChargerMenu(containerID, inventory, this)
} }
val energyConfig = ConfigurableEnergy(ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.ANDROID_CHARGER)), modesTop = FlowDirection.NONE) val energyConfig = ConfigurableEnergy(ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.ANDROID_CHARGER)), modesTop = FlowDirection.NONE)
init { init {
savetables.stateful(energyConfig::energy, ENERGY_KEY) savetables.stateful(energyConfig::energy, ENERGY_KEY)

View File

@ -28,7 +28,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return AndroidStationMenu(containerID, inventory, this) return AndroidStationMenu(containerID, inventory, this)
} }
val energy: ProfiledEnergyStorage<WorkerEnergyStorage> = ProfiledEnergyStorage(object : WorkerEnergyStorage(::setChangedLight, MachinesConfig.AndroidStation.VALUES) { override val energy: ProfiledEnergyStorage<WorkerEnergyStorage> = ProfiledEnergyStorage(object : WorkerEnergyStorage(::markDirtyFast, MachinesConfig.AndroidStation.VALUES) {
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return super.extractEnergy(howMuch, simulate).also { return super.extractEnergy(howMuch, simulate).also {
if (!simulate && this.batteryLevel.isZero) { if (!simulate && this.batteryLevel.isZero) {

View File

@ -88,7 +88,7 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
} }
if (!simulate && !summ.isZero) { if (!simulate && !summ.isZero) {
setChangedLight() markDirtyFast()
gaugeLevel = batteryLevel.percentage(maxBatteryLevel) gaugeLevel = batteryLevel.percentage(maxBatteryLevel)
} }

View File

@ -24,15 +24,15 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
return ChemicalGeneratorMenu(containerID, inventory, this) return ChemicalGeneratorMenu(containerID, inventory, this)
} }
val batteryContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val batteryContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val residueContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val residueContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val fuelContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val fuelContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val batteryItemHandler = batteryContainer.handler(HandlerFilter.Chargeable) val batteryItemHandler = batteryContainer.handler(HandlerFilter.Chargeable)
val residueItemHandler = residueContainer.handler(HandlerFilter.OnlyOut) val residueItemHandler = residueContainer.handler(HandlerFilter.OnlyOut)
val fuelItemHandler = fuelContainer.handler(HandlerFilter.ChemicalFuel) val fuelItemHandler = fuelContainer.handler(HandlerFilter.ChemicalFuel)
val energy = ProfiledEnergyStorage(GeneratorEnergyStorage(::setChangedLight, MachinesConfig.ChemicalGenerator.VALUES::energyCapacity, MachinesConfig.ChemicalGenerator.VALUES::energyThroughput)) val energy = ProfiledEnergyStorage(GeneratorEnergyStorage(::markDirtyFast, MachinesConfig.ChemicalGenerator.VALUES::energyCapacity, MachinesConfig.ChemicalGenerator.VALUES::energyThroughput))
val itemConfig = ConfigurableItemHandler( val itemConfig = ConfigurableItemHandler(
input = fuelItemHandler, input = fuelItemHandler,
@ -55,8 +55,8 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
savetables.int(::workTicksTotal) savetables.int(::workTicksTotal)
} }
override fun setChangedLight() { override fun markDirtyFast() {
super.setChangedLight() super.markDirtyFast()
checkFuelSlot = true checkFuelSlot = true
} }
@ -106,9 +106,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
} }
if (energy.batteryLevel.isPositive) { if (energy.batteryLevel.isPositive) {
val item = batteryContainer[0] for (item in batteryContainer) {
if (!item.isEmpty) {
item.energy?.also { item.energy?.also {
moveEnergy(energy, it, MachinesConfig.ChemicalGenerator.VALUES.energyThroughput, simulate = false) moveEnergy(energy, it, MachinesConfig.ChemicalGenerator.VALUES.energyThroughput, simulate = false)
} }

View File

@ -22,8 +22,8 @@ import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_SERVO, blockPos, blockState) { class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_SERVO, blockPos, blockState) {
val discharge = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val discharge = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val charge = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer) val charge = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
val energy: ProfiledEnergyStorage<IMatteryEnergyStorage> = ProfiledEnergyStorage(object : IMatteryEnergyStorage { val energy: ProfiledEnergyStorage<IMatteryEnergyStorage> = ProfiledEnergyStorage(object : IMatteryEnergyStorage {
override val energyFlow: FlowDirection get() { override val energyFlow: FlowDirection get() {

View File

@ -18,11 +18,11 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
set(value) { set(value) {
require(value >= 0L) { "Negative experience: $value" } require(value >= 0L) { "Negative experience: $value" }
field = value field = value
setChangedLight() markDirtyFast()
} }
val capsuleContainer = MatteryContainer(::setChangedLight, 1) val capsuleContainer = MatteryContainer(::markDirtyFast, 1)
val servoContainer = MatteryContainer(::setChangedLight, 1) val servoContainer = MatteryContainer(::markDirtyFast, 1)
init { init {
savetables.long(::experienceStored) savetables.long(::experienceStored)

View File

@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.container.balance
import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.find
import ru.dbotthepony.mc.otm.core.collect.maybe import ru.dbotthepony.mc.otm.core.collect.maybe
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu
@ -29,12 +28,12 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MRecipes import ru.dbotthepony.mc.otm.registry.MRecipes
class PlatePressBlockEntity( class PlatePressBlockEntity(
p_155229_: BlockPos, blockPos: BlockPos,
p_155230_: BlockState, blockState: BlockState,
val isTwin: Boolean = false, val isTwin: Boolean = false,
) : MatteryWorkerBlockEntity<ItemJob>(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, p_155229_, p_155230_, ItemJob.CODEC, if (isTwin) 2 else 1) { ) : MatteryWorkerBlockEntity<ItemJob>(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, blockPos, blockState, ItemJob.CODEC, if (isTwin) 2 else 1) {
override val upgrades = UpgradeContainer(this::setChangedLight, if (isTwin) 4 else 3, UpgradeType.BASIC_PROCESSING) override val upgrades = UpgradeContainer(this::markDirtyFast, if (isTwin) 4 else 3, UpgradeType.BASIC_PROCESSING)
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(MachinesConfig.PLATE_PRESS))) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(MachinesConfig.PLATE_PRESS)))
val inputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer) val inputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer)
val outputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer) val outputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer)

View File

@ -35,8 +35,8 @@ class PoweredFurnaceBlockEntity(
val recipeType: RecipeType<out AbstractCookingRecipe>, val recipeType: RecipeType<out AbstractCookingRecipe>,
val config: WorkerBalanceValues val config: WorkerBalanceValues
) : MatteryWorkerBlockEntity<ItemJob>(type, blockPos, blockState, ItemJob.CODEC, 2) { ) : MatteryWorkerBlockEntity<ItemJob>(type, blockPos, blockState, ItemJob.CODEC, 2) {
override val upgrades = UpgradeContainer(this::setChangedLight, 2, UpgradeType.BASIC_PROCESSING) override val upgrades = UpgradeContainer(this::markDirtyFast, 2, UpgradeType.BASIC_PROCESSING)
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config))) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config)))
val inputs = immutableList(2) { MatteryContainer(this::itemContainerUpdated, 1) } val inputs = immutableList(2) { MatteryContainer(this::itemContainerUpdated, 1) }
val outputs = immutableList(2) { MatteryContainer(this::itemContainerUpdated, 1) } val outputs = immutableList(2) { MatteryContainer(this::itemContainerUpdated, 1) }

View File

@ -15,13 +15,18 @@ import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<CompoundTag?> { abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<CompoundTag?> {
init {
storages.add(WeakReference(this))
}
private val historyReceiveInternal = ArrayList<Decimal>(HISTORY_SIZE) private val historyReceiveInternal = ArrayList<Decimal>(HISTORY_SIZE)
private val historyTransferInternal = ArrayList<Decimal>(HISTORY_SIZE) private val historyTransferInternal = ArrayList<Decimal>(HISTORY_SIZE)
private var isTicking = false
private fun startTicking() {
if (!isTicking) {
isTicking = true
storages.add(this)
}
}
val historyReceive: List<Decimal> = Collections.unmodifiableList(historyReceiveInternal) val historyReceive: List<Decimal> = Collections.unmodifiableList(historyReceiveInternal)
val historyTransfer: List<Decimal> = Collections.unmodifiableList(historyTransferInternal) val historyTransfer: List<Decimal> = Collections.unmodifiableList(historyTransferInternal)
@ -47,6 +52,7 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
protected fun recordTransfer(value: Decimal, simulate: Boolean): Decimal { protected fun recordTransfer(value: Decimal, simulate: Boolean): Decimal {
if (!simulate) { if (!simulate) {
thisTickTransfer += value thisTickTransfer += value
if (!value.isZero) startTicking()
} }
return value return value
@ -55,19 +61,23 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
protected fun recordReceive(value: Decimal, simulate: Boolean): Decimal { protected fun recordReceive(value: Decimal, simulate: Boolean): Decimal {
if (!simulate) { if (!simulate) {
thisTickReceive += value thisTickReceive += value
if (!value.isZero) startTicking()
} }
return value return value
} }
private fun tick() { private fun tick(): Boolean {
tick = (tick + 1) % HISTORY_SIZE tick = (tick + 1) % HISTORY_SIZE
historyReceiveInternal[tick] = thisTickReceive historyReceiveInternal[tick] = thisTickReceive
historyTransferInternal[tick] = thisTickTransfer historyTransferInternal[tick] = thisTickTransfer
isTicking = !thisTickReceive.isZero || !thisTickTransfer.isZero || historyReceiveInternal.any { !it.isZero } || historyTransferInternal.any { !it.isZero }
thisTickReceive = Decimal.ZERO thisTickReceive = Decimal.ZERO
thisTickTransfer = Decimal.ZERO thisTickTransfer = Decimal.ZERO
return isTicking
} }
val savedata: INBTSerializable<CompoundTag?> = object : INBTSerializable<CompoundTag?> { val savedata: INBTSerializable<CompoundTag?> = object : INBTSerializable<CompoundTag?> {
@ -155,7 +165,7 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
companion object { companion object {
const val HISTORY_SIZE = 20 const val HISTORY_SIZE = 20
private val storages = ObjectArrayList<WeakReference<AbstractProfiledStorage<*>>>() private val storages = ObjectArrayList<AbstractProfiledStorage<*>>()
val HISTORY_WEIGHTERS: ImmutableList<Decimal> = ImmutableList.of( val HISTORY_WEIGHTERS: ImmutableList<Decimal> = ImmutableList.of(
Decimal("0.313335967"), Decimal("0.313335967"),
@ -201,7 +211,7 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
// разумеется, такое решение может несколько снизить производительность сервера, // разумеется, такое решение может несколько снизить производительность сервера,
// но ничего страшного произойти не должно // но ничего страшного произойти не должно
internal fun onServerPostTick() { internal fun onServerPostTick() {
storages.forValidRefs { it.tick() } storages.removeIf { !it.tick() }
} }
} }
} }

View File

@ -2,8 +2,14 @@ package ru.dbotthepony.mc.otm.core.util
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import java.util.function.IntSupplier
/**
* If synchronization is not required, [CounterInvalidatedLazy] should be used instead.
*/
class AtomicallyInvalidatedLazy<V>(private val invalidator: IntSupplier, private val initializer: () -> V) : Lazy<V> {
constructor(invalidator: AtomicInteger, initializer: () -> V) : this(invalidator::get, initializer)
class AtomicallyInvalidatedLazy<V>(private val invalidator: AtomicInteger, private val initializer: () -> V) : Lazy<V> {
@Volatile @Volatile
private var thisCounter = -1 private var thisCounter = -1
@Volatile @Volatile
@ -11,10 +17,10 @@ class AtomicallyInvalidatedLazy<V>(private val invalidator: AtomicInteger, priva
private val lock = ReentrantLock() private val lock = ReentrantLock()
override val value: V get() { override val value: V get() {
if (thisCounter != invalidator.get()) { if (thisCounter != invalidator.asInt) {
lock.lock() lock.lock()
this.stored = Companion this.stored = Companion
thisCounter = invalidator.get() thisCounter = invalidator.asInt
lock.unlock() lock.unlock()
} }
@ -35,7 +41,7 @@ class AtomicallyInvalidatedLazy<V>(private val invalidator: AtomicInteger, priva
} }
override fun isInitialized(): Boolean { override fun isInitialized(): Boolean {
return stored !== Companion && thisCounter == invalidator.get() return stored !== Companion && thisCounter == invalidator.asInt
} }
private companion object private companion object

View File

@ -0,0 +1,80 @@
package ru.dbotthepony.mc.otm.core.util
import java.util.concurrent.atomic.AtomicInteger
import java.util.function.IntConsumer
import java.util.function.IntSupplier
/**
* This lazy is not synchronized, so in event of two or more threads accessing value behavior of this implementation is undefined
*
* For synchronized use case, [AtomicallyInvalidatedLazy] should be used
*/
fun <V> countingLazy(invalidator: IntSupplier, initializer: () -> V): Lazy<V> {
if (invalidator is IntCounter) {
return SmartCounterInvalidatedLazy(invalidator, initializer)
}
return CounterInvalidatedLazy(invalidator, initializer)
}
/**
* This lazy is not synchronized, so in event of two or more threads accessing value behavior of this implementation is undefined
*
* For synchronized use case, [AtomicallyInvalidatedLazy] should be used
*/
class CounterInvalidatedLazy<V>(private val invalidator: IntSupplier, private val initializer: () -> V) : Lazy<V> {
constructor(invalidator: AtomicInteger, initializer: () -> V) : this(invalidator::get, initializer)
private var thisCounter = -1
private var stored: Any? = Companion
override val value: V get() {
var stored = stored
if (stored !== Companion && thisCounter == invalidator.asInt)
return stored as V
stored = initializer.invoke()
this.stored = stored
this.thisCounter = invalidator.asInt
return stored
}
override fun isInitialized(): Boolean {
return stored !== Companion && thisCounter == invalidator.asInt
}
private companion object
}
/**
* This lazy is not synchronized, so in event of two or more threads accessing value behavior of this implementation is undefined
*
* For synchronized use case, [AtomicallyInvalidatedLazy] should be used
*/
class SmartCounterInvalidatedLazy<V>(invalidator: IntCounter, private val initializer: () -> V) : Lazy<V> {
init {
invalidator.addListener(IntConsumer {
stored = Companion
})
}
private var stored: Any? = Companion
override val value: V get() {
var stored = stored
if (stored !== Companion)
return stored as V
stored = initializer.invoke()
this.stored = stored
return stored
}
override fun isInitialized(): Boolean {
return stored !== Companion
}
private companion object
}

View File

@ -0,0 +1,59 @@
package ru.dbotthepony.mc.otm.core.util
import ru.dbotthepony.mc.otm.core.IIntSubcripable
import ru.dbotthepony.mc.otm.core.ISubscriptable
import java.util.function.BooleanSupplier
import java.util.function.IntConsumer
import java.util.function.IntSupplier
class IntCounter : IntSupplier, IIntSubcripable {
/**
* Doesn't subscribe to counter (counter does not reference this invalidator)
*/
inner class WeakInvalidator : BooleanSupplier {
private var thisValue = value
override fun getAsBoolean(): Boolean {
if (thisValue != value) {
thisValue = value
return true
}
return false
}
}
/**
* Subscribes to counter (counter references this invalidator, can be removed using [remove])
*/
inner class StrongInvalidator : BooleanSupplier, ISubscriptable.L {
private var isValid = true
private val l = listeners.addListener(IntConsumer { isValid = false })
override fun getAsBoolean(): Boolean {
val isValid = isValid
this.isValid = true
return isValid
}
override fun remove() {
l.remove()
}
}
private val listeners = IIntSubcripable.Impl()
private var value = 0
fun increment() {
value++
listeners.accept(value)
}
override fun addListener(listener: IntConsumer): ISubscriptable.L {
return listeners.addListener(listener)
}
override fun getAsInt(): Int {
return value
}
}

View File

@ -18,6 +18,8 @@ class TickList : ITickable {
private val timers = ArrayDeque<Timer>() private val timers = ArrayDeque<Timer>()
private val namedTimers = Object2ObjectOpenHashMap<Any, Timer>(0) private val namedTimers = Object2ObjectOpenHashMap<Any, Timer>(0)
private var shouldTick = false
var inTicker = false var inTicker = false
private set private set
var ticks = 0 var ticks = 0
@ -92,6 +94,8 @@ class TickList : ITickable {
} }
private fun <T : Any> add(value: T, regular: MutableList<T>, queue: MutableList<T>) { private fun <T : Any> add(value: T, regular: MutableList<T>, queue: MutableList<T>) {
shouldTick = true
if (inTicker) { if (inTicker) {
queue.add(value) queue.add(value)
} else { } else {
@ -148,10 +152,14 @@ class TickList : ITickable {
} }
ticks++ ticks++
if (!shouldTick) return
inTicker = true inTicker = true
shouldTick = timers.isNotEmpty()
try { try {
if (conditional.isNotEmpty()) { if (conditional.isNotEmpty()) {
shouldTick = true
val iterator = conditional.iterator() val iterator = conditional.iterator()
for (ticker in iterator) { for (ticker in iterator) {
@ -162,6 +170,8 @@ class TickList : ITickable {
} }
if (once.isNotEmpty()) { if (once.isNotEmpty()) {
shouldTick = true
for (ticker in once) { for (ticker in once) {
ticker.tick() ticker.tick()
} }
@ -170,23 +180,31 @@ class TickList : ITickable {
} }
if (toRemoveFromAlways.isNotEmpty()) { if (toRemoveFromAlways.isNotEmpty()) {
shouldTick = true
for (v in toRemoveFromAlways) always.remove(v) for (v in toRemoveFromAlways) always.remove(v)
toRemoveFromAlways.clear() toRemoveFromAlways.clear()
} }
if (always.isNotEmpty()) { if (always.isNotEmpty()) {
shouldTick = true
for (ticker in always) { for (ticker in always) {
ticker.tick() ticker.tick()
} }
} }
if (alwaysQueued.isNotEmpty()) { if (alwaysQueued.isNotEmpty()) {
shouldTick = true
always.ensureCapacity(always.size + alwaysQueued.size) always.ensureCapacity(always.size + alwaysQueued.size)
for (v in alwaysQueued) always.add(v) // avoid toArray() for (v in alwaysQueued) always.add(v) // avoid toArray()
alwaysQueued.clear() alwaysQueued.clear()
} }
if (conditionalQueued.isNotEmpty()) { if (conditionalQueued.isNotEmpty()) {
shouldTick = true
for (ticker in conditionalQueued) { for (ticker in conditionalQueued) {
conditional.addFirst(ticker) conditional.addFirst(ticker)
} }
@ -195,6 +213,8 @@ class TickList : ITickable {
} }
if (onceQueued.isNotEmpty()) { if (onceQueued.isNotEmpty()) {
shouldTick = true
for (ticker in onceQueued) { for (ticker in onceQueued) {
once.addFirst(ticker) once.addFirst(ticker)
} }

View File

@ -6,7 +6,6 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
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.capability.matteryEnergy
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
abstract class MatteryPoweredMenu protected constructor( abstract class MatteryPoweredMenu protected constructor(
@ -15,7 +14,7 @@ abstract class MatteryPoweredMenu protected constructor(
inventory: Inventory, inventory: Inventory,
tile: MatteryPoweredBlockEntity? = null tile: MatteryPoweredBlockEntity? = null
) : MatteryMenu(menuType, containerID, inventory, tile) { ) : MatteryMenu(menuType, containerID, inventory, tile) {
val energyWidget = LevelGaugeWidget(this, tile?.matteryEnergy) val energyWidget = LevelGaugeWidget(this, tile?.energy)
val batterySlot = BatterySlot(tile?.batteryContainer ?: SimpleContainer(1), 0) val batterySlot = BatterySlot(tile?.batteryContainer ?: SimpleContainer(1), 0)
val redstoneConfig = EnumInputWithFeedback<RedstoneSetting>(this) val redstoneConfig = EnumInputWithFeedback<RedstoneSetting>(this)