From 3e66862de8ffd169e2321fd01444aa04bac790a4 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 14 May 2022 18:38:30 +0700 Subject: [PATCH] Storage import bus --- .../ru/dbotthepony/mc/otm/datagen/DataGen.kt | 1 + .../mc/otm/block/StorageInterfaces.kt | 59 ++++++++ .../mc/otm/block/entity/StorageInterfaces.kt | 137 ++++++++++++++++++ .../ru/dbotthepony/mc/otm/graph/Graph6Node.kt | 3 +- .../mc/otm/registry/MBlockEntities.kt | 1 + .../ru/dbotthepony/mc/otm/registry/MBlocks.kt | 2 + .../ru/dbotthepony/mc/otm/registry/MItems.kt | 1 + .../ru/dbotthepony/mc/otm/registry/MNames.kt | 3 + .../overdrive_that_matters/lang/en_us.json | 1 + 9 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageInterfaces.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt 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 0722ba944..057753da3 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt @@ -361,6 +361,7 @@ object DataGen { tile(MBlocks.DRIVE_VIEWER, TileNbtCopy("energy"), TileNbtCopy("container"), TileNbtCopy("battery_container")) tile(MBlocks.STORAGE_BUS, TileNbtCopy("energy"), TileNbtCopy("battery_container")) + tile(MBlocks.STORAGE_IMPORTER, TileNbtCopy("energy"), TileNbtCopy("battery_container")) tile(MBlocks.STORAGE_POWER_SUPPLIER, TileNbtCopy("energy"), TileNbtCopy("battery_container"), TileNbtCopy("power_supplied")) tile(MBlocks.MATTER_DECOMPOSER, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageInterfaces.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageInterfaces.kt new file mode 100644 index 000000000..f79cc290c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageInterfaces.kt @@ -0,0 +1,59 @@ +package ru.dbotthepony.mc.otm.block + +import net.minecraft.core.BlockPos +import net.minecraft.world.item.context.BlockPlaceContext +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.EntityBlock +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.entity.BlockEntityTicker +import net.minecraft.world.level.block.entity.BlockEntityType +import net.minecraft.world.level.block.state.BlockState +import ru.dbotthepony.mc.otm.addPreWorldTickerOnce +import ru.dbotthepony.mc.otm.block.entity.StorageImporterBlockEntity +import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.unaryMinus + +class StorageImporterBlock : RotatableMatteryBlock(), EntityBlock { + override val hasFreeRotation: Boolean get() = true + + override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity { + return StorageImporterBlockEntity(p_153215_, p_153216_) + } + + override fun getTicker( + p_153212_: Level, + p_153213_: BlockState, + p_153214_: BlockEntityType + ): BlockEntityTicker? { + if (p_153212_.isClientSide || p_153214_ !== MBlockEntities.STORAGE_IMPORTER) + return null + + return BlockEntityTicker { _, _, _, tile -> if (tile is StorageImporterBlockEntity) tile.tick() } + } + + override fun getStateForPlacement(context: BlockPlaceContext): BlockState? { + return super.getStateForPlacement(context)?.setValue(FACING_FULL, -context.clickedFace) + } + + override fun neighborChanged( + state: BlockState, + level: Level, + pos: BlockPos, + sender: Block, + sender_pos: BlockPos, + flag: Boolean + ) { + super.neighborChanged(state, level, pos, sender, sender_pos, flag) + + if (!level.isClientSide) { + val tile = level.getBlockEntity(pos) + + if (tile is StorageImporterBlockEntity) { + addPreWorldTickerOnce(level) { + tile.checkSurroundings() + } + } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt new file mode 100644 index 000000000..a151a3daa --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt @@ -0,0 +1,137 @@ +package ru.dbotthepony.mc.otm.block.entity + +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.TranslatableComponent +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.level.Level +import net.minecraft.world.level.block.state.BlockState +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.LazyOptional +import net.minecraftforge.items.CapabilityItemHandler +import net.minecraftforge.items.IItemHandler +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage +import ru.dbotthepony.mc.otm.capability.extractStepInner +import ru.dbotthepony.mc.otm.core.plus +import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode +import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.orThrow +import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.storage.ItemStackWrapper +import ru.dbotthepony.mc.otm.unaryMinus + +class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_IMPORTER, blockPos, blockState) { + override val defaultDisplayName: Component + get() = MACHINE_NAME + + override val energy = WorkerEnergyStorage(this) + val cell = BasicStorageGraphNode(energy) + + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? { + return null + } + + private var valid = true + + override fun getCapability(cap: Capability, side: Direction?): LazyOptional { + return if (valid && cap === MatteryCapability.STORAGE_NODE) { + cell.get().cast() + } else super.getCapability(cap, side) + } + + override fun invalidateCaps() { + super.invalidateCaps() + cell.invalidate() + valid = false + } + + override fun reviveCaps() { + super.reviveCaps() + cell.revive() + valid = true + } + + private var target: LazyOptional = LazyOptional.empty() + private var lastSlot = 0 + private var nextTick = INTERVAL + + private val enoughEnergy get() = energy.batteryLevel >= OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation + + override fun setRemoved() { + super.setRemoved() + cell.destroy(level) + valid = false + } + + override fun setLevel(p_155231_: Level) { + super.setLevel(p_155231_) + + if (p_155231_ is ServerLevel) { + StorageNetworkGraph.discoverFull(this, cell.storageNode) + } + + tickOnceServer(this::checkSurroundings) + } + + fun tick() { + batteryChargeLoop() + cell.tickEnergyDemanding() + + nextTick-- + + if (nextTick <= 0 && target.isPresent && enoughEnergy) { + val graph = cell.storageGraph ?: return + val items = graph.getVirtualComponent(OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) + + val resolved = target.orThrow() + + if (lastSlot >= resolved.slots) { + lastSlot = 0 + } + + val maxMove = energy.extractStepInner(OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation, MAX_MOVE_PER_OPERATION, true) + var extracted = resolved.extractItem(lastSlot, maxMove, true) + + if (extracted.isEmpty) { + lastSlot++ + } else { + val leftOver = items.insertStack(ItemStackWrapper(extracted), true) + + if (leftOver.count.toInt() != extracted.count) { + extracted = resolved.extractItem(lastSlot, extracted.count - leftOver.count.toInt(), false) + energy.extractStepInner(OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation, extracted.count, false) + items.insertStack(ItemStackWrapper(extracted), false) + } else { + nextTick += INTERVAL * 4 + } + } + } + + if (nextTick <= 0) { + nextTick = INTERVAL + } + } + + fun checkSurroundings() { + target = getAndBind( + target, + level?.getBlockEntity(blockPos + blockState.getValue(RotatableMatteryBlock.FACING_FULL).normal), + CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, + -blockState.getValue(RotatableMatteryBlock.FACING_FULL), + ) { tickOnceServer(this::checkSurroundings) } + } + + companion object { + private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_IMPORTER}") + private const val INTERVAL = 5 + private const val MAX_MOVE_PER_OPERATION = 4 + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt index 00b296d69..067202a83 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.graph import net.minecraft.core.Direction import ru.dbotthepony.mc.otm.IConditionalTickable import ru.dbotthepony.mc.otm.ITickable +import ru.dbotthepony.mc.otm.SERVER_IS_DYING interface GraphNodeListener { fun onNeighbourTop(node: Graph6Node<*>) = onNeighbour(node, Direction.UP) @@ -264,7 +265,7 @@ class Graph6Node(@JvmField val value: T, graph: Abstract6Graph? = null) : private set fun destroy(factory: () -> Abstract6Graph): List> { - if (!valid) return emptyList() + if (!valid || SERVER_IS_DYING) return emptyList() top?.bottom = null bottom?.top = null diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt index 803948b75..a17a55460 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt @@ -41,6 +41,7 @@ object MBlockEntities { val MATTER_RECYCLER: BlockEntityType<*> by registry.register(MNames.MATTER_RECYCLER) { BlockEntityType.Builder.of(::MatterRecyclerBlockEntity, MBlocks.MATTER_RECYCLER).build(null) } val STORAGE_BUS: BlockEntityType<*> by registry.register(MNames.STORAGE_BUS) { BlockEntityType.Builder.of(::StorageBusBlockEntity, MBlocks.STORAGE_BUS).build(null) } + val STORAGE_IMPORTER: BlockEntityType<*> by registry.register(MNames.STORAGE_IMPORTER) { BlockEntityType.Builder.of(::StorageImporterBlockEntity, MBlocks.STORAGE_IMPORTER).build(null) } val STORAGE_POWER_SUPPLIER: BlockEntityType<*> by registry.register(MNames.STORAGE_POWER_SUPPLIER) { BlockEntityType.Builder.of(::StoragePowerSupplierBlockEntity, MBlocks.STORAGE_POWER_SUPPLIER).build(null) } val DEBUG_EXPLOSION_SMALL: BlockEntityType<*> by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockEntityType.Builder.of(::BlockEntityExplosionDebugger, MBlocks.DEBUG_EXPLOSION_SMALL).build(null) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt index a685bc545..e9a7424ec 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt @@ -53,6 +53,8 @@ object MBlocks { val MATTER_RECYCLER: Block by registry.register(MNames.MATTER_RECYCLER) { MatterRecyclerBlock() } val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS) { StorageBusBlock() } + val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER) { StorageImporterBlock() } + val DRIVE_VIEWER: Block by registry.register(MNames.DRIVE_VIEWER) { DriveViewerBlock() } val DRIVE_RACK: Block by registry.register(MNames.DRIVE_RACK) { DriveRackBlock() } val ITEM_MONITOR: Block by registry.register(MNames.ITEM_MONITOR) { ItemMonitorBlock() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt index 231d11d7d..a385c526f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt @@ -47,6 +47,7 @@ object MItems { val MATTER_RECYCLER: Item by registry.register(MNames.MATTER_RECYCLER) { BlockItem(MBlocks.MATTER_RECYCLER, DEFAULT_PROPERTIES) } val STORAGE_BUS: Item by registry.register(MNames.STORAGE_BUS) { BlockItem(MBlocks.STORAGE_BUS, DEFAULT_PROPERTIES) } + val STORAGE_IMPORTER: Item by registry.register(MNames.STORAGE_IMPORTER) { BlockItem(MBlocks.STORAGE_IMPORTER, DEFAULT_PROPERTIES) } val DRIVE_VIEWER: Item by registry.register(MNames.DRIVE_VIEWER) { BlockItem(MBlocks.DRIVE_VIEWER, DEFAULT_PROPERTIES) } val DRIVE_RACK: Item by registry.register(MNames.DRIVE_RACK) { BlockItem(MBlocks.DRIVE_RACK, DEFAULT_PROPERTIES) } val ITEM_MONITOR: Item by registry.register(MNames.ITEM_MONITOR) { BlockItem(MBlocks.ITEM_MONITOR, DEFAULT_PROPERTIES) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt index f24619f39..48c915ea2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt @@ -35,6 +35,9 @@ object MNames { const val CARGO_CRATE = "cargo_crate" // нужен рецепт? const val STORAGE_BUS = "storage_bus" + const val STORAGE_IMPORTER = "storage_importer" + const val STORAGE_EXPORTER = "storage_exporter" + const val STORAGE_INTERFACE = "storage_interface" // building blocks const val TRITANIUM_BLOCK = "tritanium_block" diff --git a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json index a5e84724a..3df748e1f 100644 --- a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json +++ b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json @@ -238,6 +238,7 @@ "block.overdrive_that_matters.storage_cable": "Storage Cable", "block.overdrive_that_matters.storage_power_supplier": "Storage Power Supplier", "block.overdrive_that_matters.storage_bus": "Storage Bus", + "block.overdrive_that_matters.storage_importer": "Storage Importer", "item.overdrive_that_matters.pill_android": "Android Pill", "item.overdrive_that_matters.pill_humane": "Humane Pill",