diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt index e9002aed7..6e251e9bf 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt @@ -14,7 +14,7 @@ import net.minecraftforge.fml.common.Mod import net.minecraftforge.data.event.GatherDataEvent import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.block.* -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock import ru.dbotthepony.mc.otm.block.storage.DriveViewerBlock diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/blocks/MatteryBlockStateProvider.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/blocks/MatteryBlockStateProvider.kt index add36a39e..0d5458351 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/blocks/MatteryBlockStateProvider.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/blocks/MatteryBlockStateProvider.kt @@ -7,7 +7,7 @@ import net.minecraftforge.client.model.generators.BlockStateProvider import net.minecraftforge.client.model.generators.ConfiguredModel import net.minecraftforge.data.event.GatherDataEvent import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.datagen.DataGen import ru.dbotthepony.mc.otm.datagen.getValueNullable import ru.dbotthepony.mc.otm.datagen.toXRotBlockstate diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt index bcc9e7de2..79784fab9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt @@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.addPreWorldTickerOnce import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt index 1ab676aca..5e1766dee 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt @@ -25,7 +25,7 @@ import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.addPreWorldTickerOnce import ru.dbotthepony.mc.otm.block.entity.GravitationStabilizerBlockEntity import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.core.plus import ru.dbotthepony.mc.otm.core.times import ru.dbotthepony.mc.otm.registry.MBlockEntities diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/PlatePressBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/PlatePressBlock.kt index 31fedcad5..448956867 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/PlatePressBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/PlatePressBlock.kt @@ -14,7 +14,7 @@ import net.minecraft.world.level.block.state.StateDefinition import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.block.entity.PlatePressBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt index aa1909a33..4c7c813eb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt @@ -19,7 +19,6 @@ import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.energy.IEnergyStorage import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.ImpreciseFraction diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/GravitationStabilizerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/GravitationStabilizerBlockEntity.kt index bbeb3c1d6..ae924813c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/GravitationStabilizerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/GravitationStabilizerBlockEntity.kt @@ -14,7 +14,6 @@ import ru.dbotthepony.mc.otm.block.BlockGravitationStabilizer import ru.dbotthepony.mc.otm.block.BlockGravitationStabilizerLens import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.core.plus import ru.dbotthepony.mc.otm.core.times import ru.dbotthepony.mc.otm.registry.MBlockEntities diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryWorkerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryWorkerBlockEntity.kt new file mode 100644 index 000000000..381ee6ed5 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryWorkerBlockEntity.kt @@ -0,0 +1,341 @@ +package ru.dbotthepony.mc.otm.block.entity + +import net.minecraft.world.level.block.entity.BlockEntityType +import net.minecraft.core.BlockPos +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.nbt.CompoundTag +import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.block.Block +import ru.dbotthepony.mc.otm.core.* +import ru.dbotthepony.mc.otm.map +import ru.dbotthepony.mc.otm.set + +private fun isReason(status: Any?, reason: Any) = status == null || status == reason + +abstract class MatteryWorkerBlockEntity( + type: BlockEntityType<*>, + blockPos: BlockPos, + blockState: BlockState, + val jobDeserializer: (tag: CompoundTag) -> JobType +) : MatteryPoweredBlockEntity(type, blockPos, blockState) { + open class Job( + open val ticks: Double, + open val powerUsage: ImpreciseFraction = ImpreciseFraction.ZERO + ) { + constructor( + tag: CompoundTag + ) : this(tag.getDouble("ticks"), tag.getImpreciseFraction("power")) + + open fun serializeNBT(): CompoundTag { + return CompoundTag().also { + it["ticks"] = ticks + it["power"] = powerUsage + } + } + } + + @Suppress("LeakingThis") + open class ItemJob : Job { + open val itemStack: ItemStack + + constructor( + itemStack: ItemStack, + ticks: Double, + power: ImpreciseFraction = ImpreciseFraction.ZERO + ) : super(ticks, power) { + this.itemStack = itemStack + } + + constructor( + tag: CompoundTag + ) : super(tag) { + this.itemStack = (tag["item"] as? CompoundTag)?.let { ItemStack.of(it) } ?: ItemStack.EMPTY + } + + override fun serializeNBT(): CompoundTag { + return super.serializeNBT().also { + it["item"] = itemStack.serializeNBT() + } + } + } + + enum class IdleReason { + ITEM, + POWER, + MATTER, + + /** + * Observing external factor, such as waiting for matter/item network tasks + */ + OBSERVING + } + + data class Status(val success: Boolean, val throttleTicks: Int = 0, val idleReason: IdleReason? = null) { + companion object { + val SUCCESS = Status(true) + val FAILURE = Status(false) + val FAILURE_ITEM = Status(false, 20, IdleReason.ITEM) + val FAILURE_MATTER = Status(false, 20, IdleReason.MATTER) + val FAILURE_WAIT = Status(false, 100) + val FAILURE_WAIT_FAST = Status(false, 20) + } + } + + var workTicks = 0.0 + protected set + + var throttleTicks = 0 + protected set + + var currentJob: JobType? = null + protected set + + /** + * Can be whatever you want, but [IdleReason] certainly contains all cases + */ + var idleReason: Any? = null + private set + + var isIdling = false + protected set + + val isUnableToProcess: Boolean get() = throttleTicks > 0 + + val workProgress: Float + get() { + val currentJob = currentJob ?: return 0.0f + return (workTicks / currentJob.ticks).coerceAtMost(1.0).toFloat() + } + + override fun saveAdditional(nbt: CompoundTag) { + super.saveAdditional(nbt) + nbt["work_ticks"] = workTicks + currentJob?.let { nbt["job"] = it.serializeNBT() } + } + + override fun load(nbt: CompoundTag) { + super.load(nbt) + + workTicks = nbt.getDouble("work_ticks") + currentJob = nbt.map("job", jobDeserializer::invoke) + + if (currentJob == null) + workTicks = 0.0 + } + + override fun setChanged() { + super.setChanged() + isIdling = false + } + + override fun setChangedLight() { + super.setChangedLight() + isIdling = false + } + + protected fun powerLevelUpdated() { + super.setChangedLight() + + if (isReason(idleReason, IdleReason.POWER)) { + isIdling = false + throttleTicks = 0 + } + } + + protected fun itemContainerUpdated() { + super.setChanged() + + if (isReason(idleReason, IdleReason.ITEM)) { + isIdling = false + throttleTicks = 0 + } + } + + protected fun matterLevelUpdated() { + super.setChangedLight() + + if (isReason(idleReason, IdleReason.MATTER)) { + isIdling = false + throttleTicks = 0 + } + } + + /** + * Called whenever reaching desired amount of ticks at job + */ + protected abstract fun onJobFinish(job: JobType): Status + + /** + * [Pair.second] is reason why job can't be performed + * + * If not null, it is written to [idleReason] + */ + protected abstract fun computeNextJob(): Pair + + protected open fun onWorkTick(requiredPower: ImpreciseFraction, extractedPower: ImpreciseFraction, ticksAdvanced: Double): Status { + return Status.SUCCESS + } + + private var idleTicksAnim = 0 + private var workingTicksAnim = 0 + private var errorTicksAnim = 0 + + override fun redstoneStatusUpdated(new_blocked: Boolean, old_blocked: Boolean) { + super.redstoneStatusUpdated(new_blocked, old_blocked) + isIdling = new_blocked + } + + protected fun workerLoop() { + if (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) + } + + if (throttleTicks > 0) { + workingTicksAnim = 0 + idleTicksAnim = 0 + throttleTicks-- + errorTicksAnim++ + + if (throttleTicks > 0) + return + } + + if (isIdling) { + workingTicksAnim = 0 + errorTicksAnim = 0 + idleTicksAnim++ + + if (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) + } + + return + } + + var availableTicks = 1.0 + + while (!isIdling && weakGreaterThan(availableTicks, 0.0)) { + if (isBlockedByRedstone) { + isIdling = true + break + } + + var currentJob = currentJob + + if (currentJob == null) { + if (isBlockedByRedstone) { + isIdling = true + break + } + + val (job, reason) = computeNextJob() + + if (job == null) { + idleReason = reason + isIdling = reason != null + workingTicksAnim = 0 + break + } + + this.currentJob = job + currentJob = job + } + + if (!currentJob.powerUsage.isZero && energy.batteryLevel.isZero) { + idleReason = IdleReason.POWER + isIdling = true + idleTicksAnim++ + + if (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) + } + + break + } + + idleTicksAnim = 0 + + if (weakLessThan(workTicks, currentJob.ticks)) { + val ticksLeft = currentJob.ticks - workTicks + val ticksAdvanced: Double + + var requiredPower: ImpreciseFraction? = null + var extractedPower: ImpreciseFraction? = null + + if (currentJob.powerUsage.isZero) { + ticksAdvanced = availableTicks.coerceAtMost(ticksLeft) + } else { + requiredPower = currentJob.powerUsage * ticksLeft.coerceAtMost(availableTicks) + extractedPower = energy.extractEnergyInner(requiredPower, true) + ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceAtMost(ticksLeft).coerceAtMost(availableTicks) + } + + if (weakEqualDoubles(ticksAdvanced, 0.0)) { + break + } + + val status = onWorkTick(requiredPower ?: ImpreciseFraction.ZERO, extractedPower ?: ImpreciseFraction.ZERO, ticksAdvanced) + + if (!status.success) { + throttleTicks += status.throttleTicks + + if (status.idleReason != null) { + idleReason = status.idleReason + isIdling = true + } + + break + } + + workingTicksAnim++ + errorTicksAnim = 0 + + workTicks += ticksAdvanced + availableTicks -= ticksAdvanced + + if (extractedPower != null) { + energy.extractEnergyInner(extractedPower, false) + } + + continue + } + + val status = onJobFinish(currentJob) + + if (status.success) { + this.currentJob = null + workTicks = 0.0 + errorTicksAnim = 0 + } else { + throttleTicks += status.throttleTicks + + if (status.idleReason != null) { + idleReason = status.idleReason + isIdling = true + } + + errorTicksAnim++ + } + } + + if (workingTicksAnim > 20 && + errorTicksAnim == 0 && + 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) + } + } + + fun basicTicker() { + batteryChargeLoop() + workerLoop() + } +} \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt index c02389e33..e2a6e0b3b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt @@ -10,12 +10,9 @@ import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.item.ItemStack import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional -import net.minecraftforge.items.CapabilityItemHandler import ru.dbotthepony.mc.otm.TranslatableComponent -import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainerFilter @@ -25,7 +22,10 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MRecipes import ru.dbotthepony.mc.otm.set -class PlatePressBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.PLATE_PRESS, p_155229_, p_155230_) { +class PlatePressBlockEntity( + p_155229_: BlockPos, + p_155230_: BlockState +) : MatteryWorkerBlockEntity(MBlockEntities.PLATE_PRESS, p_155229_, p_155230_, ::ItemJob) { val container = MatteryContainer(this::setChangedLight, 2) override val energy = WorkerEnergyStorage(this::setChangedLight) @@ -50,7 +50,7 @@ class PlatePressBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matter } override fun getCapability(cap: Capability, side: Direction?): LazyOptional { - if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + if (cap == ForgeCapabilities.ITEM_HANDLER) return itemHandler.get().cast() return super.getCapability(cap, side) @@ -73,32 +73,24 @@ class PlatePressBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matter return PlatePressMenu(containerID, inventory, this) } - override fun onJobFinish(job: WorkerJob): WorkerJobStatus { - val resultTag = job.data["result"] as? CompoundTag ?: return WorkerJobStatus() - val result = ItemStack.of(resultTag) + override fun onJobFinish(job: ItemJob): Status { + if (job.itemStack.isEmpty) + return Status.SUCCESS - if (result.isEmpty) - return WorkerJobStatus() + if (!container.fullyAddItem(job.itemStack, start = SLOT_OUTPUT, end = SLOT_OUTPUT)) + return Status.FAILURE_ITEM - if (!container.fullyAddItem(result, start = SLOT_OUTPUT, end = SLOT_OUTPUT)) { - return WorkerJobStatus(false, 20) - } - - return WorkerJobStatus() + return Status.SUCCESS } - override fun computeNextJob(): WorkerJob? { - val level = level ?: return null - val recipe = level.recipeManager.getRecipeFor(MRecipes.PLATE_PRESS, container, level).orElse(null) ?: return null + override fun computeNextJob(): Pair { + if (energy.batteryLevel.isZero) { + return null to IdleReason.POWER + } - val copy = container[SLOT_INPUT].copy() + val recipe = level?.recipeManager?.getRecipeFor(MRecipes.PLATE_PRESS, container, level!!)?.orElse(null) ?: return null to IdleReason.ITEM container[SLOT_INPUT].shrink(1) - container.setChanged(SLOT_INPUT) - copy.count = 1 - - return WorkerJob(copy, recipe.workTime.toDouble(), BASELINE_CONSUMPTION, CompoundTag().also { - it["result"] = recipe.resultItem.serializeNBT() - }) + return ItemJob(recipe.resultItem, recipe.workTime.toDouble(), BASELINE_CONSUMPTION) to null } companion object { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/WorkerState.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/WorkerState.kt new file mode 100644 index 000000000..2c592bb86 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/WorkerState.kt @@ -0,0 +1,21 @@ +package ru.dbotthepony.mc.otm.block.entity + +import net.minecraft.util.StringRepresentable +import net.minecraft.world.level.block.state.properties.EnumProperty + +enum class WorkerState : StringRepresentable { + IDLE, + WORKING, + ERROR; + + companion object { + @JvmField + val WORKER_STATE: EnumProperty = EnumProperty.create("worker", WorkerState::class.java) + @JvmField + val SEMI_WORKER_STATE: EnumProperty = EnumProperty.create("worker", WorkerState::class.java, IDLE, WORKING) + } + + override fun getSerializedName(): String { + return if (this == IDLE) "idle" else if (this == WORKING) "working" else "error" + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index 7d42b525a..bdfe096af 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -18,7 +18,7 @@ import net.minecraftforge.items.CapabilityItemHandler import ru.dbotthepony.mc.otm.TranslatableComponent import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt index 1b97ca714..0c8400f15 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt @@ -12,20 +12,21 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional -import net.minecraftforge.items.CapabilityItemHandler import net.minecraftforge.items.IItemHandler import ru.dbotthepony.mc.otm.TranslatableComponent -import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus +import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler import ru.dbotthepony.mc.otm.capability.matter.MatterDirection import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerImpl import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.MatteryContainerFilter import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.getImpreciseFraction +import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph @@ -93,7 +94,29 @@ fun moveMatterAsDustIntoContainer(_matterValue: ImpreciseFraction, container: Ma } class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) - : MatteryWorkerBlockEntity(MBlockEntities.MATTER_DECOMPOSER, pos, state), IMatterGraphNode { + : MatteryWorkerBlockEntity(MBlockEntities.MATTER_DECOMPOSER, pos, state, ::DecomposerJob), IMatterGraphNode { + + class DecomposerJob : Job { + val toDust: Boolean + var matterValue: ImpreciseFraction + + constructor(tag: CompoundTag) : super(tag) { + toDust = tag.getBoolean("to_dust") + matterValue = tag.getImpreciseFraction("value") + } + + constructor(toDust: Boolean, matterValue: ImpreciseFraction, ticks: Double) : super(ticks, BASE_CONSUMPTION) { + this.toDust = toDust + this.matterValue = matterValue + } + + override fun serializeNBT(): CompoundTag { + return super.serializeNBT().also { + it["to_dust"] = toDust + it["value"] = matterValue + } + } + } override val energy = WorkerEnergyStorage(this, ENERGY_STORAGE, MAX_IO) private var valid = true @@ -110,13 +133,18 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) private var resolverNode = LazyOptional.of { this } // вход, выход - @JvmField val container = MatteryContainer(this::setChangedLight, 3) private val itemHandler = LazyOptional.of { - container.handler( - { slot: Int, stack: ItemStack -> slot == INPUT_SLOT && canDecompose(stack) }, - { slot: Int, _: Int, _: ItemStack -> slot != INPUT_SLOT }) + container.handler(object : MatteryContainerFilter { + override fun canInsert(slot: Int, stack: ItemStack): Boolean { + return slot == INPUT_SLOT && canDecompose(stack) + } + + override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { + return slot != INPUT_SLOT + } + }) } override val defaultDisplayName: Component @@ -156,39 +184,35 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) override fun getCapability(cap: Capability, side: Direction?): LazyOptional { if (valid) { - if (cap === MatteryCapability.MATTER) return resolverMatter.cast() - if (cap === MatteryCapability.MATTER_NODE) return resolverNode.cast() - if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.cast() + if (cap == MatteryCapability.MATTER) return resolverMatter.cast() + if (cap == MatteryCapability.MATTER_NODE) return resolverNode.cast() + if (cap == ForgeCapabilities.ITEM_HANDLER) return itemHandler.cast() } return super.getCapability(cap, side) } - override fun onJobFinish(job: WorkerJob): WorkerJobStatus { - var matterValue = ImpreciseFraction.deserializeNBT(job.data["value"]) + override fun onJobFinish(job: DecomposerJob): Status { + if (job.toDust) { + job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING) - if (job.data.getBoolean("to_dust")) { - matterValue = moveMatterAsDustIntoContainer(matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING) - - if (!matterValue.isZero) { - job.data["value"] = matterValue.serializeNBT() - return WorkerJobStatus(20) + if (!job.matterValue.isZero) { + return Status.FAILURE_WAIT_FAST } - return WorkerJobStatus() + return Status.SUCCESS } - matterValue -= matter.receiveMatterInner(matterValue, false) + job.matterValue -= matter.receiveMatterInner(job.matterValue, false) - if (matterValue.isPositive) { - job.data["value"] = matterValue.serializeNBT() - return WorkerJobStatus(false, 20) + if (job.matterValue.isPositive) { + return Status.FAILURE_MATTER } - return WorkerJobStatus() + return Status.SUCCESS } - override fun computeNextJob(): WorkerJob? { + override fun computeNextJob(): Pair { val stack = container[INPUT_SLOT] if (!stack.isEmpty) { @@ -197,19 +221,13 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) if (canDecompose(copy)) { val matter = getMatterValue(copy) + stack.count-- - if (!matter.isZero) { - stack.count-- - - return WorkerJob(copy, matter.complexity * baselineComplexityDecomposeTicks, BASE_CONSUMPTION, CompoundTag().also { - it["to_dust"] = (level?.random?.nextDouble() ?: 1.0) <= 0.2 - it["value"] = matter.value.serializeNBT() - }) - } + return DecomposerJob((level?.random?.nextDouble() ?: 1.0) <= 0.2, matter.value, matter.complexity * baselineComplexityDecomposeTicks) to null } } - return null + return null to IdleReason.ITEM } override fun setRemoved() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt index 13c847970..e29f1a301 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt @@ -12,13 +12,10 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional -import net.minecraftforge.items.CapabilityItemHandler import ru.dbotthepony.mc.otm.TranslatableComponent -import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerTickContext +import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler @@ -30,26 +27,26 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph -import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.item.MatterDustItem +import ru.dbotthepony.mc.otm.map import ru.dbotthepony.mc.otm.menu.MatterRecyclerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.set class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) - : MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState), IMatterGraphNode { + : MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, ::Job), IMatterGraphNode { val matter = MatterHandlerImpl( - this::setChangedLight, + this::matterLevelUpdated, MatterDirection.EXTRACT, STORAGE ) - val container = MatteryContainer(this::setChangedLight, 1) + val container = MatteryContainer(this::itemContainerUpdated, 1) override val matterNode = Graph6Node(this) private var resolverNode = LazyOptional.of { this } private var valid = true - override val energy = WorkerEnergyStorage(this, MAX_POWER) + override val energy = WorkerEnergyStorage(this::powerLevelUpdated, MAX_POWER) override fun getMatterHandler(): IMatterHandler { return matter @@ -99,7 +96,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) override fun load(nbt: CompoundTag) { super.load(nbt) - nbt.ifHas("matter", CompoundTag::class.java, matter::deserializeNBT) + nbt.map("matter", matter::deserializeNBT) container.deserializeNBT(nbt["container"]) } @@ -107,15 +104,12 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) if (!valid) return super.getCapability(cap, side) - if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { - return itemHandler.get().cast() - } else if (cap === MatteryCapability.MATTER) { - return matter.get().cast() - } else if (cap === MatteryCapability.MATTER_NODE) { - return resolverNode.cast() + return when (cap) { + ForgeCapabilities.ITEM_HANDLER -> itemHandler.get().cast() + MatteryCapability.MATTER -> matter.get().cast() + MatteryCapability.MATTER_NODE -> resolverNode.cast() + else -> super.getCapability(cap, side) } - - return super.getCapability(cap, side) } override val defaultDisplayName: Component @@ -125,41 +119,39 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) return MatterRecyclerMenu(containerID, inventory, this) } - override fun onJobFinish(job: WorkerJob): WorkerJobStatus { + override fun onJobFinish(job: Job): Status { // вся логика в onWorkTick - return WorkerJobStatus() + return Status.SUCCESS } - override fun computeNextJob(): WorkerJob? { + override fun computeNextJob(): Pair { if (matter.missingMatter.isZero) - return null + return null to IdleReason.ITEM val stack = container[0] if (stack.isEmpty || stack.item !is MatterDustItem) { - return null + return null to IdleReason.ITEM } - val copy = stack.copy() - copy.count = 1 - - val dustMatter = (stack.item as MatterDustItem).getMatterValue(copy) ?: return null + val dustMatter = (stack.item as MatterDustItem).getMatterValue(stack.copy().also { it.count = 1 }) ?: return null to IdleReason.ITEM stack.shrink(1) - return WorkerJob(copy, dustMatter.value.toDouble() * MATTER_TICKS, POWER_CONSUMPTION) + container.setChanged(0) + return Job(dustMatter.value.toDouble() * MATTER_TICKS, POWER_CONSUMPTION) to null } - override fun onWorkTick(context: WorkerTickContext): WorkerJobStatus { + override fun onWorkTick(requiredPower: ImpreciseFraction, extractedPower: ImpreciseFraction, ticksAdvanced: Double): Status { if ((level?.random?.nextDouble() ?: 1.0) <= 0.4) - return WorkerJobStatus() + return Status.SUCCESS - val receive = if (context.ticksAdvanced == 1.0) MATTER_PER_TICK else MATTER_PER_TICK * context.ticksAdvanced + val receive = MATTER_PER_TICK * ticksAdvanced val received = matter.receiveMatterInner(receive, true) if (receive != received) - return WorkerJobStatus(false, 20) + return Status.FAILURE_MATTER matter.receiveMatterInner(receive, false) - return WorkerJobStatus() + return Status.SUCCESS } fun tick() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index bdcdc5286..c7eec86c1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -8,26 +8,25 @@ import net.minecraft.server.level.ServerLevel import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional -import net.minecraftforge.items.CapabilityItemHandler import ru.dbotthepony.mc.otm.TranslatableComponent -import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerTickContext +import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainerFilterOnlyOut import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.getImpreciseFraction import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph -import ru.dbotthepony.mc.otm.ifHas +import ru.dbotthepony.mc.otm.map import ru.dbotthepony.mc.otm.matter.baselineComplexityReplicateTicks import ru.dbotthepony.mc.otm.matter.getMatterValue import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu @@ -35,22 +34,51 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.set class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryWorkerBlockEntity(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_), IMatterGraphNode { + MatteryWorkerBlockEntity(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_, ::ReplicatorJob), IMatterGraphNode { - override val energy = WorkerEnergyStorage(this, STORAGE, MAX_IO) + class ReplicatorJob : ItemJob { + val matterPerTick: ImpreciseFraction + val task: MatterTask + var matterValue: ImpreciseFraction + val pattern: PatternState? + val asDust: Boolean + + constructor(tag: CompoundTag) : super(tag) { + matterPerTick = tag.getImpreciseFraction("matter_per_tick") + matterValue = tag.getImpreciseFraction("value") + pattern = tag.map("pattern", PatternState::deserializeNBT) + asDust = tag.getBoolean("as_dust") + task = tag.map("task", MatterTask::deserializeNBT) ?: throw NullPointerException("Unable to deserialize matter task") + } + + constructor( + itemStack: ItemStack, + matterPerTick: ImpreciseFraction, + task: MatterTask, + matterValue: ImpreciseFraction, + pattern: PatternState?, + asDust: Boolean, + ticks: Double, + ) : super(itemStack, ticks, BASE_CONSUMPTION) { + this.matterPerTick = matterPerTick + this.task = task + this.matterValue = matterValue + this.pattern = pattern + this.asDust = asDust + } + } + + override val energy = WorkerEnergyStorage(this::powerLevelUpdated, STORAGE, MAX_IO) override val matterNode = Graph6Node(this) private val resolverNode = LazyOptional.of { this } - @JvmField val matter = MatterHandlerImpl( - this::setChangedLight, + this::matterLevelUpdated, MatterDirection.RECEIVE, ImpreciseFraction(2) ) - // обычные запросы - @JvmField - val container = MatteryContainer(this::setChangedLight, 5) + val container = MatteryContainer(this::itemContainerUpdated, 5) private val itemHandler = container.handler(MatteryContainerFilterOnlyOut) override val defaultDisplayName: Component @@ -60,38 +88,42 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : return MatterReplicatorMenu(containerID, inventory, this) } - override fun onJobFinish(job: WorkerJob): WorkerJobStatus { - if (job.data.getBoolean("as_dust")) { - val matterValue = moveMatterAsDustIntoContainer(ImpreciseFraction.deserializeNBT(job["matter"]), container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING) + override fun onJobFinish(job: ReplicatorJob): Status { + if (job.asDust) { + job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING) - if (!matterValue.isZero) { - job["matter"] = matterValue.serializeNBT() - return WorkerJobStatus(false, 20) + if (!job.matterValue.isZero) { + return Status.FAILURE_WAIT } - (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(MatterTask.deserializeNBT(job["task"])!!) - - return WorkerJobStatus() + (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task) + return Status.SUCCESS } - if (!container.fullyAddItem(job.stack, FIRST_ACTUAL_OUTPUT_SLOT .. LAST_ACTUAL_OUTPUT_SLOT)) { - return WorkerJobStatus(false, 20) + if (!container.fullyAddItem(job.itemStack, FIRST_ACTUAL_OUTPUT_SLOT .. LAST_ACTUAL_OUTPUT_SLOT)) { + return Status.FAILURE_ITEM } - (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(MatterTask.deserializeNBT(job["task"])!!) - return WorkerJobStatus() + (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task) + return Status.SUCCESS } override fun onMatterTaskCreated(task: MatterTask) { - isIdling = false + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } } override fun onMatterTaskUpdated(new_state: MatterTask, old_state: MatterTask) { - isIdling = false + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } } override fun onPatternAdded(state: PatternState) { - isIdling = false + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } } override fun setRemoved() { @@ -106,33 +138,31 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatterNetworkGraph.discoverFull(this, matterNode) } - override fun computeNextJob(): WorkerJob? { - val graph = matterNode.graph as MatterNetworkGraph? ?: return null - val allocation = graph.allocateTask(false) ?: return null + override fun computeNextJob(): Pair { + val graph = matterNode.graph as MatterNetworkGraph? ?: return null to null + val allocation = graph.allocateTask(simulate = false) ?: return null to IdleReason.OBSERVING val stack = allocation.task.stack(1) val matter = getMatterValue(stack) // ???????? - if (matter.isZero) return null + if (matter.isZero) return null to null val ticks = matter.complexity * baselineComplexityReplicateTicks - return WorkerJob(stack, ticks, BASE_CONSUMPTION, CompoundTag().also { - it["matter_per_tick"] = (matter.value / ticks).serializeNBT() - it["task"] = allocation.task.serializeNBT() - it["matter"] = matter.value.serializeNBT() - - if (allocation.pattern != null) - it["pattern"] = allocation.pattern.serializeNBT() - - if ((level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.research ?: 2.0)) - it["as_dust"] = true - }) + return ReplicatorJob( + itemStack = stack, + matterPerTick = matter.value / ticks, + task = allocation.task, + matterValue = matter.value, + pattern = allocation.pattern, + asDust = (level?.random?.nextDouble() ?: 1.0) > (allocation.pattern?.research ?: 2.0), + ticks = ticks, + ) to null } - override fun onWorkTick(context: WorkerTickContext): WorkerJobStatus { - val drainPerTick = ImpreciseFraction.deserializeNBT(context.job.data["matter_per_tick"]) - val graph = matterNode.graph as MatterNetworkGraph? ?: return WorkerJobStatus(false, 20) + override fun onWorkTick(requiredPower: ImpreciseFraction, extractedPower: ImpreciseFraction, ticksAdvanced: Double): Status { + val drainPerTick = currentJob!!.matterPerTick * ticksAdvanced + val graph = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT_FAST if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) { // в машине недостаточно материи @@ -142,44 +172,42 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : val toExtract = drainPerTick - matter.extractMatterInner(drainPerTick, true) val drain = graph.extractMatter(toExtract, true) - if (drain < toExtract) { + if (drain != toExtract) { // недостаточно материи в сети - return WorkerJobStatus(false, 200) + return Status.FAILURE_MATTER } // достаточно материи в сети + внутри машины matter.extractMatterInner(drainPerTick, false) graph.extractMatter(drain, false) - return WorkerJobStatus() + return Status.SUCCESS } else { // в тик требуется меньше материи, чем её может хранить репликатор // примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше - val toExtract = - matter.missingMatter.coerceAtMost(drainPerTick.times(DRAIN_MULT)) - - val drain = graph.extractMatter(toExtract, true) + val drain = graph.extractMatter(matter.missingMatter.coerceAtMost(drainPerTick * DRAIN_MULT), true) if (drain.isZero) { // в сети нет материи - return WorkerJobStatus(false, 200) + return Status.FAILURE_MATTER } val received = matter.receiveMatterOuter(drain, false) graph.extractMatter(received, false) // получили материю, проверяем возможность работы - if (matter.extractMatterInner(drainPerTick, false) >= drainPerTick) { - return WorkerJobStatus() + if (matter.extractMatterInner(drainPerTick, true) >= drainPerTick) { + matter.extractMatterInner(drainPerTick, false) + return Status.SUCCESS } else { // :( - return WorkerJobStatus(false, 200) + return Status.FAILURE_WAIT } } } // в машине достаточно материи matter.extractMatterInner(drainPerTick, false) - return WorkerJobStatus() + return Status.SUCCESS } override fun saveAdditional(nbt: CompoundTag) { @@ -191,10 +219,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun load(nbt: CompoundTag) { super.load(nbt) container.deserializeNBT(nbt["container"]) - - nbt.ifHas("matter", CompoundTag::class.java) { - matter.deserializeNBT(it) - } + nbt.map("matter", matter::deserializeNBT) } private var valid = true @@ -213,8 +238,8 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun getCapability(cap: Capability, side: Direction?): LazyOptional { if (valid) { - if (cap === MatteryCapability.MATTER_NODE) return resolverNode.cast() - if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.get().cast() + if (cap == MatteryCapability.MATTER_NODE) return resolverNode.cast() + if (cap == ForgeCapabilities.ITEM_HANDLER) return itemHandler.get().cast() } return super.getCapability(cap, side) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index 020e67d48..6ef44800b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -12,16 +12,16 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.items.CapabilityItemHandler import ru.dbotthepony.mc.otm.TranslatableComponent -import ru.dbotthepony.mc.otm.block.entity.worker.MatteryWorkerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJob -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerJobStatus +import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.MatteryContainerFilter import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode @@ -32,26 +32,38 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities import java.util.* class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryWorkerBlockEntity(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_), IMatterGraphNode { + MatteryWorkerBlockEntity(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::ItemJob), IMatterGraphNode { - val container = MatteryContainer(this::setChanged, 1) - override val energy = WorkerEnergyStorage(this, STORAGE, MAX_IO) - private val itemHandler = container.handler( - { _: Int, stack: ItemStack -> canDecompose(stack) }, - { _: Int, _: Int, _: ItemStack -> isIdling } - ) + val container = MatteryContainer(this::itemContainerUpdated, 1) + override val energy = WorkerEnergyStorage(this::powerLevelUpdated, STORAGE, MAX_IO) + + private val itemHandler = container.handler(object : MatteryContainerFilter { + override fun canInsert(slot: Int, stack: ItemStack): Boolean { + return canDecompose(stack) + } + + override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { + return isIdling + } + }) // IMatterGraphNode override fun onPatternAdded(state: PatternState) { - isIdling = false + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } } override fun onPatternRemoved(state: PatternState) { - isIdling = false + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } } override fun onPatternUpdated(new_state: PatternState, old_state: PatternState) { - isIdling = false + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } } // /IMatterGraphNode @@ -61,7 +73,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun getCapability(cap: Capability, side: Direction?): LazyOptional { if (valid) { - if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return itemHandler.get().cast() + if (cap == ForgeCapabilities.ITEM_HANDLER) return itemHandler.get().cast() if (cap == MatteryCapability.MATTER_NODE) return resolverNode.cast() } @@ -105,11 +117,11 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : super.load(nbt) } - override fun onJobFinish(job: WorkerJob): WorkerJobStatus { - val grid = matterNode.graph as MatterNetworkGraph? ?: return WorkerJobStatus(false, 100) + override fun onJobFinish(job: ItemJob): Status { + val grid = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT - val stack = job.stack - if (stack.isEmpty || !hasMatterValue(stack)) return WorkerJobStatus() + val stack = job.itemStack + if (stack.isEmpty || !hasMatterValue(stack)) return Status.SUCCESS val getState = grid.findPatterns(stack.item) var findState: PatternState? = null @@ -132,17 +144,21 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } if (!grid.insertPattern(new, onlyUpdate = false, simulate = false).isFailed) { - return WorkerJobStatus() + return Status.SUCCESS } else { - return WorkerJobStatus(false, 200) + return Status.FAILURE_WAIT } } - override fun computeNextJob(): WorkerJob? { - val grid = matterNode.graph as MatterNetworkGraph? ?: return null + override fun computeNextJob(): Pair { + if (energy.batteryLevel.isZero) { + return null to IdleReason.POWER + } + + val grid = matterNode.graph as MatterNetworkGraph? ?: return null to null val stack = container.getItem(0) - if (stack.isEmpty || !canDecompose(stack)) return null + if (stack.isEmpty || !canDecompose(stack)) return null to IdleReason.ITEM val getState = grid.findPatterns(stack.item) var findState: PatternState? = null @@ -151,7 +167,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : if (state.item === stack.item && state.research < 1.0) { findState = state } else if (state.item === stack.item && state.research >= 1.0) { - return null + return null to IdleReason.OBSERVING } } @@ -163,14 +179,13 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } if (!grid.insertPattern(new, onlyUpdate = false, simulate = true).isFailed) { - val copy = stack.copy() - copy.count = 1 + val copy = stack.copy().also { it.count = 1 } stack.shrink(1) container.setChanged() - return WorkerJob(copy, getMatterValue(copy).complexity * baselineComplexityScanTicks, BASE_CONSUMPTION) + return ItemJob(copy, getMatterValue(copy).complexity * baselineComplexityScanTicks, BASE_CONSUMPTION) to null } - return null + return null to IdleReason.ITEM } override fun setLevel(p_155231_: Level) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt index eb83c3295..a1075a2e6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt @@ -14,7 +14,7 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.TranslatableComponent import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.block.storage.DriveViewerBlock -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.container.MatteryContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/MatteryWorkerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/MatteryWorkerBlockEntity.kt deleted file mode 100644 index bb3991c28..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/MatteryWorkerBlockEntity.kt +++ /dev/null @@ -1,261 +0,0 @@ -package ru.dbotthepony.mc.otm.block.entity.worker - -import net.minecraft.world.level.block.entity.BlockEntityType -import net.minecraft.core.BlockPos -import net.minecraft.world.level.block.state.BlockState -import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.DoubleTag -import net.minecraft.world.level.block.Block -import ru.dbotthepony.mc.otm.core.ImpreciseFraction -import ru.dbotthepony.mc.otm.core.weakGreaterOrEqual -import ru.dbotthepony.mc.otm.core.weakLessThan -import ru.dbotthepony.mc.otm.ifHas -import ru.dbotthepony.mc.otm.set - -abstract class MatteryWorkerBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : - MatteryPoweredBlockEntity(p_155228_, p_155229_, p_155230_) { - var workTicks = 0.0 - protected set - - var throttleTicks = 0 - protected set - - var currentJob: WorkerJob? = null - protected set - - // если isIdling То ничего не делать - // isIdling должна быть выставлена в true если что то изменилось, что могло создать работу - var isIdling = false - protected set - - val isUnableToProcess: Boolean get() = throttleTicks > 0 - - val workProgress: Float - get() { - val currentJob = currentJob ?: return 0.0f - return (workTicks / currentJob.ticks).coerceAtMost(1.0).toFloat() - } - - override fun saveAdditional(nbt: CompoundTag) { - super.saveAdditional(nbt) - nbt["work_ticks"] = workTicks - currentJob?.let { nbt["current_job"] = it.serializeNBT() } - } - - override fun load(nbt: CompoundTag) { - super.load(nbt) - - nbt.ifHas("work_ticks", DoubleTag::class.java) { - workTicks = it.asDouble - } - - currentJob = WorkerJob.deserializeNBT(nbt["current_job"]) - - if (currentJob == null) - workTicks = 0.0 - } - - override fun setChanged() { - super.setChanged() - isIdling = false - } - - override fun setChangedLight() { - super.setChangedLight() - isIdling = false - } - - /** - * @param job current job - * @return whenever machine can finish it's job. return false if machine for whatever reason can't finish it's job, - * waiting on conditions to be met - */ - protected abstract fun onJobFinish(job: WorkerJob): WorkerJobStatus - - /** - * @param context context for current job - * @return whenever machine can perform it - */ - protected open fun onWorkTick(context: WorkerTickContext): WorkerJobStatus { - return WorkerJobStatus() - } - - private var idleTicksAnim = 0 - private var workingTicksAnim = 0 - private var errorTicksAnim = 0 - - override fun redstoneStatusUpdated(new_blocked: Boolean, old_blocked: Boolean) { - super.redstoneStatusUpdated(new_blocked, old_blocked) - isIdling = new_blocked - } - - protected fun workerLoop() { - if (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) - } - - if (throttleTicks > 0) { - workingTicksAnim = 0 - idleTicksAnim = 0 - throttleTicks-- - errorTicksAnim++ - - if (throttleTicks > 0) - return - } - - if (isIdling) { - workingTicksAnim = 0 - errorTicksAnim = 0 - idleTicksAnim++ - - if (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) - } - - return - } - - var currentJob = currentJob - - if (currentJob == null) { - if (isBlockedByRedstone) { - isIdling = true - return - } - - val input = computeNextJob() - - if (input == null) { - isIdling = true - workingTicksAnim = 0 - return - } - - this.currentJob = input - currentJob = input - } - - if (isBlockedByRedstone) { - isIdling = true - return - } - - if (!currentJob.power.isZero && energy.batteryLevel.isZero) { - idleTicksAnim++ - - if (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) - } - - return - } - - idleTicksAnim = 0 - - if (weakLessThan(workTicks, currentJob.ticks)) { - if (!currentJob.power.isZero) { - // сколько осталось тиков работать - val ticksLeft = currentJob.ticks - workTicks - val requiredPower: ImpreciseFraction - - // запрос энергии на то количество, сколько действительно осталось работать - if (ticksLeft > 1.0) { - requiredPower = currentJob.power - } else { - requiredPower = currentJob.power * ticksLeft - } - - val extractedPower = if (requiredPower.isZero) ImpreciseFraction.ZERO else energy.extractEnergyInner(requiredPower, true) - - // сколько тиков мы "проработали" - // может быть меньше, чем единица, если недостаточно питания или мы завершаем работу, - // для которой осталось дробное количество тиков - val ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceAtMost(ticksLeft) - val ticksAdvancedWeak = if (requiredPower.isZero) 1.0 else ticksAdvanced - val status = onWorkTick(WorkerTickContext(currentJob, requiredPower, extractedPower, ticksAdvanced)) - - if (!status.valid) { - throttleTicks += status.throttle - return - } - - workingTicksAnim++ - errorTicksAnim = 0 - - val updatedWorkTicks = (workTicks + ticksAdvancedWeak).coerceAtMost(currentJob.ticks) - - if (weakGreaterOrEqual(updatedWorkTicks, currentJob.ticks)) { - workTicks = currentJob.ticks - energy.extractEnergyInner(extractedPower * (1.0 - (updatedWorkTicks - currentJob.ticks)), false) - - val finish = onJobFinish(currentJob) - - if (finish.valid) { - this.currentJob = null - workTicks = 0.0 - } else { - throttleTicks += finish.throttle - } - } else { - workTicks = updatedWorkTicks - energy.extractEnergyInner(extractedPower, false) - } - } else { - val ticksLeft = (currentJob.ticks - workTicks).coerceAtMost(1.0) - val status = onWorkTick(WorkerTickContext(currentJob, ImpreciseFraction.ZERO, ImpreciseFraction.ZERO, ticksLeft)) - - if (!status.valid) { - throttleTicks += status.throttle - return - } - - workingTicksAnim++ - errorTicksAnim = 0 - workTicks = (workTicks + 1.0).coerceAtMost(currentJob.ticks) - - if (weakGreaterOrEqual(workTicks, currentJob.ticks)) { - val finish = onJobFinish(currentJob) - - if (finish.valid) { - this.currentJob = null - workTicks = 0.0 - } else { - throttleTicks += finish.throttle - } - } - } - } else { - val finish = onJobFinish(currentJob) - - if (finish.valid) { - this.currentJob = null - workTicks = 0.0 - errorTicksAnim = 0 - } else { - throttleTicks += finish.throttle - errorTicksAnim++ - } - } - - if (workingTicksAnim > 20 && - errorTicksAnim == 0 && - 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) - } - } - - /** - * Determine which item can be processed from input slots if idling - * @return any item in input slots. null if no work is available - */ - protected abstract fun computeNextJob(): WorkerJob? - - fun basicTicker() { - batteryChargeLoop() - workerLoop() - } -} \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/WorkerLogic.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/WorkerLogic.kt deleted file mode 100644 index 87c73438d..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/WorkerLogic.kt +++ /dev/null @@ -1,85 +0,0 @@ -package ru.dbotthepony.mc.otm.block.entity.worker - -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.DoubleTag -import net.minecraft.nbt.Tag -import net.minecraft.util.StringRepresentable -import net.minecraft.world.item.ItemStack -import net.minecraft.world.level.block.state.properties.EnumProperty -import ru.dbotthepony.mc.otm.core.ImpreciseFraction -import ru.dbotthepony.mc.otm.set - -@JvmRecord -data class WorkerTickContext( - val job: WorkerJob, - val requiredPower: ImpreciseFraction, - val extractedPower: ImpreciseFraction, - val ticksAdvanced: Double -) - -enum class WorkerState : StringRepresentable { - IDLE, - WORKING, - ERROR; - - companion object { - @JvmField - val WORKER_STATE: EnumProperty = EnumProperty.create("worker", WorkerState::class.java) - @JvmField - val SEMI_WORKER_STATE: EnumProperty = EnumProperty.create("worker", WorkerState::class.java, IDLE, WORKING) - } - - override fun getSerializedName(): String { - return if (this == IDLE) "idle" else if (this == WORKING) "working" else "error" - } -} - -@JvmRecord -data class WorkerJobStatus @JvmOverloads constructor(val valid: Boolean = true, val throttle: Int = 0) { - constructor(throttle: Int) : this(false, throttle) -} - -@JvmRecord -data class WorkerJob @JvmOverloads constructor( - val stack: ItemStack, - val ticks: Double, - val power: ImpreciseFraction = ImpreciseFraction.ZERO, - val data: CompoundTag = CompoundTag()) { - - fun serializeNBT(): CompoundTag { - return CompoundTag().also { - it["stack"] = stack.serializeNBT() - it["ticks"] = ticks - it["power"] = power.serializeNBT() - it["data"] = data - } - } - - operator fun get(index: String) = data[index] - operator fun set(index: String, value: Tag) { data[index] = value } - operator fun set(index: String, value: Int) { data[index] = value } - operator fun set(index: String, value: Byte) { data[index] = value } - operator fun set(index: String, value: Short) { data[index] = value } - operator fun set(index: String, value: Long) { data[index] = value } - operator fun set(index: String, value: Float) { data[index] = value } - operator fun set(index: String, value: Double) { data[index] = value } - operator fun set(index: String, value: String) { data[index] = value } - operator fun set(index: String, value: Boolean) { data[index] = value } - operator fun set(index: String, value: ByteArray) { data[index] = value } - operator fun set(index: String, value: IntArray) { data[index] = value } - operator fun set(index: String, value: LongArray) { data[index] = value } - - companion object { - @JvmStatic - fun deserializeNBT(tag: Tag?): WorkerJob? { - val nbt = tag as? CompoundTag ?: return null - - return WorkerJob( - ItemStack.of(nbt["stack"] as? CompoundTag ?: return null), - (nbt["ticks"] as? DoubleTag ?: return null).asDouble, - ImpreciseFraction.deserializeNBT(nbt["power"]), - nbt["data"] as? CompoundTag ?: return null - ) - } - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterBottlerBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterBottlerBlock.kt index 3ce941a6b..e6542499d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterBottlerBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterBottlerBlock.kt @@ -19,7 +19,7 @@ import net.minecraft.world.level.block.state.properties.BooleanProperty import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterDecomposerBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterDecomposerBlock.kt index 992109b78..faf3065c4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterDecomposerBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterDecomposerBlock.kt @@ -17,7 +17,7 @@ import net.minecraft.world.level.block.Block import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterRecyclerBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterRecyclerBlock.kt index 276657139..d8c99395a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterRecyclerBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterRecyclerBlock.kt @@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterReplicatorBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterReplicatorBlock.kt index 9d3fed1d3..1d15fbbc6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterReplicatorBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterReplicatorBlock.kt @@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.entity.matter.MatterReplicatorBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterScannerBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterScannerBlock.kt index f58763a77..51b3a72c3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterScannerBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/matter/MatterScannerBlock.kt @@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.entity.matter.MatterScannerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/storage/DriveViewerBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/storage/DriveViewerBlock.kt index a3a815d1c..f0776f5b8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/storage/DriveViewerBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/storage/DriveViewerBlock.kt @@ -17,7 +17,7 @@ import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.entity.storage.DriveViewerBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/GravitationStabilizerRenderer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/GravitationStabilizerRenderer.kt index ab12d926a..f4f2e2429 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/GravitationStabilizerRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/GravitationStabilizerRenderer.kt @@ -15,7 +15,7 @@ import ru.dbotthepony.mc.otm.block.BlackHoleBlock import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock import ru.dbotthepony.mc.otm.block.entity.GravitationStabilizerBlockEntity import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity -import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState +import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.client.render.* import ru.dbotthepony.mc.otm.core.* import kotlin.math.PI diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt index fe3c159c2..b045dde31 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt @@ -1,6 +1,7 @@ package ru.dbotthepony.mc.otm.core import net.minecraft.nbt.ByteArrayTag +import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.StringTag import net.minecraft.nbt.Tag import net.minecraft.network.FriendlyByteBuf @@ -660,3 +661,8 @@ fun OutputStream.writeImpreciseFraction(value: ImpreciseFraction) { write(bytes) writeDouble(value.decimal) } + +fun CompoundTag.getImpreciseFraction(key: String) = ImpreciseFraction.deserializeNBT(this[key]) +fun CompoundTag.putImpreciseFraction(key: String, value: ImpreciseFraction) = put(key, value.serializeNBT()) + +operator fun CompoundTag.set(key: String, value: ImpreciseFraction) = putImpreciseFraction(key, value)