From 5f16804febcd823c1a7b0f86fb2120d33d4180eb Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 24 Mar 2023 20:25:35 +0700 Subject: [PATCH] New graph implementation --- .../mc/otm/capability/MatteryCapability.java | 12 +- .../dbotthepony/mc/otm/GlobalEventHandler.kt | 3 + .../dbotthepony/mc/otm/block/entity/Cables.kt | 136 ++--- .../entity/matter/ItemRepairerBlockEntity.kt | 35 +- .../entity/matter/MatterBottlerBlockEntity.kt | 25 +- .../matter/MatterCapacitorBankBlockEntity.kt | 21 +- .../matter/MatterDecomposerBlockEntity.kt | 44 +- .../entity/matter/MatterPanelBlockEntity.kt | 31 +- .../matter/MatterRecyclerBlockEntity.kt | 22 +- .../matter/MatterReplicatorBlockEntity.kt | 95 ++-- .../entity/matter/MatterScannerBlockEntity.kt | 71 ++- .../matter/PatternStorageBlockEntity.kt | 42 +- .../entity/storage/DriveRackBlockEntity.kt | 12 +- .../entity/storage/ItemMonitorBlockEntity.kt | 16 +- .../entity/storage/StorageBusBlockEntity.kt | 25 +- .../block/entity/storage/StorageInterfaces.kt | 34 +- .../StoragePowerSupplierBlockEntity.kt | 23 +- .../dbotthepony/mc/otm/compat/mekanism/QIO.kt | 40 +- .../dbotthepony/mc/otm/core/util/LOHolder.kt | 20 + .../mc/otm/graph/Abstract6Graph.kt | 254 +++++---- .../ru/dbotthepony/mc/otm/graph/Graph6Node.kt | 527 ++++++++---------- .../dbotthepony/mc/otm/graph/GraphFlooder.kt | 64 --- ...erGraphNode.kt => IMatterGraphListener.kt} | 10 - .../{MatterNetworkGraph.kt => MatterGraph.kt} | 127 ++--- .../mc/otm/graph/matter/MatterNode.kt | 18 + .../mc/otm/graph/matter/SimpleMatterNode.kt | 23 + .../mc/otm/graph/storage/IStorageGraphNode.kt | 22 - ...StorageNetworkGraph.kt => StorageGraph.kt} | 51 +- ...asicStorageGraphNode.kt => StorageNode.kt} | 103 ++-- .../mc/otm/menu/matter/MatterBottlerMenu.kt | 4 +- .../menu/matter/MatterCapacitorBankMenu.kt | 4 +- .../mc/otm/menu/matter/MatterPanelMenu.kt | 24 +- .../mc/otm/menu/matter/MatterRecyclerMenu.kt | 6 +- .../mc/otm/menu/matter/MatterScannerMenu.kt | 4 +- .../mc/otm/menu/matter/PatternStorageMenu.kt | 4 +- .../menu/storage/StoragePowerSupplierMenu.kt | 2 +- 36 files changed, 808 insertions(+), 1146 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LOHolder.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/graph/GraphFlooder.kt rename src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/{IMatterGraphNode.kt => IMatterGraphListener.kt} (58%) rename src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/{MatterNetworkGraph.kt => MatterGraph.kt} (64%) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterNode.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/SimpleMatterNode.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt rename src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/{StorageNetworkGraph.kt => StorageGraph.kt} (60%) rename src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/{BasicStorageGraphNode.kt => StorageNode.kt} (61%) diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java index 4b182e74a..ad3d8aeff 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java @@ -11,8 +11,8 @@ import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage; import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage; import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider; import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage; -import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode; -import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode; +import ru.dbotthepony.mc.otm.graph.matter.MatterNode; +import ru.dbotthepony.mc.otm.graph.storage.StorageNode; import top.theillusivec4.curios.api.type.capability.ICurio; import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; @@ -33,7 +33,7 @@ public class MatteryCapability { @Nonnull @NotNull - public static final Capability MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {}); + public static final Capability MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {}); @Nonnull @NotNull @@ -49,7 +49,7 @@ public class MatteryCapability { @Nonnull @NotNull - public static final Capability STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {}); + public static final Capability STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {}); @Nonnull @NotNull @@ -67,10 +67,10 @@ public class MatteryCapability { event.register(IMatteryEnergyStorage.class); event.register(MatteryPlayerCapability.class); event.register(IMatterStorage.class); - event.register(IMatterGraphNode.class); + event.register(MatterNode.class); event.register(IPatternStorage.class); event.register(IReplicationTaskProvider.class); event.register(IMatteryDrive.class); - event.register(IStorageGraphNode.class); + event.register(StorageNode.class); } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt index 0130a93d4..d52964449 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt @@ -19,6 +19,7 @@ import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.core.util.IConditionalTickable import ru.dbotthepony.mc.otm.core.util.ITickable import ru.dbotthepony.mc.otm.core.util.TickList +import ru.dbotthepony.mc.otm.graph.Abstract6Graph import java.util.* private val preServerTick = TickList() @@ -145,6 +146,8 @@ fun onServerTick(event: ServerTickEvent) { preServerTick.tick() } else { postServerTick.tick() + // чтоб не плодить кучу подписчиков, вызовем напрямую отсюда + Abstract6Graph.tick() } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Cables.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Cables.kt index 7b091594c..12d498cf7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Cables.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Cables.kt @@ -2,135 +2,81 @@ package ru.dbotthepony.mc.otm.block.entity import net.minecraft.core.BlockPos import net.minecraft.core.Direction -import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.Level import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.state.BlockState -import net.minecraftforge.common.capabilities.Capability -import net.minecraftforge.common.util.LazyOptional import ru.dbotthepony.mc.otm.SERVER_IS_LIVE import ru.dbotthepony.mc.otm.block.CableBlock import ru.dbotthepony.mc.otm.capability.MatteryCapability -import ru.dbotthepony.mc.otm.graph.Graph6Node -import ru.dbotthepony.mc.otm.graph.GraphNodeListener -import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode -import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph -import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode -import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.graph.matter.MatterNode +import ru.dbotthepony.mc.otm.graph.storage.StorageGraph +import ru.dbotthepony.mc.otm.graph.storage.StorageNode import ru.dbotthepony.mc.otm.registry.MBlockEntities -class MatterCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - BlockEntity(MBlockEntities.MATTER_CABLE, p_155229_, p_155230_), IMatterGraphNode, GraphNodeListener { +class MatterCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.MATTER_CABLE, p_155229_, p_155230_) { + val matterNode = object : MatterNode() { + override fun onNeighbour(direction: Direction) { + val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) - private var valid = true - override val matterNode = Graph6Node(this) - private val resolverNode = LazyOptional.of { this } - - override fun invalidateCaps() { - super.invalidateCaps() - valid = false - } - - override fun reviveCaps() { - super.reviveCaps() - valid = true - } - - override fun getCapability(cap: Capability, side: Direction?): LazyOptional { - if (valid) { - if (cap === MatteryCapability.MATTER_NODE) - return resolverNode.cast() + if (newState !== blockState && SERVER_IS_LIVE) + level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) } - return super.getCapability(cap, side) + override fun onUnNeighbour(direction: Direction) { + val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false) + + if (newState !== blockState && SERVER_IS_LIVE) + level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) + } } - override fun setLevel(p_155231_: Level) { - super.setLevel(p_155231_) - - if (p_155231_ is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) + init { + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) } - override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { - val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) - - if (newState !== blockState && SERVER_IS_LIVE) - level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) - } - - override fun onUnNeighbour(node: Graph6Node<*>, direction: Direction) { - val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false) - - if (newState !== blockState && SERVER_IS_LIVE) - level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) + override fun setLevel(level: Level) { + super.setLevel(level) + matterNode.discover(this) } override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } } -class StorageCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - BlockEntity(MBlockEntities.STORAGE_CABLE, p_155229_, p_155230_), IStorageGraphNode, GraphNodeListener { +class StorageCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.STORAGE_CABLE, p_155229_, p_155230_) { + val storageNode = object : StorageNode() { + override fun attachComponents(to: StorageGraph) {} + override fun removeComponents(from: StorageGraph) {} - private var valid = true - private val resolverNode = LazyOptional.of { this } + override fun onNeighbour(direction: Direction) { + val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) - override fun attachComponents(to: StorageNetworkGraph) {} - override fun removeComponents(from: StorageNetworkGraph) {} - override val storageNode = Graph6Node(this) - - override fun invalidateCaps() { - super.invalidateCaps() - valid = false - } - - override fun reviveCaps() { - super.reviveCaps() - valid = true - } - - override fun getCapability(cap: Capability, side: Direction?): LazyOptional { - if (valid) { - if (cap === MatteryCapability.STORAGE_NODE) - return resolverNode.cast() + if (newState !== blockState && SERVER_IS_LIVE) + level!!.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) } - return super.getCapability(cap, side) + override fun onUnNeighbour(direction: Direction) { + val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false) + + if (newState !== blockState && SERVER_IS_LIVE) + level!!.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) + } } - override fun setLevel(p_155231_: Level) { - super.setLevel(p_155231_) - - if (p_155231_ is ServerLevel) - StorageNetworkGraph.discoverFull(this, storageNode) + init { + exposeGlobally(MatteryCapability.STORAGE_NODE, storageNode) } - override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { - val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) - - if (newState !== blockState && SERVER_IS_LIVE) - level!!.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) - } - - override fun onUnNeighbour(node: Graph6Node<*>, direction: Direction) { - val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false) - - if (newState !== blockState && SERVER_IS_LIVE) - level!!.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) + override fun setLevel(level: Level) { + super.setLevel(level) + storageNode.discover(this) } override fun setRemoved() { super.setRemoved() - - val level = level!! - - storageNode.destroy { - StorageNetworkGraph(level) - } + storageNode.isValid = false } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/ItemRepairerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/ItemRepairerBlockEntity.kt index 4ad22dacc..625df3d54 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/ItemRepairerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/ItemRepairerBlockEntity.kt @@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter import net.minecraft.core.BlockPos import net.minecraft.nbt.StringTag import net.minecraft.resources.ResourceLocation -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 @@ -29,16 +28,16 @@ import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.util.WriteOnce -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.graph.matter.MatterGraph +import ru.dbotthepony.mc.otm.graph.matter.MatterNode +import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.matter.IMatterValue import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.menu.matter.ItemRepairerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MNames -class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ITEM_REPAIRER, blockPos, blockState), IMatterGraphNode { +class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ITEM_REPAIRER, blockPos, blockState) { val repairContainer = MatteryContainer(::containerChanged, 1).also(::addDroppableContainer) private var matterPerTick = Decimal.ZERO @@ -48,13 +47,13 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt var canNotWork = false - override val matterNode = Graph6Node(this) val matter = MatterStorageImpl(::setChangedLight, FlowDirection.INPUT, ::CAPACITY) + val matterNode = SimpleMatterNode(matter = matter) val energy = WorkerEnergyStorage(::setChangedLight, ENERGY_VALUES) init { exposeGlobally(MatteryCapability.MATTER, matter) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) savetables.stateful(::repairContainer) savetables.stateful(::matter) @@ -83,10 +82,10 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt } } - return (matterNode.graph as MatterNetworkGraph?) - ?.patterns - ?.filter { stack.item.isValidRepairItem(stack, ItemStack(it.item, 1)) } - ?.findFirst()?.orElse(null).let { + return matterNode.graph + .patterns + .filter { stack.item.isValidRepairItem(stack, ItemStack(it.item, 1)) } + .findFirst().orElse(null).let { if (it == null) { IMatterValue.ZERO } else { @@ -105,20 +104,14 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt return ItemRepairerMenu(containerID, inventory, this) } - override fun getMatterHandler(): IMatterStorage { - return matter - } - override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) + matterNode.discover(this) } private fun containerChanged() { @@ -147,7 +140,7 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt } } - val found = (matterNode.graph as MatterNetworkGraph?)?.patterns?.filter { item.item.isValidRepairItem(item, ItemStack(it.item, 1)) }?.findFirst()?.orElse(null) + val found = matterNode.graph.patterns.filter { item.item.isValidRepairItem(item, ItemStack(it.item, 1)) }.findFirst().orElse(null) if (found != null) { @Suppress("name_shadowing") @@ -187,7 +180,7 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt } if (matter.storedMatter < matterPerTick) { - val graph = matterNode.graph as MatterNetworkGraph? + val graph = matterNode.graph as MatterGraph? if (graph != null) { val toDrain = (matterPerTick * EXTRACT_TICKS.coerceAtMost(item.damageValue)).coerceAtLeast(Decimal.ZERO).coerceAtMost(matter.missingMatter) 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 697386f75..799e86601 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 @@ -22,9 +22,7 @@ import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter -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.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.core.* @@ -33,11 +31,12 @@ import ru.dbotthepony.mc.otm.core.util.WriteOnce import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.defineDecimal +import ru.dbotthepony.mc.otm.graph.matter.MatterNode +import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, p_155229_, p_155230_), IMatterGraphNode { + MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, p_155229_, p_155230_) { - override val matterNode = Graph6Node(this) val energy = WorkerEnergyStorage(this, ENERGY_VALUES) var isBottling: Boolean = true @@ -110,9 +109,11 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } } + val matterNode = SimpleMatterNode(matter = matter) + init { exposeGlobally(MatteryCapability.MATTER, matter) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) exposeItemsGlobally(itemHandler) savetables.bool(::isBottling) @@ -126,15 +127,9 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : private var initialCapacity: Decimal? = null private var lastWorkStack: ItemStack? = null - override fun getMatterHandler(): IMatterStorage { - return matter - } - override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) + matterNode.discover(this) } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { @@ -163,7 +158,7 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun tick() { @@ -212,7 +207,7 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : initialCapacity = capability!!.storedMatter } - val graph = matterNode.graph as MatterNetworkGraph? + val graph = matterNode.graph as MatterGraph? if (capability != null) { if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.WORKING) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt index 78f70be78..bc77a87fd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt @@ -1,7 +1,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter import net.minecraft.core.BlockPos -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 @@ -17,17 +16,15 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.ifPresentK -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.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities -class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterGraphNode, IMatterStorage { +class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterStorage { var gaugeLevel by synchronizer.float().property private set - override val matterNode = Graph6Node(this) + val matterNode = SimpleMatterNode(matter = this) override val canSetMatterLevel: Boolean get() = false @@ -137,7 +134,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) init { savetable(::container, INVENTORY_KEY) exposeGlobally(MatteryCapability.MATTER, this) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { @@ -146,17 +143,11 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) - } - - override fun getMatterHandler(): IMatterStorage { - return this + matterNode.discover(this) } } 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 b9f889f36..60fa7ae59 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 @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter import net.minecraft.core.BlockPos import net.minecraft.nbt.CompoundTag -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 @@ -10,32 +9,30 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.ForgeConfigSpec -import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection -import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage -import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl -import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.container.HandlerFilter -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.item.MatterDustItem -import ru.dbotthepony.mc.otm.menu.matter.MatterDecomposerMenu -import ru.dbotthepony.mc.otm.registry.MBlockEntities -import ru.dbotthepony.mc.otm.registry.MItems -import ru.dbotthepony.mc.otm.registry.MNames -import ru.dbotthepony.mc.otm.core.util.WriteOnce +import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.core.math.getDecimal import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.util.WriteOnce +import ru.dbotthepony.mc.otm.graph.matter.MatterGraph +import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode +import ru.dbotthepony.mc.otm.item.MatterDustItem import ru.dbotthepony.mc.otm.matter.MatterManager +import ru.dbotthepony.mc.otm.menu.matter.MatterDecomposerMenu +import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MItems +import ru.dbotthepony.mc.otm.registry.MNames fun moveMatterAsDustIntoContainer(_matterValue: Decimal, container: MatteryContainer, OUTPUT_DUST_MAIN: Int, OUTPUT_DUST_STACKING: Int): Decimal { var matterValue = _matterValue @@ -91,7 +88,7 @@ fun moveMatterAsDustIntoContainer(_matterValue: Decimal, container: MatteryConta } class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) - : MatteryWorkerBlockEntity(MBlockEntities.MATTER_DECOMPOSER, pos, state, ::DecomposerJob), IMatterGraphNode { + : MatteryWorkerBlockEntity(MBlockEntities.MATTER_DECOMPOSER, pos, state, ::DecomposerJob) { class DecomposerJob : Job { val toDust: Boolean @@ -127,13 +124,12 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) savetable(::energy, ENERGY_KEY) } - override val matterNode = Graph6Node(this) - val matter = MatterStorageImpl(::setChangedLight, FlowDirection.OUTPUT, ::CAPACITY) + val matterNode = SimpleMatterNode(matter = matter) init { exposeGlobally(MatteryCapability.MATTER, matter) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) savetable(::matter, MATTER_STORAGE_KEY) } @@ -199,24 +195,18 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) - } - - override fun getMatterHandler(): IMatterStorage { - return matter + matterNode.discover(this) } override fun tick() { super.tick() - val grid = matterNode.graph as MatterNetworkGraph? ?: return + val grid = matterNode.graph as MatterGraph? ?: return if (!matter.storedMatter.isZero) { val diff = matter.extractMatterInner(matter.storedMatter, true) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt index 7aabff5bb..2bce86dcf 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt @@ -25,14 +25,15 @@ import ru.dbotthepony.mc.otm.core.nbt.mapString import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.util.ItemSorter 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.graph.matter.MatterGraph +import ru.dbotthepony.mc.otm.graph.matter.MatterNode +import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.registry.MBlockEntities import java.util.ArrayList import java.util.stream.Stream class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IMatterGraphNode, IReplicationTaskProvider { + MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IReplicationTaskProvider { class PlayerSettings(var sorter: ItemSorter = ItemSorter.DEFAULT, var ascending: Boolean = true) : INBTSerializable { override fun serializeNBT(): CompoundTag { @@ -55,7 +56,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } private val listeners = ArrayList() - override val matterNode = Graph6Node(this) + val matterNode = SimpleMatterNode(tasks = this) fun attachMenu(menu: MatterPanelMenu) { listeners.add(menu) @@ -70,24 +71,18 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } init { - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) exposeGlobally(MatteryCapability.TASK, this) } override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) + matterNode.discover(this) } override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) - } - - override fun getTaskHandler(): IReplicationTaskProvider { - return this + matterNode.isValid = false } private val _tasks = HashMap() @@ -101,7 +96,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? { - val graph = matterNode.graph as MatterNetworkGraph? ?: return null + val graph = matterNode.graph as MatterGraph? ?: return null for ((key, task) in _tasks) { if (task.required > 0) { @@ -127,7 +122,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : val oldTask = localTask localTask = localTask.finish() - val graph = matterNode.graph as MatterNetworkGraph? + val graph = matterNode.graph as MatterGraph? // Задача полностью выполнена if (localTask.required <= 0 && localTask.inProgress <= 0) { @@ -196,7 +191,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : val task = _tasks[id] ?: return _tasks.remove(id) - (matterNode.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task) + (matterNode.graph as MatterGraph?)?.onMatterTaskRemoved(task) listeners.forEach { it.taskRemoved(task) } setChanged() @@ -206,7 +201,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : val task = ReplicationTask(UUID.randomUUID(), state.id, state.item, 0, 0, count) _tasks[task.id] = task - (matterNode.graph as MatterNetworkGraph?)?.onMatterTaskCreated(task) + (matterNode.graph as MatterGraph?)?.onMatterTaskCreated(task) listeners.forEach { it.taskUpdated(task) } setChanged() @@ -215,7 +210,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override fun dropAllTasks() { - val graph = matterNode.graph as MatterNetworkGraph? + val graph = matterNode.graph as MatterGraph? for (task in _tasks.values) { graph?.onMatterTaskRemoved(task) 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 432ba23e8..9db761ccd 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 @@ -23,8 +23,7 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.core.math.Decimal 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.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.item.MatterDustItem import ru.dbotthepony.mc.otm.menu.matter.MatterRecyclerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities @@ -34,9 +33,10 @@ import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.core.util.WriteOnce import ru.dbotthepony.mc.otm.core.math.getDecimal import ru.dbotthepony.mc.otm.core.math.set +import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) - : MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, ::RecyclerJob), IMatterGraphNode { + : MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, ::RecyclerJob) { class RecyclerJob : Job { var totalMatter: Decimal @@ -72,13 +72,9 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) val container = MatteryContainer(this::itemContainerUpdated, 1).also(::addDroppableContainer) - override val matterNode = Graph6Node(this) + val matterNode = SimpleMatterNode(matter = matter) val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_CONFIG) - override fun getMatterHandler(): IMatterStorage { - return matter - } - private val itemHandler = container.handler(object : HandlerFilter { override fun canInsert(slot: Int, stack: ItemStack): Boolean { return stack.item is MatterDustItem @@ -93,7 +89,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) exposeItemsGlobally(itemHandler) exposeEnergyGlobally(energy) exposeGlobally(MatteryCapability.MATTER, matter) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) savetable(::energy, ENERGY_KEY) savetable(::container, INVENTORY_KEY) savetable(::matter, MATTER_STORAGE_KEY) @@ -101,14 +97,12 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) + matterNode.discover(this) } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { @@ -155,7 +149,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) override fun tick() { super.tick() - val graph = matterNode.graph as MatterNetworkGraph? ?: return + val graph = matterNode.graph as MatterGraph? ?: return val received = graph.receiveMatter(matter.storedMatter, false) if (!received.isZero) { 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 74ade4275..1206dc3aa 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 @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter import net.minecraft.core.BlockPos import net.minecraft.nbt.CompoundTag -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 @@ -10,22 +9,20 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.ForgeConfigSpec -import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection -import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage -import ru.dbotthepony.mc.otm.capability.matter.* -import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage +import ru.dbotthepony.mc.otm.capability.matter.IPatternState +import ru.dbotthepony.mc.otm.capability.matter.IReplicationTask +import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl +import ru.dbotthepony.mc.otm.capability.matter.PatternState +import ru.dbotthepony.mc.otm.capability.matter.ReplicationTask +import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.container.HandlerFilter -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.menu.matter.MatterReplicatorMenu -import ru.dbotthepony.mc.otm.registry.MBlockEntities -import ru.dbotthepony.mc.otm.registry.MNames -import ru.dbotthepony.mc.otm.core.util.WriteOnce +import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.defineDecimal @@ -33,7 +30,12 @@ import ru.dbotthepony.mc.otm.core.math.getDecimal import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.util.WriteOnce +import ru.dbotthepony.mc.otm.graph.matter.MatterNode import ru.dbotthepony.mc.otm.matter.MatterManager +import ru.dbotthepony.mc.otm.menu.matter.MatterReplicatorMenu +import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MNames class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_, { @@ -42,7 +44,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } catch(err: NoSuchElementException) { null } - }), IMatterGraphNode { + }) { class ReplicatorJob : ItemJob { val matterPerTick: Decimal @@ -98,16 +100,39 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES) - override val matterNode = Graph6Node(this) val matter = MatterStorageImpl(this::matterLevelUpdated, FlowDirection.INPUT, ::MATTER_CAPACITY) val container = MatteryContainer(this::itemContainerUpdated, 5).also(::addDroppableContainer) val itemHandler = container.handler(HandlerFilter.OnlyOut) + val matterNode = object : MatterNode() { + override fun getMatterHandler(): IMatterStorage { + return matter + } + + override fun onMatterTaskCreated(task: IReplicationTask<*>) { + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } + } + + override fun > onMatterTaskUpdated(newState: T, oldState: T) { + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } + } + + override fun onPatternAdded(state: IPatternState) { + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } + } + } + init { exposeEnergyGlobally(energy) exposeItemsGlobally(itemHandler) exposeGlobally(MatteryCapability.MATTER, matter) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) savetable(::energy, ENERGY_KEY) savetable(::matter, MATTER_STORAGE_KEY) @@ -126,7 +151,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : return Status.FAILURE_WAIT } - (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id) + matterNode.graph.notifyTaskCompletion(job.task.id) return Status.SUCCESS } @@ -134,38 +159,18 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : return Status.FAILURE_ITEM } - (matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id) + matterNode.graph.notifyTaskCompletion(job.task.id) return Status.SUCCESS } - override fun onMatterTaskCreated(task: IReplicationTask<*>) { - if (idleReason == IdleReason.OBSERVING) { - isIdling = false - } - } - - override fun > onMatterTaskUpdated(newState: T, oldState: T) { - if (idleReason == IdleReason.OBSERVING) { - isIdling = false - } - } - - override fun onPatternAdded(state: IPatternState) { - if (idleReason == IdleReason.OBSERVING) { - isIdling = false - } - } - override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) + matterNode.discover(this) } override fun jobUpdated(oldJob: ReplicatorJob?, newJob: ReplicatorJob?) { @@ -176,7 +181,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : var visualItemStack by synchronizer.item(observe = false) private set - var visualProgress by synchronizer.float() + var visualProgress by synchronizer.float().property private set var renderRotation = 0f @@ -188,8 +193,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : return null to IdleReason.POWER } - val graph = matterNode.graph as MatterNetworkGraph? ?: return null to null - val allocation = graph.allocateTask(simulate = false) ?: return null to IdleReason.OBSERVING + val allocation = matterNode.graph.allocateTask(simulate = false) ?: return null to IdleReason.OBSERVING val stack = allocation.task.stack(1) val matter = MatterManager.get(stack) @@ -211,7 +215,6 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: ReplicatorJob): Status { val drainPerTick = job.matterPerTick * ticksAdvanced - val graph = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT_FAST if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) { // в машине недостаточно материи @@ -219,7 +222,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : if (drainPerTick > matter.maxStoredMatter) { // в тик требуется больше материи, чем её может хранить репликатор val toExtract = drainPerTick - matter.extractMatterInner(drainPerTick, true) - val drain = graph.extractMatter(toExtract, true) + val drain = matterNode.graph.extractMatter(toExtract, true) if (drain != toExtract) { // недостаточно материи в сети @@ -228,12 +231,12 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : // достаточно материи в сети + внутри машины matter.extractMatterInner(drainPerTick, false) - graph.extractMatter(drain, false) + matterNode.graph.extractMatter(drain, false) return Status.SUCCESS } else { // в тик требуется меньше материи, чем её может хранить репликатор // примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше - val drain = graph.extractMatter((drainPerTick * DRAIN_MULT) + val drain = matterNode.graph.extractMatter((drainPerTick * DRAIN_MULT) .coerceAtMost(job.matterPerTick * (job.ticks - workTicks - ticksAdvanced)) .coerceAtLeast(Decimal.ONE) .coerceAtMost(matter.missingMatter), false) 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 2d31a57fb..93b068c2d 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 @@ -22,18 +22,18 @@ import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.defineDecimal 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.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.menu.matter.MatterScannerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.core.util.WriteOnce +import ru.dbotthepony.mc.otm.graph.matter.MatterNode import ru.dbotthepony.mc.otm.matter.MatterManager import java.util.* import kotlin.math.pow class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryWorkerBlockEntity(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::ItemJob), IMatterGraphNode { + MatteryWorkerBlockEntity(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::ItemJob) { val container = MatteryContainer(this::itemContainerUpdated, 1).also(::addDroppableContainer) val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES) @@ -47,45 +47,43 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } }) + val matterNode = object : MatterNode() { + override fun onPatternAdded(state: IPatternState) { + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } + } + + override fun onPatternRemoved(state: IPatternState) { + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } + } + + override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) { + if (idleReason == IdleReason.OBSERVING) { + isIdling = false + } + } + } + init { exposeItemsGlobally(itemHandler) exposeEnergyGlobally(energy) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) savetable(::container, INVENTORY_KEY) savetable(::energy, ENERGY_KEY) } - // IMatterGraphNode - override fun onPatternAdded(state: IPatternState) { - if (idleReason == IdleReason.OBSERVING) { - isIdling = false - } - } - - override fun onPatternRemoved(state: IPatternState) { - if (idleReason == IdleReason.OBSERVING) { - isIdling = false - } - } - - override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) { - if (idleReason == IdleReason.OBSERVING) { - isIdling = false - } - } - // /IMatterGraphNode - - override val matterNode: Graph6Node = Graph6Node(this) - override fun invalidateCaps() { super.invalidateCaps() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { @@ -93,14 +91,12 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override fun onJobFinish(job: ItemJob): Status { - val grid = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT - val stack = job.itemStack if (stack.isEmpty || !MatterManager.hasMatterValue(stack)) return Status.SUCCESS var findState: IPatternState? = null - for (state in grid.patterns.filter { it.item === stack.item }) { + for (state in matterNode.graph.patterns.filter { it.item === stack.item }) { if (findState == null && state.researchPercent < 1.0) { findState = state } else if (findState != null && findState.researchPercent < state.researchPercent && state.researchPercent < 1.0) { @@ -117,7 +113,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : PatternState(UUID.randomUUID(), stack.item, researchAdvance) } - if (!grid.insertPattern(new, onlyUpdate = false, simulate = false).isFailed) { + if (!matterNode.graph.insertPattern(new, onlyUpdate = false, simulate = false).isFailed) { return Status.SUCCESS } else { return Status.FAILURE_WAIT @@ -129,14 +125,12 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : return null to IdleReason.POWER } - val grid = matterNode.graph as MatterNetworkGraph? ?: return null to null - val stack = container.getItem(0) if (stack.isEmpty || !MatterManager.canDecompose(stack)) return null to IdleReason.ITEM var findState: IPatternState? = null - for (state in grid.patterns.filter { it.item === stack.item }) { + for (state in matterNode.graph.patterns.filter { it.item === stack.item }) { if (state.researchPercent < 1.0) { findState = state } else if (state.researchPercent >= 1.0) { @@ -155,7 +149,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : PatternState(UUID.randomUUID(), stack.item, researchAdvance) } - if (!grid.insertPattern(new, onlyUpdate = false, simulate = true).isFailed) { + if (!matterNode.graph.insertPattern(new, onlyUpdate = false, simulate = true).isFailed) { val copy = stack.copy().also { it.count = 1 } stack.shrink(1) container.setChanged() @@ -168,10 +162,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) { - MatterNetworkGraph.discoverFull(this, matterNode) - } + matterNode.discover(this) } companion object { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt index fd6cbf42a..36c49590d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt @@ -20,8 +20,8 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.core.collect.iterator 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.graph.matter.MatterGraph +import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.registry.MBlockEntities import java.util.ArrayList import java.util.stream.Stream @@ -29,24 +29,22 @@ import java.util.stream.Stream @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryDeviceBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IMatterGraphNode, IPatternStorage { + MatteryDeviceBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IPatternStorage { - override val matterNode = Graph6Node(this) + val matterNode = SimpleMatterNode(patterns = this) val container: MatteryContainer = object : MatteryContainer(this::setChanged, 8) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - val grid = matterNode.graph as MatterNetworkGraph? - - if (grid != null && !ItemStack.isSameItemSameTags(new, old)) { + if (!ItemStack.isSameItemSameTags(new, old)) { if (!old.isEmpty) { old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> - cap.patterns.forEach { grid.onPatternRemoved(it) } + cap.patterns.forEach { matterNode.graph.onPatternRemoved(it) } } } if (!new.isEmpty) { new.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> - cap.patterns.forEach { grid.onPatternAdded(it) } + cap.patterns.forEach { matterNode.graph.onPatternAdded(it) } } } @@ -82,23 +80,17 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - MatterNetworkGraph.discoverFull(this, matterNode) - } - - override fun getPatternHandler(): IPatternStorage { - return this + matterNode.discover(this) } override fun invalidateCaps() { super.invalidateCaps() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } init { exposeGlobally(MatteryCapability.PATTERN, this) - exposeGlobally(MatteryCapability.MATTER_NODE, this) + exposeGlobally(MatteryCapability.MATTER_NODE, matterNode) exposeItemsGlobally(itemHandler) savetable(::container, INVENTORY_KEY) @@ -138,7 +130,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun setRemoved() { super.setRemoved() - matterNode.destroy(::MatterNetworkGraph) + matterNode.isValid = false } override fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus { @@ -149,14 +141,10 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : if (!simulate) { setChanged() - val graph = matterNode.graph as MatterNetworkGraph? - - if (graph != null) { - if (status.isInserted) { - graph.onPatternAdded(status.newState!!) - } else { - graph.onPatternUpdated(status.newState!!, status.oldState!!) - } + if (status.isInserted) { + matterNode.graph.onPatternAdded(status.newState!!) + } else { + matterNode.graph.onPatternUpdated(status.newState!!, status.oldState!!) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt index caba91cdf..8f8405bab 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt @@ -9,13 +9,13 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity -import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode +import ru.dbotthepony.mc.otm.graph.storage.StorageNode import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu -import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.graph.storage.StorageGraph import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.storage.* @@ -41,7 +41,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } }.also(::addDroppableContainer) - val cell = BasicStorageGraphNode(energy) + val cell = StorageNode(energy) init { savetable(::energy, ENERGY_KEY) @@ -52,9 +52,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - StorageNetworkGraph.discoverFull(this, cell.storageNode) + cell.discover(this) } override fun tick() { @@ -68,6 +66,6 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun setRemoved() { super.setRemoved() - cell.destroy(level) + cell.isValid = false } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index e19cee385..b24bde36f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -30,8 +30,8 @@ import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get -import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode -import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.graph.storage.StorageNode +import ru.dbotthepony.mc.otm.graph.storage.StorageGraph import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.container.set @@ -188,13 +188,13 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : var poweredView: PoweredVirtualComponent? = null private set - val cell = object : BasicStorageGraphNode(energy) { - override fun attachComponents(to: StorageNetworkGraph) { + val cell = object : StorageNode(energy) { + override fun attachComponents(to: StorageGraph) { super.attachComponents(to) poweredView = PoweredVirtualComponent(to.getVirtualComponent(ITEM_STORAGE), energy) } - override fun removeComponents(from: StorageNetworkGraph) { + override fun removeComponents(from: StorageGraph) { super.removeComponents(from) poweredView?.removeListeners() poweredView = null @@ -499,13 +499,11 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) - StorageNetworkGraph.discoverFull(this, cell.storageNode) + cell.discover(this) } override fun setRemoved() { super.setRemoved() - cell.destroy(level) + cell.isValid = false } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt index c11ce88fa..4ae09678d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt @@ -4,8 +4,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import net.minecraft.core.BlockPos import net.minecraft.core.Direction -import net.minecraft.network.chat.Component -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 @@ -31,21 +29,14 @@ import ru.dbotthepony.mc.otm.core.math.getCapability import ru.dbotthepony.mc.otm.core.math.isPositive import ru.dbotthepony.mc.otm.core.math.isZero import ru.dbotthepony.mc.otm.core.math.plus -import ru.dbotthepony.mc.otm.graph.Graph6Node -import ru.dbotthepony.mc.otm.graph.GraphNodeListener -import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode -import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.graph.storage.StorageNode import ru.dbotthepony.mc.otm.menu.storage.StorageBusMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities -import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.storage.* import java.lang.ref.WeakReference import java.math.BigInteger import java.util.* import java.util.stream.Stream -import kotlin.NoSuchElementException -import kotlin.collections.ArrayList -import kotlin.collections.HashMap private class SlotTuple(val slot: Int, val stack: ItemStack) private class TrackedTuple(override val stack: ItemStackWrapper, override val id: UUID) : IStorageTuple { @@ -77,15 +68,15 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter savetable(::energy, ENERGY_KEY) } - val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(energy), GraphNodeListener { - override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { + val cell: StorageNode = object : StorageNode(energy) { + override fun onNeighbour(direction: Direction) { val newState = this@StorageBusBlockEntity.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) if (newState !== this@StorageBusBlockEntity.blockState && SERVER_IS_LIVE) level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) } - override fun onUnNeighbour(node: Graph6Node<*>, direction: Direction) { + override fun onUnNeighbour(direction: Direction) { val newState = this@StorageBusBlockEntity.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false) if (newState !== this@StorageBusBlockEntity.blockState && SERVER_IS_LIVE) @@ -109,11 +100,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) { - StorageNetworkGraph.discoverFull(this, cell.storageNode) - } - + cell.discover(this) tickList.once(this::checkSurroundings) } @@ -128,7 +115,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter override fun setRemoved() { super.setRemoved() - cell.destroy(level) + cell.isValid = false } fun checkSurroundings() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt index ec4d9b8b9..a37b4b10e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt @@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.block.entity.storage import net.minecraft.core.BlockPos import net.minecraft.core.Direction import net.minecraft.network.chat.Component -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 @@ -26,14 +25,10 @@ import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.core.TranslatableComponent -import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.math.toIntSafe import ru.dbotthepony.mc.otm.core.orNull -import ru.dbotthepony.mc.otm.graph.Graph6Node -import ru.dbotthepony.mc.otm.graph.GraphNodeListener -import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode -import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.graph.storage.StorageNode import ru.dbotthepony.mc.otm.menu.storage.StorageExporterMenu import ru.dbotthepony.mc.otm.menu.storage.StorageImporterMenu import ru.dbotthepony.mc.otm.once @@ -62,8 +57,8 @@ abstract class AbstractStorageImportExport( savetable(::energy, ENERGY_KEY) } - val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(energy), GraphNodeListener { - override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { + val cell: StorageNode = object : StorageNode(energy) { + override fun onNeighbour(direction: Direction) { level?.once { if (!isRemoved) { val newState = this@AbstractStorageImportExport.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) @@ -74,7 +69,7 @@ abstract class AbstractStorageImportExport( } } - override fun onUnNeighbour(node: Graph6Node<*>, direction: Direction) { + override fun onUnNeighbour(direction: Direction) { level?.once { if (!isRemoved) { val newState = this@AbstractStorageImportExport.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false) @@ -93,15 +88,12 @@ abstract class AbstractStorageImportExport( override fun setRemoved() { super.setRemoved() - cell.destroy(level) + cell.isValid = false } override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) { - StorageNetworkGraph.discoverFull(this, cell.storageNode) - } + cell.discover(this) } protected abstract val targetCapability: Capability @@ -117,7 +109,6 @@ abstract class AbstractStorageImportExport( } companion object { - val MAX_POWER = Decimal(10_000) const val FILTER_KEY = "filter" } } @@ -155,7 +146,7 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : A if (redstoneControl.isBlockedByRedstone || !filter.match(stack)) return stack - val view = cell.storageGraph?.getVirtualComponent(ITEM_STORAGE) ?: return stack + val view = cell.graph.getVirtualComponent(ITEM_STORAGE) val maxMove = energy.extractEnergyExact(ITEM_STORAGE.energyPerOperation, stack.count.toBigInteger(), true) if (maxMove == BigInteger.ZERO) @@ -195,8 +186,7 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : A val target = target.get().orNull() if (nextTick <= 0 && target != null && enoughEnergy) { - val graph = cell.storageGraph ?: return - val items = graph.getVirtualComponent(ITEM_STORAGE) + val items = cell.graph.getVirtualComponent(ITEM_STORAGE) if (lastSlot >= target.slots) { lastSlot = 0 @@ -227,7 +217,6 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : A companion object { const val MAX_MOVE_PER_OPERATION = 4 - private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_IMPORTER}") private const val INTERVAL = 5 const val MAX_FILTERS = 6 * 3 } @@ -271,7 +260,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : override val filter = ItemFilter(MAX_FILTERS) { _, _, _ -> relevantTuples.clear() - val component = cell.storageGraph?.getVirtualComponent(ITEM_STORAGE) ?: return@ItemFilter + val component = cell.graph.getVirtualComponent(ITEM_STORAGE) for (tuple in component.stacks) { addStack(tuple, component) @@ -291,7 +280,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : private val exportStacks: Stream> get() { - val view = cell.storageGraph?.getVirtualComponent(ITEM_STORAGE) ?: return Stream.empty() + val view = cell.graph.getVirtualComponent(ITEM_STORAGE) return relevantTuples.stream().map { it to view[it] } } @@ -308,8 +297,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : val target = target.get().orNull() if (nextTick <= 0 && target != null && enoughEnergy) { - val graph = cell.storageGraph ?: return - val items = graph.getVirtualComponent(ITEM_STORAGE) + val items = cell.graph.getVirtualComponent(ITEM_STORAGE) if (lastSlot >= target.slots) { lastSlot = 0 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt index fa0dbb017..61c395979 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt @@ -13,8 +13,8 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.transferChecked import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode -import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.graph.storage.StorageNode +import ru.dbotthepony.mc.otm.graph.storage.StorageGraph import ru.dbotthepony.mc.otm.menu.storage.StoragePowerSupplierMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities @@ -23,7 +23,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState return StoragePowerSupplierMenu(containerID, inventory, this) } - val cell = BasicStorageGraphNode() + val cell = StorageNode() val energy = WorkerEnergyStorage(this, MachinesConfig.STORAGE_POWER_SUPPLIER) init { @@ -42,15 +42,12 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState override fun setLevel(level: Level) { super.setLevel(level) - - if (level is ServerLevel) { - StorageNetworkGraph.discoverFull(this, cell.storageNode) - } + cell.discover(this) } override fun setRemoved() { super.setRemoved() - cell.destroy(level) + cell.isValid = false } override fun tick() { @@ -62,9 +59,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState if (energy.batteryLevel.isZero) return - val graph = cell.storageGraph ?: return - - if (graph.powerDemandingNodes.isEmpty()) + if (cell.graph.powerDemandingNodes.isEmpty()) return var demand = Decimal.ZERO @@ -72,7 +67,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState val available = energy.batteryLevel.coerceAtMost(MachinesConfig.STORAGE_POWER_SUPPLIER.throughput) - for (demanding in graph.powerDemandingNodes) { + for (demanding in cell.graph.powerDemandingNodes) { val received = demanding.receiveEnergy(available, true) if (received.isPositive) { @@ -84,13 +79,13 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState if (demand.isZero) { return } else if (demand < available) { - for (demanding in graph.powerDemandingNodes) { + for (demanding in cell.graph.powerDemandingNodes) { powerPassed += energy.transferChecked(demanding, available, false) } } else { val forEach = available / i - for (demanding in graph.powerDemandingNodes) { + for (demanding in cell.graph.powerDemandingNodes) { powerPassed += energy.transferChecked(demanding, forEach, false) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt index 5556f0819..b63a601e7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt @@ -21,8 +21,9 @@ import ru.dbotthepony.mc.otm.onceServer import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.isMekanismLoaded import ru.dbotthepony.mc.otm.core.math.isPositive -import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode -import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.core.util.LOHolder +import ru.dbotthepony.mc.otm.graph.storage.StorageNode +import ru.dbotthepony.mc.otm.graph.storage.StorageGraph import ru.dbotthepony.mc.otm.storage.* import java.math.BigInteger import java.util.UUID @@ -206,14 +207,14 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit private var frequencyAccess: QIOFrequencyAccess? = null private var wasAttached = false - val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(), ITickable { + val cell: StorageNode = object : StorageNode(), ITickable { init { manualAttaching = true } override fun tick() { if (tile.isRemoved) { - destroy(tile.level) + isValid = false return } @@ -225,9 +226,7 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit val lastFrequency = lastFrequency ?: throw IllegalStateException("lastFrequency is null") - checkNotNull(storageGraph) { - "Unexpected internal state (expected storage graph to be present, something detached $this from storage grid, but did not call removeComponents())" - }.userData.remove(key(lastFrequency)) + graph.userData.remove(key(lastFrequency)) } frequencyAccess?.let(this::removeStorageComponent) @@ -240,17 +239,16 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit val frequencyAccess = frequencyAccess ?: return frequencyAccess.scan() - val storageGraph = storageGraph ?: return val key = key(frequencyAccess.parent) - if (!storageGraph.userData.containsKey(key)) { - storageGraph.userData[key] = true + if (!graph.userData.containsKey(key)) { + graph.userData[key] = true wasAttached = true - storageGraph.add(frequencyAccess) + graph.add(frequencyAccess) } } - override fun removeComponents(from: StorageNetworkGraph) { + override fun removeComponents(from: StorageGraph) { super.removeComponents(from) if (wasAttached) { @@ -259,11 +257,23 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit wasAttached = false } } + + override fun invalidate() { + super.invalidate() + holder.invalidate() + } + + override fun revive() { + super.revive() + holder.revive() + } } + private val holder = LOHolder(cell) + override fun getCapability(cap: Capability, side: Direction?): LazyOptional { if (cap === MatteryCapability.STORAGE_NODE) - return cell.get().cast() + return holder.get() return LazyOptional.empty() } @@ -286,8 +296,8 @@ fun attachCapabilities(event: AttachCapabilitiesEvent) { event.addCapability(QIO_LOCATION, capability) onceServer { - if (!event.`object`.isRemoved && event.`object`.level?.isClientSide == false) { - StorageNetworkGraph.discoverFull(event.`object`, capability.cell.storageNode) + if (!event.`object`.isRemoved) { + capability.cell.discover(event.`object`, MatteryCapability.STORAGE_NODE) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LOHolder.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LOHolder.kt new file mode 100644 index 000000000..289c1785f --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LOHolder.kt @@ -0,0 +1,20 @@ +package ru.dbotthepony.mc.otm.core.util + +import net.minecraftforge.common.util.LazyOptional + +class LOHolder(val value: T) { + private var lazyOptional: LazyOptional = LazyOptional.of { value } + + fun invalidate() { + lazyOptional.invalidate() + } + + fun revive() { + lazyOptional.invalidate() + lazyOptional = LazyOptional.of { value } + } + + fun get(): LazyOptional { + return lazyOptional.cast() + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Abstract6Graph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Abstract6Graph.kt index 4a7b15557..6999a110e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Abstract6Graph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Abstract6Graph.kt @@ -1,178 +1,172 @@ package ru.dbotthepony.mc.otm.graph -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.core.SectionPos -import net.minecraft.server.level.ServerLevel -import net.minecraft.world.level.block.entity.BlockEntity import ru.dbotthepony.mc.otm.core.util.IConditionalTickable -import ru.dbotthepony.mc.otm.core.math.plus -import ru.dbotthepony.mc.otm.addTicker +import ru.dbotthepony.mc.otm.core.util.ITickable +import java.lang.ref.WeakReference import java.util.* import kotlin.collections.ArrayList -import kotlin.collections.HashMap -abstract class Abstract6Graph : IConditionalTickable { - protected val nodes = ArrayList>() - fun size() = nodes.size - private val tickable = ArrayList>() - val nodeList: Collection> = Collections.unmodifiableCollection(nodes) +open class Abstract6Graph, G : Abstract6Graph> : IConditionalTickable { + private val nodesInternal = ArrayList() + private val conditional = ArrayList() + private val always = ArrayList() + + protected val nodes: List = Collections.unmodifiableList(nodesInternal) + + val size get() = nodesInternal.size + + var isMerged = false + private set + + private var isTicking = false /** * Allows storing arbitrary data by external code */ - @JvmField val userData = HashMap() - abstract fun onNodeRemoved(node: Graph6Node) - abstract fun onNodeAdded(node: Graph6Node) + open fun onNodeRemoved(node: N) {} + open fun onNodeAdded(node: N) {} + open fun onMergedInto(other: G) {} - override fun tick(): Boolean { - for (i in tickable.size - 1 downTo 0) { - val node = tickable[i] + protected open fun innerTick(): Boolean { + return false + } + + final override fun tick(): Boolean { + if (isMerged) + return false + + // позволяет вершинам изменять список тикающих вершин + for (i in conditional.size - 1 downTo 0) { + val node = conditional[i] if (!node.tick()) { - tickable.removeAt(i) + conditional.removeAt(i) } } - return nodes.size > 0 + // позволяет вершинам изменять список тикающих вершин + for (node in always.size - 1 downTo 0) { + always[node].tick() + } + + return innerTick() || always.isNotEmpty() || conditional.isNotEmpty() } - fun removeNode(node: Graph6Node) { - if (!nodes.remove(node)) - throw IllegalStateException("Not containing node $node") + fun addNode(node: N): Boolean { + if (node in nodesInternal) + return false - node.graph = null - onNodeRemoved(node) - tickable.remove(node) - } + nodesInternal.add(node) - fun addNode(node: Graph6Node) { - if (nodes.contains(node)) - throw IllegalStateException("Already containing node $node") + if (node is IConditionalTickable) { + conditional.add(node) + + if (!isTicking) { + isTicking = true + next.add(WeakReference(this)) + } + } else if (node is ITickable) { + always.add(node) + + if (!isTicking) { + isTicking = true + next.add(WeakReference(this)) + } + } - nodes.add(node) - node.graph = this onNodeAdded(node) - tickable.add(node) + return true } - fun merge(other: Abstract6Graph): Abstract6Graph { + fun removeNode(node: N): Boolean { + if (!nodesInternal.remove(node)) + return false + + nodesInternal.remove(node) + + if (node is IConditionalTickable) + conditional.remove(node) + else if (node is ITickable) + always.remove(node) + + onNodeRemoved(node) + return true + } + + fun retain(nodes: Set) { + for (i in this.nodesInternal.size - 1 downTo 0) { + if (this.nodesInternal[i] !in nodes) { + val node = this.nodesInternal[i] + + this.nodesInternal.removeAt(i) + + if (node is IConditionalTickable) + conditional.remove(node) + else if (node is ITickable) + always.remove(node) + + onNodeRemoved(node) + } + } + } + + fun merge(other: G, setter: (N, G) -> Unit): G { if (other === this) return this - if (size() >= other.size()) { - for (node in other.nodes) { - nodes.add(node) - node.graph = this + if (size >= other.size) { + for (node in other.nodesInternal) { + nodesInternal.add(node) + setter.invoke(node, this as G) onNodeAdded(node) + + if (node is IConditionalTickable) { + conditional.add(node) + + if (!isTicking) { + isTicking = true + next.add(WeakReference(this)) + } + } else if (node is ITickable) { + always.add(node) + + if (!isTicking) { + isTicking = true + next.add(WeakReference(this)) + } + } } + other.isMerged = true + other.onMergedInto(this as G) return this } else { - return other.merge(this) + return other.merge(this as G, setter) } } companion object { - fun discoverFull( - level: ServerLevel, - blockPos: BlockPos, - node: Graph6Node, - nodeGetter: (BlockEntity) -> Graph6Node?, - factory: () -> Abstract6Graph - ) { - level.addTicker { - !discover(level, blockPos, node, nodeGetter, factory) && node.valid - } - } + private val graphs = ArrayList>>() + private val next = ArrayList>>() - @JvmStatic - fun discover( - level: ServerLevel, - blockPos: BlockPos, - node: Graph6Node, - nodeGetter: (BlockEntity) -> Graph6Node?, - factory: () -> Abstract6Graph - ): Boolean { - var fullDiscovery = true - - node.nullifyConnections() - - var _graph = node.graph - - // для начала найдем граф к которому будем принадлежать - if (_graph == null) { - for (dir in Direction.values()) { - val offset = blockPos + dir - val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(offset.x), SectionPos.blockToSectionCoord(offset.z)) - - if (chunk == null) { - fullDiscovery = false - continue - } - - val entity = chunk.getBlockEntity(offset) - - if (entity != null) { - val getNode = nodeGetter(entity) - - if (getNode?.graph != null) { - _graph = getNode.graph - break - } - } - } - - // мы нашли граф рядом - if (_graph != null) { - node.graph = _graph - _graph.addNode(node) - } else { - // графов рядом нет, создаем свой - _graph = factory() - node.graph = _graph - _graph.addNode(node) - } + fun tick() { + if (next.isNotEmpty()) { + graphs.addAll(next) + next.clear() } - // теперь снова смотрим на соседей, если у них нет графа - присоединяем к своему - // если у них есть граф - слияем его со своим или свой с его - for (dir in Direction.values()) { - val offset = blockPos + dir - val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(offset.x), SectionPos.blockToSectionCoord(offset.z)) + val iterator = graphs.iterator() - if (chunk == null) { - fullDiscovery = false - continue - } + for (value in iterator) { + val graph = value.get() - val entity = chunk.getBlockEntity(offset) - - if (entity != null) { - val getNode = nodeGetter(entity) - - if (getNode != null) { - // у вершины нет своего графа - // добавляем в свой граф - if (getNode.graph == null) { - getNode.graph = node.graph!! - node.graph!!.addNode(getNode) - } else if (getNode.graph != node.graph) { - // у вершины уже есть свой граф, и он не наш - // произведём слияние графов - val merged = getNode.graph!!.merge(node.graph!!) - getNode.graph = merged - node.graph = merged - } - - node.setToNeightbour(getNode, dir) - } + if (graph == null || !graph.tick()) { + graph?.isTicking = false + iterator.remove() } } - - return fullDiscovery } } } 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 2ca4c3e02..9c0ff9ebe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt @@ -1,313 +1,268 @@ package ru.dbotthepony.mc.otm.graph +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet +import net.minecraft.core.BlockPos import net.minecraft.core.Direction -import ru.dbotthepony.mc.otm.core.util.IConditionalTickable -import ru.dbotthepony.mc.otm.core.util.ITickable -import ru.dbotthepony.mc.otm.SERVER_IS_LIVE +import net.minecraft.core.SectionPos +import net.minecraft.server.level.ServerLevel +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraftforge.common.capabilities.Capability +import ru.dbotthepony.mc.otm.addTicker +import ru.dbotthepony.mc.otm.core.math.plus +import ru.dbotthepony.mc.otm.core.math.unaryMinus +import ru.dbotthepony.mc.otm.core.orNull +import java.util.EnumMap +import java.util.concurrent.atomic.AtomicInteger -interface GraphNodeListener { - fun onNeighbourTop(node: Graph6Node<*>) = onNeighbour(node, Direction.UP) - fun onNeighbourBottom(node: Graph6Node<*>) = onNeighbour(node, Direction.DOWN) - fun onNeighbourLeft(node: Graph6Node<*>) = onNeighbour(node, Direction.WEST) - fun onNeighbourRight(node: Graph6Node<*>) = onNeighbour(node, Direction.EAST) - fun onNeighbourFront(node: Graph6Node<*>) = onNeighbour(node, Direction.SOUTH) - fun onNeighbourBack(node: Graph6Node<*>) = onNeighbour(node, Direction.NORTH) +open class Graph6Node, G : Abstract6Graph>(val graphFactory: () -> G) { + private val neighbours = EnumMap(Direction::class.java) - fun onNeighbour(node: Graph6Node<*>, direction: Direction) - - fun onUnNeighbourTop(node: Graph6Node<*>) = onUnNeighbour(node, Direction.UP) - fun onUnNeighbourBottom(node: Graph6Node<*>) = onUnNeighbour(node, Direction.DOWN) - fun onUnNeighbourLeft(node: Graph6Node<*>) = onUnNeighbour(node, Direction.WEST) - fun onUnNeighbourRight(node: Graph6Node<*>) = onUnNeighbour(node, Direction.EAST) - fun onUnNeighbourFront(node: Graph6Node<*>) = onUnNeighbour(node, Direction.SOUTH) - fun onUnNeighbourBack(node: Graph6Node<*>) = onUnNeighbour(node, Direction.NORTH) - - fun onUnNeighbour(node: Graph6Node<*>, direction: Direction) -} - -// Вершина графа, содержит то, к какому графу принадлежит, соседей и своё "значение" -class Graph6Node(@JvmField val value: T, graph: Abstract6Graph? = null) : IConditionalTickable { - var graph: Abstract6Graph? = null - - init { - this.graph = graph - } - - var top: Graph6Node? = null - set(value) { - if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph") - - if (field != value && this.value is GraphNodeListener) { - if (field != null) { - this.value.onUnNeighbourTop(field!!) - } - - if (value != null) { - this.value.onNeighbourTop(value) - } - } - - field = value - } - - var bottom: Graph6Node? = null - set(value) { - if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph") - - if (field != value && this.value is GraphNodeListener) { - if (field != null) { - this.value.onUnNeighbourBottom(field!!) - } - - if (value != null) { - this.value.onNeighbourBottom(value) - } - } - - field = value - } - - var left: Graph6Node? = null - set(value) { - if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph") - - if (field != value && this.value is GraphNodeListener) { - if (field != null) { - this.value.onUnNeighbourLeft(field!!) - } - - if (value != null) { - this.value.onNeighbourLeft(value) - } - } - - field = value - } - - var right: Graph6Node? = null - set(value) { - if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph") - - if (field != value && this.value is GraphNodeListener) { - if (field != null) { - this.value.onUnNeighbourRight(field!!) - } - - if (value != null) { - this.value.onNeighbourRight(value) - } - } - - field = value - } - - var front: Graph6Node? = null - set(value) { - if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph") - - if (field != value && this.value is GraphNodeListener) { - if (field != null) { - this.value.onUnNeighbourFront(field!!) - } - - if (value != null) { - this.value.onNeighbourFront(value) - } - } - - field = value - } - - var back: Graph6Node? = null - set(value) { - if (value != null && (graph == null || value.graph !== graph)) throw IllegalStateException("Can not be neighbour with node from different graph") - - if (field != value && this.value is GraphNodeListener) { - if (field != null) { - this.value.onUnNeighbourBack(field!!) - } - - if (value != null) { - this.value.onNeighbourBack(value) - } - } - - field = value - } - - fun nullifyConnections() { - top?.bottom = null - bottom?.top = null - left?.right = null - right?.left = null - front?.back = null - back?.front = null - - top = null - bottom = null - left = null - right = null - front = null - back = null - } - - fun setToNeightbour(node: Graph6Node, direction: Direction) { - when (direction) { - Direction.DOWN -> { - node.top = this - bottom = node - } - - Direction.UP -> { - node.bottom = this - top = node - } - - Direction.NORTH -> { - node.front = this - back = node - } - - Direction.SOUTH -> { - node.back = this - front = node - } - - Direction.WEST -> { - node.right = this - left = node - } - - Direction.EAST -> { - node.left = this - right = node - } - } - } - - override fun tick(): Boolean { - if (value is IConditionalTickable) { - return value.tick() - } else if (value is ITickable) { - value.tick() - return true - } else { - return false - } - } - - var seen: Int = 0 - - private fun _flood(): List> { - val list = ArrayList>() - var seen = Int.MAX_VALUE - - GraphFlooder.floodIf(top, seen) { - seen = it.seen - list.add(it) - } - - GraphFlooder.floodIf(bottom, seen) { - seen = it.seen - list.add(it) - } - - GraphFlooder.floodIf(left, seen) { - seen = it.seen - list.add(it) - } - - GraphFlooder.floodIf(right, seen) { - seen = it.seen - list.add(it) - } - - GraphFlooder.floodIf(front, seen) { - seen = it.seen - list.add(it) - } - - GraphFlooder.floodIf(back, seen) { - seen = it.seen - list.add(it) - } - - return list - } - - fun flood(): List> { - top?.bottom = null - bottom?.top = null - left?.right = null - right?.left = null - front?.back = null - back?.front = null - - val list = _flood() - - top?.bottom = this - bottom?.top = this - left?.right = this - right?.left = this - front?.back = this - back?.front = this - - return list - } - - var valid = true + var graph: G = graphFactory.invoke() private set - fun destroy(factory: () -> Abstract6Graph): List> { - if (!valid || !SERVER_IS_LIVE) return emptyList() + init { + graph.addNode(this as N) + } - top?.bottom = null - bottom?.top = null - left?.right = null - right?.left = null - front?.back = null - back?.front = null + private var seen: Int = 0 - graph?.removeNode(this) + operator fun get(direction: Direction): N? = neighbours[direction] - var num = 0 + operator fun set(direction: Direction, node: N?) { + set(direction, node, false) + } - if (top != null) num++ - if (bottom != null) num++ - if (left != null) num++ - if (right != null) num++ - if (front != null) num++ - if (back != null) num++ + fun set(direction: Direction, node: N?, allowReplacement: Boolean) { + check(isValid) { "Can not neighbour any node while this node is invalid" } - if (num < 2) { - return emptyList() + val old = neighbours[direction] + if (old === node) return + + if (old != null) + breakConnection(this as N, old, direction) + + if (node != null) { + require(node.isValid) { "Can not neighbour invalid node" } + + val opposite = -direction + + if (allowReplacement) { + node.neighbours[opposite]?.let { + breakConnection(node, it, opposite) + } + + check(node.neighbours[opposite] == null) { "$node didn't break connection at direction $opposite" } + } else { + check(node.neighbours[opposite] == null) { "Trying to form connection from $this to $node at direction $direction, but $node already has neighbour at $opposite (${node.neighbours[opposite]})!" } + } + + node.neighbours[opposite] = this as N + neighbours[direction] = node + node.graph.merge(graph, setter) + node.onNeighbour(opposite) + onNeighbour(direction) + } else { + neighbours.remove(direction) + } + } + + var top: N? + get() = neighbours[Direction.UP] + set(value) { + set(Direction.UP, value) } - val paths = _flood() - - if (paths.size < 2) { - return paths + var bottom: N? + get() = neighbours[Direction.DOWN] + set(value) { + set(Direction.DOWN, value) } - var biggest = paths[0] + var south: N? + get() = neighbours[Direction.SOUTH] + set(value) { + set(Direction.SOUTH, value) + } - for (i in 1 until paths.size) { - if (biggest.size() < paths[i].size()) { - biggest = paths[i] + var north: N? + get() = neighbours[Direction.NORTH] + set(value) { + set(Direction.NORTH, value) + } + + var west: N? + get() = neighbours[Direction.WEST] + set(value) { + set(Direction.WEST, value) + } + + var east: N? + get() = neighbours[Direction.EAST] + set(value) { + set(Direction.EAST, value) + } + + open fun onNeighbour(direction: Direction) {} + open fun onUnNeighbour(direction: Direction) {} + + protected open fun invalidate() {} + protected open fun revive() {} + + var isValid: Boolean = true + set(value) { + if (value == field) return + field = value + + if (!value) { + val neighbours = ArrayList(neighbours.entries) + + for ((dir, node) in neighbours) { + breakConnection(this as N, node, dir) + } + + graph.removeNode(this as N) + invalidate() + } else { + revive() } } - for (flooder in paths) { - if (flooder == biggest) continue + fun discover( + level: ServerLevel, + blockPos: BlockPos, + nodeGetter: (BlockEntity) -> N? + ) { + if (!isValid) return - val graph = factory() + level.addTicker { + isValid && !discoverStep(level, blockPos, nodeGetter) + } + } - for (node in flooder.nodes) { - node.graph?.removeNode(node) - graph.addNode(node) + fun discover( + level: ServerLevel, + blockPos: BlockPos, + capability: Capability + ) { + if (!isValid) return + + level.addTicker { + isValid && !discoverStep(level, blockPos) { it.getCapability(capability).orNull() } + } + } + + fun discover(blockEntity: BlockEntity, nodeGetter: (BlockEntity) -> N?) { + discover(blockEntity.level as? ServerLevel ?: return, blockEntity.blockPos, nodeGetter) + } + + fun discover(blockEntity: BlockEntity, capability: Capability) { + discover(blockEntity.level as? ServerLevel ?: return, blockEntity.blockPos, capability) + } + + fun discoverStep( + level: ServerLevel, + blockPos: BlockPos, + nodeGetter: (BlockEntity) -> N?, + ): Boolean { + if (!isValid) return false + var fullDiscovery = true + + for (dir in directions) { + val offset = blockPos + dir + val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(offset.x), SectionPos.blockToSectionCoord(offset.z)) + + if (chunk == null) { + fullDiscovery = false + set(dir, null) + continue + } + + val entity = chunk.getBlockEntity(offset) + + if (entity != null) { + set(dir, nodeGetter(entity)) + } else { + set(dir, null) } } - return paths + return fullDiscovery + } + + companion object { + private val setter = Graph6Node<*, *>::graph::set + private val nextSeen = AtomicInteger() + private val directions = Direction.values() + + private fun , G : Abstract6Graph> breakConnection(a: N, b: N, direction: Direction) { + val opposite = -direction + + require(a.neighbours[direction] === b) { "$a does not neighbour with $b at direction $direction (forward)" } + require(b.neighbours[opposite] === a) { "$b does not neighbour with $a at direction $opposite (backward)" } + require(a.graph === b.graph) { "$a and $b belong to different graphs (${a.graph} vs ${b.graph})" } + + a.neighbours.remove(direction) + b.neighbours.remove(opposite) + + val seen = nextSeen.incrementAndGet() + val flood1 = flood(a, seen) + + if (b.seen != seen) { + val flood2 = flood(b, seen) + + val big: ArrayList + val small: ArrayList + + if (flood1.size >= flood2.size) { + big = flood1 + small = flood2 + } else { + big = flood2 + small = flood1 + } + + a.graph.retain(ReferenceOpenHashSet(big)) + val newGraph = a.graphFactory.invoke() + + for (node in small) { + node.graph = newGraph + } + + for (node in small) { + if (node.isValid) { + newGraph.addNode(node) + } + } + } + + if (a.isValid) + a.onUnNeighbour(direction) + + if (b.isValid) + b.onUnNeighbour(opposite) + } + + private fun , G : Abstract6Graph> flood(startingNode: N, seen: Int): ArrayList { + val unopen = ArrayList() + val result = ArrayList() + unopen.add(startingNode) + + while (unopen.isNotEmpty()) { + val last = unopen.removeLast() + + if (last.seen < seen) { + result.add(last) + last.seen = seen + + for (node in last.neighbours.values) { + if (node.seen < seen) { + unopen.add(node) + } + } + } + } + + return result + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/GraphFlooder.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/GraphFlooder.kt deleted file mode 100644 index 5c0a4d1c3..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/GraphFlooder.kt +++ /dev/null @@ -1,64 +0,0 @@ -package ru.dbotthepony.mc.otm.graph - -import java.util.* -import kotlin.collections.ArrayList - -class GraphFlooder(val startNode: Graph6Node, @JvmField val seen: Int = nextSeen++) { - var flooded = false - private set - - private val _nodes = ArrayList>() - - @JvmField - val nodes = Collections.unmodifiableCollection(_nodes)!! - - fun size() = _nodes.size - - private fun flood(node: Graph6Node) { - if (node.seen >= seen) return - - _nodes.add(node) - node.seen = seen - - if (node.top != null) flood(node.top!!) - if (node.bottom != null) flood(node.bottom!!) - if (node.left != null) flood(node.left!!) - if (node.right != null) flood(node.right!!) - if (node.front != null) flood(node.front!!) - if (node.back != null) flood(node.back!!) - } - - fun flood() { - if (flooded) throw IllegalStateException("Already flooded") - - flooded = true - - _nodes.add(startNode) - startNode.seen = seen - - if (startNode.top != null) flood(startNode.top!!) - if (startNode.bottom != null) flood(startNode.bottom!!) - if (startNode.left != null) flood(startNode.left!!) - if (startNode.right != null) flood(startNode.right!!) - if (startNode.front != null) flood(startNode.front!!) - if (startNode.back != null) flood(startNode.back!!) - } - - companion object { - private var nextSeen = 0 - - fun floodIf(node: Graph6Node?, seen: Int, runnable: (GraphFlooder) -> Unit) { - if (node != null && node.seen < seen) { - if (seen == Int.MAX_VALUE) { - val flooder = GraphFlooder(node) - flooder.flood() - runnable(flooder) - } else { - val flooder = GraphFlooder(node, seen) - flooder.flood() - runnable(flooder) - } - } - } - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/IMatterGraphNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/IMatterGraphListener.kt similarity index 58% rename from src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/IMatterGraphNode.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/IMatterGraphListener.kt index c64294c2c..1d2177c8e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/IMatterGraphNode.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/IMatterGraphListener.kt @@ -1,7 +1,6 @@ package ru.dbotthepony.mc.otm.graph.matter import ru.dbotthepony.mc.otm.capability.matter.* -import ru.dbotthepony.mc.otm.graph.Graph6Node interface IMatterGraphListener { fun onPatternAdded(state: IPatternState) {} @@ -13,12 +12,3 @@ interface IMatterGraphListener { fun onMatterTaskFinished(state: IReplicationTask<*>) {} fun onMatterTaskRemoved(state: IReplicationTask<*>) {} } - -interface IMatterGraphNode : IMatterGraphListener { - fun getMatterHandler(): IMatterStorage? = null - fun getPatternHandler(): IPatternStorage? = null - fun getTaskHandler(): IReplicationTaskProvider? = null - - val matterNode: Graph6Node - val matterGraph: MatterNetworkGraph? get() = matterNode.graph as MatterNetworkGraph? -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterNetworkGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterGraph.kt similarity index 64% rename from src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterNetworkGraph.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterGraph.kt index 8fea4f865..b0e0e2a10 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterNetworkGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterGraph.kt @@ -1,30 +1,25 @@ package ru.dbotthepony.mc.otm.graph.matter -import com.google.common.collect.Streams -import net.minecraft.server.level.ServerLevel +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import net.minecraft.world.item.Item -import net.minecraft.world.level.block.entity.BlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection -import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.core.filterNotNull import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.graph.Abstract6Graph -import ru.dbotthepony.mc.otm.graph.Graph6Node import java.util.* import java.util.function.Predicate import java.util.stream.Stream -import kotlin.collections.HashSet @Suppress("unused") -class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListener { - private val listeners = HashSet() +class MatterGraph : Abstract6Graph(), IMatterGraphListener { + private val listeners = ObjectOpenHashSet() fun addListener(listener: IMatterGraphListener) = listeners.add(listener) fun removeListener(listener: IMatterGraphListener) = listeners.remove(listener) - override fun onNodeRemoved(node: Graph6Node) { - val patterns = node.value.getPatternHandler() + override fun onNodeRemoved(node: MatterNode) { + val patterns = node.getPatternHandler() if (patterns != null) { for (pattern in patterns.patterns) { @@ -32,7 +27,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe } } - val tasks = node.value.getTaskHandler() + val tasks = node.getTaskHandler() if (tasks != null) { for (task in tasks.replicationTasks) { @@ -41,24 +36,24 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe } for (pattern in this.patterns) { - node.value.onPatternRemoved(pattern) + node.onPatternRemoved(pattern) } for (task in this.tasks) { - node.value.onMatterTaskRemoved(task) + node.onMatterTaskRemoved(task) } } - override fun onNodeAdded(node: Graph6Node) { + override fun onNodeAdded(node: MatterNode) { for (pattern in this.patterns) { - node.value.onPatternAdded(pattern) + node.onPatternAdded(pattern) } for (task in this.tasks) { - node.value.onMatterTaskCreated(task) + node.onMatterTaskCreated(task) } - val patterns = node.value.getPatternHandler() + val patterns = node.getPatternHandler() if (patterns != null) { for (pattern in patterns.patterns) { @@ -66,7 +61,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe } } - val tasks = node.value.getTaskHandler() + val tasks = node.getTaskHandler() if (tasks != null) { for (task in tasks.replicationTasks) { @@ -79,7 +74,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe var level = Decimal.ZERO for (node in nodes) { - val matter = node.value.getMatterHandler() + val matter = node.getMatterHandler() if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) { level += matter.storedMatter @@ -93,7 +88,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe var level = Decimal.ZERO for (node in nodes) { - val matter = node.value.getMatterHandler() + val matter = node.getMatterHandler() if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) { level += matter.maxStoredMatter @@ -112,7 +107,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe var extracted = Decimal.ZERO for (node in nodes) { - val matter = node.value.getMatterHandler() + val matter = node.getMatterHandler() if (matter != null) { val value = matter.extractMatter(howMuch, simulate) @@ -136,7 +131,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe var received = Decimal.ZERO for (node in nodes) { - val matter = node.value.getMatterHandler() + val matter = node.getMatterHandler() if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) { val value = matter.receiveMatter(howMuch, simulate) @@ -160,7 +155,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe var received = Decimal.ZERO for (node in nodes) { - val matter = node.value.getMatterHandler() + val matter = node.getMatterHandler() if (matter != null && matter.matterFlow != FlowDirection.OUTPUT) { val value = matter.receiveMatter(howMuch, simulate) @@ -177,7 +172,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe private fun doInsertPattern(state: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus { for (node in nodes) { - val storage = node.value.getPatternHandler() + val storage = node.getPatternHandler() if (storage != null) { val status = storage.insertPattern(state, onlyUpdate, simulate) @@ -198,23 +193,23 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe return doInsertPattern(state, false, simulate) } - val tasks: Stream> get() { - return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.replicationTasks }.toTypedArray()) + val tasks: Stream> get() { + return nodes.stream().map { it.getTaskHandler()?.replicationTasks }.filterNotNull().flatMap { it } } - val allTasks: Stream> get() { - return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.allReplicationTasks }.toTypedArray()) + val allTasks: Stream> get() { + return nodes.stream().map { it.getTaskHandler()?.allReplicationTasks }.filterNotNull().flatMap { it } } - val patterns: Stream get() { - return nodes.stream().map { it.value.getPatternHandler()?.patterns }.filterNotNull().flatMap { it } + val patterns: Stream get() { + return nodes.stream().map { it.getPatternHandler()?.patterns }.filterNotNull().flatMap { it } } val patternCount: Long get() { var value = 0L for (node in nodes) { - val storage = node.value.getPatternHandler() + val storage = node.getPatternHandler() if (storage != null) { value += storage.storedPatterns @@ -228,7 +223,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe var value = 0L for (node in nodes) { - val storage = node.value.getPatternHandler() + val storage = node.getPatternHandler() if (storage != null) { value += storage.patternCapacity @@ -240,7 +235,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe fun getPattern(id: UUID): IPatternState? { for (node in nodes) { - val storage = node.value.getPatternHandler() + val storage = node.getPatternHandler() if (storage != null) { val get = storage.getPattern(id) @@ -260,7 +255,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe fun findPattern(predicate: Predicate): IPatternState? { for (node in nodes) { - val storage = node.value.getPatternHandler() + val storage = node.getPatternHandler() if (storage != null) { val find = storage.patterns.filter(predicate).findAny() @@ -284,7 +279,7 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? { for (node in nodes) { - val tasks = node.value.getTaskHandler() + val tasks = node.getTaskHandler() if (tasks != null) { val allocated = tasks.allocateTask(simulate) @@ -299,87 +294,41 @@ class MatterNetworkGraph : Abstract6Graph(), IMatterGraphListe } fun notifyTaskCompletion(taskId: UUID): Boolean { - return nodes.any { it.value.getTaskHandler()?.notifyTaskCompletion(taskId) == true } + return nodes.any { it.getTaskHandler()?.notifyTaskCompletion(taskId) == true } } override fun onPatternAdded(state: IPatternState) { - for (node in nodes) node.value.onPatternAdded(state) + for (node in nodes) node.onPatternAdded(state) for (node in listeners) node.onPatternAdded(state) } override fun onPatternRemoved(state: IPatternState) { - for (node in nodes) node.value.onPatternRemoved(state) + for (node in nodes) node.onPatternRemoved(state) for (node in listeners) node.onPatternRemoved(state) } override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) { - for (node in nodes) node.value.onPatternUpdated(newState, oldState) + for (node in nodes) node.onPatternUpdated(newState, oldState) for (node in listeners) node.onPatternUpdated(newState, oldState) } override fun onMatterTaskCreated(task: IReplicationTask<*>) { - for (node in nodes) node.value.onMatterTaskCreated(task) + for (node in nodes) node.onMatterTaskCreated(task) for (node in listeners) node.onMatterTaskCreated(task) } override fun > onMatterTaskUpdated(newState: T, oldState: T) { - for (node in nodes) node.value.onMatterTaskUpdated(newState, oldState) + for (node in nodes) node.onMatterTaskUpdated(newState, oldState) for (node in listeners) node.onMatterTaskUpdated(newState, oldState) } override fun onMatterTaskFinished(state: IReplicationTask<*>) { - for (node in nodes) node.value.onMatterTaskFinished(state) + for (node in nodes) node.onMatterTaskFinished(state) for (node in listeners) node.onMatterTaskFinished(state) } override fun onMatterTaskRemoved(state: IReplicationTask<*>) { - for (node in nodes) node.value.onMatterTaskRemoved(state) + for (node in nodes) node.onMatterTaskRemoved(state) for (node in listeners) node.onMatterTaskRemoved(state) } - - companion object { - @JvmStatic - fun discoverFull(tile: BlockEntity, node: Graph6Node) { - if (tile.level !is ServerLevel) - return - - return discoverFull( - tile.level!! as ServerLevel, - tile.blockPos, - node, - fun(_tile): Graph6Node? { - val resolve = _tile.getCapability(MatteryCapability.MATTER_NODE) - - return if (resolve.isPresent) { - resolve.resolve().get().matterNode - } else { - null - } - }, - ::MatterNetworkGraph - ) - } - - @JvmStatic - fun discover(tile: BlockEntity, node: Graph6Node): Boolean { - if (tile.level !is ServerLevel) - return false - - return discover( - tile.level!! as ServerLevel, - tile.blockPos, - node, - fun(_tile): Graph6Node? { - val resolve = _tile.getCapability(MatteryCapability.MATTER_NODE) - - return if (resolve.isPresent) { - resolve.resolve().get().matterNode - } else { - null - } - }, - ::MatterNetworkGraph - ) - } - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterNode.kt new file mode 100644 index 000000000..33b885a98 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/MatterNode.kt @@ -0,0 +1,18 @@ +package ru.dbotthepony.mc.otm.graph.matter + +import net.minecraft.world.level.block.entity.BlockEntity +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage +import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage +import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider +import ru.dbotthepony.mc.otm.graph.Graph6Node + +open class MatterNode : Graph6Node(::MatterGraph), IMatterGraphListener { + open fun getMatterHandler(): IMatterStorage? = null + open fun getPatternHandler(): IPatternStorage? = null + open fun getTaskHandler(): IReplicationTaskProvider? = null + + fun discover(blockEntity: BlockEntity) { + discover(blockEntity, MatteryCapability.MATTER_NODE) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/SimpleMatterNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/SimpleMatterNode.kt new file mode 100644 index 000000000..6f171f85c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/matter/SimpleMatterNode.kt @@ -0,0 +1,23 @@ +package ru.dbotthepony.mc.otm.graph.matter + +import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage +import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage +import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider + +open class SimpleMatterNode( + private val matter: IMatterStorage? = null, + private val patterns: IPatternStorage? = null, + private val tasks: IReplicationTaskProvider? = null, +) : MatterNode() { + override fun getMatterHandler(): IMatterStorage? { + return matter + } + + override fun getPatternHandler(): IPatternStorage? { + return patterns + } + + override fun getTaskHandler(): IReplicationTaskProvider? { + return tasks + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt deleted file mode 100644 index 4362f1b55..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt +++ /dev/null @@ -1,22 +0,0 @@ -package ru.dbotthepony.mc.otm.graph.storage - -import ru.dbotthepony.mc.otm.graph.Graph6Node -import ru.dbotthepony.mc.otm.storage.IStorage - -interface IStorageGraphNode { - /** - * Called by storage graph on node being attached to it - */ - fun attachComponents(to: StorageNetworkGraph) - - /** - * Called by storage graph on node being detached from it - * - * This is NOT called when graph is being destroyed (e.g. even by merging - * with another graph). - */ - fun removeComponents(from: StorageNetworkGraph) - - val storageNode: Graph6Node - val storageGraph: StorageNetworkGraph? get() = storageNode.graph as StorageNetworkGraph? -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageGraph.kt similarity index 60% rename from src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageGraph.kt index a86764829..4e06a4d53 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageGraph.kt @@ -14,8 +14,9 @@ import ru.dbotthepony.mc.otm.core.orNull import ru.dbotthepony.mc.otm.storage.* import java.util.LinkedList -class StorageNetworkGraph(private val level: Level) : Abstract6Graph() { +class StorageGraph : Abstract6Graph() { private val virtualComponents = Object2ObjectArrayMap, VirtualComponent<*>>() + val powerDemandingNodes = LinkedList() /** * Returns a [VirtualComponent] representing [type] storage @@ -31,8 +32,6 @@ class StorageNetworkGraph(private val level: Level) : Abstract6Graph } - private var addedTicker = false - fun add(storage: IStorage) { getVirtualComponent(storage.storageType).add(storage) } @@ -46,50 +45,12 @@ class StorageNetworkGraph(private val level: Level) : Abstract6Graph).contains(storage) } - override fun onNodeAdded(node: Graph6Node) { - node.value.attachComponents(this) - - if (!addedTicker) { - addedTicker = true - level.addTickerPre(this) - } + override fun onNodeAdded(node: StorageNode) { + node.attachComponents(this) } - override fun onNodeRemoved(node: Graph6Node) { - node.value.removeComponents(this) + override fun onNodeRemoved(node: StorageNode) { + node.removeComponents(this) } - val powerDemandingNodes = LinkedList() - - companion object { - @JvmStatic - fun discoverFull(tile: BlockEntity, node: Graph6Node) { - if (tile.level !is ServerLevel) - return - - return discoverFull( - tile.level as ServerLevel, - tile.blockPos, - node, - fun(_tile): Graph6Node? { - return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode - } - ) { StorageNetworkGraph(tile.level!!) } - } - - @JvmStatic - fun discover(tile: BlockEntity, node: Graph6Node): Boolean { - if (tile.level !is ServerLevel) - return false - - return discover( - tile.level as ServerLevel, - tile.blockPos, - node, - fun(_tile): Graph6Node? { - return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode - }, - ) { StorageNetworkGraph(tile.level!!) } - } - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNode.kt similarity index 61% rename from src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNode.kt index b0f52a83b..a5b57a4b5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNode.kt @@ -1,7 +1,7 @@ package ru.dbotthepony.mc.otm.graph.storage -import net.minecraft.world.level.Level -import net.minecraftforge.common.util.LazyOptional +import net.minecraft.world.level.block.entity.BlockEntity +import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.storage.IStorage @@ -9,9 +9,7 @@ import ru.dbotthepony.mc.otm.storage.IStorageStack import ru.dbotthepony.mc.otm.storage.StorageStackType import java.util.* -open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStorage? = null) : IStorageGraphNode { - private var resolver = LazyOptional.of { this } - private var valid = true +open class StorageNode(private val energyDemander: IMatteryEnergyStorage? = null) : Graph6Node(::StorageGraph) { protected val components = ArrayList>() /** @@ -22,13 +20,12 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora * [invalidate] and [removeComponents] still detach all components */ protected var manualAttaching = false - - @Suppress("LeakingThis") - final override val storageNode = Graph6Node(this) - private var demandingEnergy = false - override fun attachComponents(to: StorageNetworkGraph) { + /** + * Called by storage graph on node being attached to it + */ + open fun attachComponents(to: StorageGraph) { if (energyDemander != null) { if (energyDemander.missingPower.isPositive) { demandingEnergy = true @@ -45,19 +42,13 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora } } - fun tickEnergyDemanding() { - energyDemander ?: throw IllegalStateException("No energy demander") - - if (!demandingEnergy && storageGraph != null && energyDemander.missingPower.isPositive) { - demandingEnergy = true - storageGraph!!.powerDemandingNodes.add(energyDemander) - } else if (demandingEnergy && storageGraph != null && !energyDemander.missingPower.isPositive) { - demandingEnergy = false - storageGraph!!.powerDemandingNodes.remove(energyDemander) - } - } - - override fun removeComponents(from: StorageNetworkGraph) { + /** + * Called by storage graph on node being detached from it + * + * This is NOT called when graph is being destroyed (e.g. even by merging + * with another graph). + */ + open fun removeComponents(from: StorageGraph) { for (component in components) { from.remove(component) } @@ -68,6 +59,18 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora } } + fun tickEnergyDemanding() { + energyDemander ?: throw IllegalStateException("No energy demander") + + if (!demandingEnergy && energyDemander.missingPower.isPositive) { + demandingEnergy = true + graph.powerDemandingNodes.add(energyDemander) + } else if (demandingEnergy && !energyDemander.missingPower.isPositive) { + demandingEnergy = false + graph.powerDemandingNodes.remove(energyDemander) + } + } + @Suppress("unchecked_cast") fun > computeIfAbsent(identity: StorageStackType, provider: (StorageStackType) -> U): U { for (component in components) { @@ -90,8 +93,8 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora components.add(component) - if (valid && !manualAttaching) - storageGraph?.add(component) + if (isValid && !manualAttaching) + graph.add(component) } fun removeStorageComponent(component: IStorage<*>) { @@ -111,8 +114,8 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora val self = components[indexOf] components.removeAt(indexOf) - if (valid) - storageGraph?.remove(self) + if (isValid) + graph.remove(self) } fun removeStorageComponent(component: StorageStackType<*>) { @@ -132,47 +135,25 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora val self = components[indexOf] components.removeAt(indexOf) - if (valid && !manualAttaching) - storageGraph?.remove(self) + if (isValid && !manualAttaching) + graph.remove(self) } - open fun invalidate() { - if (!valid) return - valid = false - resolver.invalidate() + override fun invalidate() { + for (component in components) { + graph.remove(component) + } + } - val storageGraph = storageGraph - - if (storageGraph != null) { + override fun revive() { + if (!manualAttaching) { for (component in components) { - storageGraph.remove(component) + graph.add(component) } } } - open fun revive() { - if (valid) return - valid = true - resolver = LazyOptional.of { this } - - val storageGraph = storageGraph - - if (storageGraph != null && !manualAttaching) { - for (component in components) { - storageGraph.add(component) - } - } - } - - fun get(): LazyOptional { - return if (valid) resolver else LazyOptional.empty() - } - - fun destroy(level: Level?) { - if (level != null) { - storageNode.destroy { StorageNetworkGraph(level) } - } else { - storageGraph?.removeNode(storageNode) - } + fun discover(blockEntity: BlockEntity) { + discover(blockEntity, MatteryCapability.STORAGE_NODE) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt index 33371430e..ec591c7c7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt @@ -45,8 +45,8 @@ class MatterBottlerMenu @JvmOverloads constructor( storageSlots = immutableList(6) { index -> object : MatterySlot(container, index) { - override fun mayPlace(p_40231_: ItemStack): Boolean { - val cap = p_40231_.getCapability(MatteryCapability.MATTER).orNull() ?: return false + override fun mayPlace(itemStack: ItemStack): Boolean { + val cap = itemStack.getCapability(MatteryCapability.MATTER).orNull() ?: return false if (workFlow.value) { return index < 3 && cap.canReceiveMatter diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt index 4993feffe..6582c186a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt @@ -29,9 +29,9 @@ class MatterCapacitorBankMenu @JvmOverloads constructor( } else { matterGauge = LevelGaugeWidget(this, tile) totalMatterGauge = LevelGaugeWidget(this, { - tile.matterGraph?.getMatterStorageLevel() ?: Decimal.ZERO + tile.matterNode.graph.getMatterStorageLevel() }, { - tile.matterGraph?.getMatterStorageMaxLevel() ?: Decimal.ZERO + tile.matterNode.graph.getMatterStorageMaxLevel() }) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt index e7b237950..28397e409 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt @@ -19,7 +19,7 @@ import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec import ru.dbotthepony.mc.otm.core.util.ItemSorter import ru.dbotthepony.mc.otm.core.util.codec import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener -import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph +import ru.dbotthepony.mc.otm.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.registry.MMenus @@ -176,7 +176,7 @@ class MatterPanelMenu @JvmOverloads constructor( }) val totalMatterStored: Decimal by mSynchronizer.ComputedField( - getter = { tile?.matterGraph?.getMatterStorageLevel() ?: Decimal.ZERO }, + getter = { tile?.matterNode?.graph?.getMatterStorageLevel() ?: Decimal.ZERO }, codec = DecimalValueCodec, ) @@ -278,8 +278,7 @@ class MatterPanelMenu @JvmOverloads constructor( val tile = tile as MatterPanelBlockEntity? ?: return - val graph = tile.matterGraph ?: return - val state = graph.getPattern(id) + val state = tile.matterNode.graph.getPattern(id) if (state == null) { LOGGER.error("Received replication request from {} of {}, but it is not found in grid", ply, id) @@ -312,14 +311,13 @@ class MatterPanelMenu @JvmOverloads constructor( } private var initialSend = false - - private var listeningGrid: MatterNetworkGraph? = null + private var listeningGrid: MatterGraph? = null init { if (tile != null) { - listeningGrid = tile.matterGraph + listeningGrid = tile.matterNode.graph tile.attachMenu(this) - listeningGrid?.addListener(this) + listeningGrid!!.addListener(this) } } @@ -347,13 +345,9 @@ class MatterPanelMenu @JvmOverloads constructor( val tile = tile as MatterPanelBlockEntity? if (tile != null) { - val grid = tile.matterGraph - - if (grid != null) { - initialSend = true - sendNetwork(PatternsChangePacket(true, grid.patterns.toList())) - } - + val grid = tile.matterNode.graph + initialSend = true + sendNetwork(PatternsChangePacket(true, grid.patterns.toList())) sendNetwork(TasksChangePacket(true, tile.allReplicationTasks.toList())) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt index d590773c9..b025ddf03 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt @@ -1,9 +1,7 @@ package ru.dbotthepony.mc.otm.menu.matter -import com.google.common.collect.ImmutableList import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.inventory.Slot import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity import ru.dbotthepony.mc.otm.item.MatterDustItem @@ -26,8 +24,8 @@ class MatterRecyclerMenu @JvmOverloads constructor( val container = tile?.container ?: SimpleContainer(1) input = object : MatterySlot(container, 0) { - override fun mayPlace(p_40231_: ItemStack): Boolean { - return p_40231_.item is MatterDustItem && (p_40231_.item as MatterDustItem).getMatterValue(p_40231_) != null + override fun mayPlace(itemStack: ItemStack): Boolean { + return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt index d0b36b5b8..e218d2630 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt @@ -36,8 +36,8 @@ class MatterScannerMenu @JvmOverloads constructor( if (tile != null) { progress = ProgressGaugeWidget(this, tile::workProgress, tile::isUnableToProcess) patterns = LevelGaugeWidget(this, - { Decimal(tile.matterGraph?.patternCount ?: 0L) }, - { Decimal(tile.matterGraph?.patternCapacity ?: 0L) }) + { Decimal(tile.matterNode.graph.patternCount) }, + { Decimal(tile.matterNode.graph.patternCapacity) }) } else { progress = ProgressGaugeWidget(this) patterns = LevelGaugeWidget(this) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt index 7307b7867..a5163cd6a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt @@ -29,9 +29,9 @@ class PatternStorageMenu @JvmOverloads constructor( } else { storedThis = LevelGaugeWidget(this, tile) storedGrid = LevelGaugeWidget(this, { - Decimal(tile.matterGraph?.patternCount ?: 0) + Decimal(tile.matterNode.graph.patternCount) }, { - Decimal(tile.matterGraph?.patternCapacity ?: 0) + Decimal(tile.matterNode.graph.patternCapacity) }) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StoragePowerSupplierMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StoragePowerSupplierMenu.kt index e62778ed3..e1f84a444 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StoragePowerSupplierMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StoragePowerSupplierMenu.kt @@ -22,7 +22,7 @@ class StoragePowerSupplierMenu @JvmOverloads constructor( override fun broadcastChanges() { if (tile is StoragePowerSupplierBlockEntity) { totalTransferred = tile.powerPassed - activeNodes = tile.cell.storageGraph?.powerDemandingNodes?.size ?: 0 + activeNodes = tile.cell.graph.powerDemandingNodes.size } super.broadcastChanges()