Allow MatteryWorkerBlockEntity to have multiple job event loops

This commit is contained in:
DBotThePony 2023-06-23 00:00:35 +07:00
parent 4e62b47f84
commit 97d3a07065
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -1,7 +1,9 @@
package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.ImmutableList
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
@ -12,12 +14,14 @@ import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
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.math.Decimal
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.core.nbt.set
/**
* Simple machine, which can work on only one job at time.
* Simple machine, which can work on only one job type.
*
* From technical point, this is a specialized use case of [MachineJobEventLoop].
*/
@ -25,32 +29,35 @@ abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
type: BlockEntityType<*>,
blockPos: BlockPos,
blockState: BlockState,
val jobDeserializer: (tag: CompoundTag) -> JobType?
val jobDeserializer: (tag: CompoundTag) -> JobType?,
maxJobs: Int = 1
) : MatteryPoweredBlockEntity(type, blockPos, blockState) {
val jobEventLoop = object : MachineJobEventLoop<JobType>() {
override val energy: IMatteryEnergyStorage?
get() = matteryEnergy
override val isBlockedByRedstone: Boolean
get() = redstoneControl.isBlockedByRedstone
val jobEventLoops: ImmutableList<MachineJobEventLoop<JobType>> = immutableList(maxJobs) {
object : MachineJobEventLoop<JobType>() {
override val energy: IMatteryEnergyStorage?
get() = matteryEnergy
override val isBlockedByRedstone: Boolean
get() = redstoneControl.isBlockedByRedstone
override fun deserializeJob(nbt: CompoundTag): JobType? {
return jobDeserializer.invoke(nbt)
}
override fun deserializeJob(nbt: CompoundTag): JobType? {
return jobDeserializer.invoke(nbt)
}
override fun onJobFinish(job: JobType): JobStatus {
return this@MatteryWorkerBlockEntity.onJobFinish(job)
}
override fun onJobFinish(job: JobType): JobStatus {
return this@MatteryWorkerBlockEntity.onJobFinish(job)
}
override fun computeNextJob(): JobContainer<JobType> {
return this@MatteryWorkerBlockEntity.computeNextJob()
}
override fun computeNextJob(): JobContainer<JobType> {
return this@MatteryWorkerBlockEntity.computeNextJob()
}
override fun jobUpdated(new: JobType?, old: JobType?) {
this@MatteryWorkerBlockEntity.jobUpdated(new, old)
}
override fun jobUpdated(new: JobType?, old: JobType?) {
this@MatteryWorkerBlockEntity.jobUpdated(new, old)
}
override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: JobType): JobStatus {
return this@MatteryWorkerBlockEntity.onWorkTick(requiredPower, extractedPower, ticksAdvanced, job)
override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: JobType): JobStatus {
return this@MatteryWorkerBlockEntity.onWorkTick(requiredPower, extractedPower, ticksAdvanced, job)
}
}
}
@ -64,53 +71,68 @@ abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
override fun saveShared(nbt: CompoundTag) {
super.saveShared(nbt)
nbt["JobLoop"] = jobEventLoop.serializeNBT()
nbt["jobs"] = ListTag().also {
for ((i, job) in jobEventLoops.withIndex()) {
it.add(job.serializeNBT().also {
it["_id"] = i
})
}
}
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt.map("JobLoop", jobEventLoop::deserializeNBT)
for (v in nbt.getCompoundList("jobs")) {
if ("_id" in v) {
val id = v.getInt("_id")
if (id in jobEventLoops.indices) {
jobEventLoops[id].deserializeNBT(v)
}
}
}
}
override fun setChanged() {
super.setChanged()
jobEventLoop.isIdling = false
jobEventLoops.forEach { it.isIdling = false }
}
override fun setChangedLight() {
super.setChangedLight()
jobEventLoop.isIdling = false
jobEventLoops.forEach { it.isIdling = false }
}
protected fun powerLevelUpdated() {
super.setChangedLight()
jobEventLoop.notify(MachineJobEventLoop.IdleReason.POWER)
jobEventLoops.forEach { it.notify(MachineJobEventLoop.IdleReason.POWER) }
}
protected fun itemContainerUpdated() {
super.setChanged()
jobEventLoop.notify(MachineJobEventLoop.IdleReason.ITEM)
jobEventLoops.forEach { it.notify(MachineJobEventLoop.IdleReason.ITEM) }
}
protected fun matterLevelUpdated() {
super.setChangedLight()
jobEventLoop.notify(MachineJobEventLoop.IdleReason.MATTER)
jobEventLoops.forEach { it.notify(MachineJobEventLoop.IdleReason.MATTER) }
}
override fun redstoneStatusUpdated(newBlocked: Boolean, oldBlocked: Boolean) {
super.redstoneStatusUpdated(newBlocked, oldBlocked)
jobEventLoop.isIdling = newBlocked
jobEventLoops.forEach { it.isIdling = newBlocked }
}
override fun tick() {
super.tick()
jobEventLoop.think()
jobEventLoops.forEach { it.think() }
if (jobEventLoop.errorTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.ERROR) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.ERROR), Block.UPDATE_CLIENTS)
} else if (jobEventLoop.workingTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.WORKING) {
if (jobEventLoops.any { it.workingTicksAnim > 20 } && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.WORKING) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
} else if (jobEventLoop.idleTicksAnim > 20 && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.IDLE) {
} else if (jobEventLoops.any { it.errorTicksAnim > 20 } && blockState.hasProperty(WorkerState.WORKER_STATE) && blockState.getValue(WorkerState.WORKER_STATE) != WorkerState.ERROR) {
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) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
}
}