From 7152108cc88bd8b2205e692c7e4fdef56c8e83cd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 21 Mar 2022 23:40:22 +0700 Subject: [PATCH] Improve ticker, actually remove nodes from storage graph --- .../kotlin/ru/dbotthepony/mc/otm/Ticker.kt | 190 +++++++++++++----- .../mc/otm/block/ChemicalGeneratorBlock.kt | 5 +- .../otm/block/GravitationStabilizerBlock.kt | 10 +- .../mc/otm/block/StorageBusBlock.kt | 5 +- .../otm/block/entity/DriveRackBlockEntity.kt | 7 +- .../block/entity/ItemMonitorBlockEntity.kt | 5 + .../mc/otm/block/entity/MatteryBlockEntity.kt | 13 +- .../otm/block/entity/StorageBusBlockEntity.kt | 5 + .../mc/otm/graph/Abstract6Graph.kt | 53 ++++- .../ru/dbotthepony/mc/otm/graph/Graph6Node.kt | 21 +- .../graph/storage/BasicStorageGraphNode.kt | 11 +- .../otm/graph/storage/StorageNetworkGraph.kt | 24 ++- 12 files changed, 261 insertions(+), 88 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/Ticker.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/Ticker.kt index c996c767a..41efcab87 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/Ticker.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/Ticker.kt @@ -1,89 +1,177 @@ + +@file:Suppress("unused", "UNUSED_PARAMETER") + package ru.dbotthepony.mc.otm -import net.minecraft.client.multiplayer.ClientLevel -import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.Level import net.minecraftforge.event.TickEvent +import net.minecraftforge.event.TickEvent.ServerTickEvent import net.minecraftforge.event.TickEvent.WorldTickEvent import net.minecraftforge.event.server.ServerAboutToStartEvent import net.minecraftforge.event.server.ServerStoppingEvent import net.minecraftforge.eventbus.api.EventPriority import net.minecraftforge.eventbus.api.SubscribeEvent -import net.minecraftforge.fml.LogicalSide import java.util.* -import java.util.function.Consumer -import java.util.function.Supplier +import kotlin.collections.ArrayList -private val tick_until = WeakHashMap>>() -private val tick_once = WeakHashMap>() +private val preServerTick = ArrayList() +private val postServerTick = ArrayList() +private val preServerTickOnce = ArrayList() +private val postServerTickOnce = ArrayList() -@SubscribeEvent(priority = EventPriority.HIGHEST) -@Suppress("unused") -fun onServerStarting(event: ServerAboutToStartEvent?) { - tick_until.clear() +private val preWorldTick = WeakHashMap>() +private val postWorldTick = WeakHashMap>() +private val preWorldTickOnce = WeakHashMap>() +private val postWorldTickOnce = WeakHashMap>() + +fun interface ITickable { + fun tick() } -@SubscribeEvent(priority = EventPriority.HIGHEST) -@Suppress("unused") -fun onServerStopping(event: ServerStoppingEvent?) { - tick_until.clear() +interface IConditionalTickable : ITickable { + /** + * Once this returns false, it should stay false. + * + * If it suddenly turns true after being false, result is undefined. + */ + val canTick: Boolean } @SubscribeEvent(priority = EventPriority.LOWEST) -@Suppress("unused") -fun onPreTick(event: WorldTickEvent) { - if (event.phase != TickEvent.Phase.START || event.side != LogicalSide.SERVER) return +fun onServerTick(event: ServerTickEvent) { + if (event.phase === TickEvent.Phase.START) { + for (i in preServerTick.size - 1 downTo 0) { + val ticker = preServerTick[i] - // удаляем список сразу что бы если кто-либо добавит туда элементы у нас была "копия" - val until = tick_until.remove(event.world) - - if (until != null) { - for (i in until.indices.reversed()) { - if (until[i].get()) { - until.removeAt(i) + if (!ticker.canTick) { + preServerTick.removeAt(i) + } else { + ticker.tick() } } - if (until.size != 0) { - val replaced = tick_until.put(event.world, until) + for (i in preServerTickOnce.size - 1 downTo 0) { + preServerTickOnce[i].tick() + preServerTickOnce.removeAt(i) + } + } else { + for (i in postServerTick.size - 1 downTo 0) { + val ticker = postServerTick[i] - if (replaced != null) { - until.addAll(replaced) + if (!ticker.canTick) { + postServerTick.removeAt(i) + } else { + ticker.tick() + } + } + + for (i in postServerTickOnce.size - 1 downTo 0) { + postServerTickOnce[i].tick() + postServerTickOnce.removeAt(i) + } + } +} + +fun addPreServerTicker(ticker: IConditionalTickable) { + preServerTick.add(ticker) +} + +fun addPostServerTicker(ticker: IConditionalTickable) { + postServerTick.add(ticker) +} + +fun addPreServerTickerOnce(ticker: ITickable) { + preServerTickOnce.add(ticker) +} + +fun addPostServerTickerOnce(ticker: ITickable) { + postServerTickOnce.add(ticker) +} + +@SubscribeEvent(priority = EventPriority.LOWEST) +fun onWorldTick(event: WorldTickEvent) { + if (event.phase === TickEvent.Phase.START) { + val it = preWorldTick[event.world] + + if (it != null) { + for (i in it.size - 1 downTo 0) { + val ticker = it[i] + + if (!ticker.canTick) { + it.removeAt(i) + } else { + ticker.tick() + } + } + } + + val it2 = preWorldTickOnce.remove(event.world) + + if (it2 != null) { + for (i in it2.size - 1 downTo 0) { + it2[i].tick() + it2.removeAt(i) + } + } + } else { + val it = postWorldTick[event.world] + + if (it != null) { + for (i in it.size - 1 downTo 0) { + val ticker = it[i] + + if (!ticker.canTick) { + it.removeAt(i) + } else { + ticker.tick() + } + } + } + + val it2 = postWorldTickOnce.remove(event.world) + + if (it2 != null) { + for (i in it2.size - 1 downTo 0) { + it2[i].tick() + it2.removeAt(i) } } } - - val once = tick_once.remove(event.world) - - if (once != null) - for (ticker in once) - ticker.run() } -fun tickUntil(level: Level, ticker: Supplier) { - tick_until.computeIfAbsent(level) { ArrayList() }.add(ticker) +fun addPreWorldTicker(level: Level, ticker: IConditionalTickable) { + preWorldTick.computeIfAbsent(level) { ArrayList() }.add(ticker) } -fun tickUntilServer(level: Level, ticker: Supplier) { - if (level is ServerLevel) - tick_until.computeIfAbsent(level) { ArrayList() }.add(ticker) +fun addPostWorldTicker(level: Level, ticker: IConditionalTickable) { + postWorldTick.computeIfAbsent(level) { ArrayList() }.add(ticker) } -fun tickUntilClient(level: Level, ticker: Supplier) { - if (level is ClientLevel) - tick_until.computeIfAbsent(level) { ArrayList() }.add(ticker) +fun addPreWorldTickerOnce(level: Level, ticker: ITickable) { + preWorldTickOnce.computeIfAbsent(level) { ArrayList() }.add(ticker) } -fun tickOnce(level: Level, ticker: Runnable) { - tick_once.computeIfAbsent(level) { ArrayList() }.add(ticker) +fun addPostWorldTickerOnce(level: Level, ticker: ITickable) { + postWorldTickOnce.computeIfAbsent(level) { ArrayList() }.add(ticker) } -fun tickOnceServer(level: Level, ticker: Runnable) { - if (level is ServerLevel) - tick_once.computeIfAbsent(level) { ArrayList() }.add(ticker) +private fun clear() { + preServerTick.clear() + postServerTick.clear() + preWorldTick.clear() + postWorldTick.clear() + preServerTickOnce.clear() + postServerTickOnce.clear() + preWorldTickOnce.clear() + postWorldTickOnce.clear() } -fun tickOnceClient(level: Level, ticker: Runnable) { - if (level is ClientLevel) - tick_once.computeIfAbsent(level) { ArrayList() }.add(ticker) +@SubscribeEvent(priority = EventPriority.HIGHEST) +fun onServerStarting(event: ServerAboutToStartEvent?) { + clear() +} + +@SubscribeEvent(priority = EventPriority.HIGHEST) +fun onServerStopping(event: ServerStoppingEvent?) { + clear() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt index dc5c59116..bcc9e7de2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/ChemicalGeneratorBlock.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block import net.minecraft.core.BlockPos import net.minecraft.core.Direction -import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.Level import net.minecraft.world.level.block.Block @@ -14,11 +13,11 @@ import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.StateDefinition import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape +import ru.dbotthepony.mc.otm.addPreWorldTickerOnce import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.shapes.BlockShapes -import ru.dbotthepony.mc.otm.tickOnceServer class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock { override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity { @@ -55,7 +54,7 @@ class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock { val tile = level.getBlockEntity(pos) if (tile is ChemicalGeneratorBlockEntity) { - tickOnceServer(level) { + addPreWorldTickerOnce(level) { tile.checkSurroundings() } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt index 58013eadd..1ab676aca 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/GravitationStabilizerBlock.kt @@ -22,6 +22,7 @@ import net.minecraft.world.level.material.MaterialColor import net.minecraft.world.level.material.PushReaction import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape +import ru.dbotthepony.mc.otm.addPreWorldTickerOnce import ru.dbotthepony.mc.otm.block.entity.GravitationStabilizerBlockEntity import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState @@ -30,7 +31,6 @@ import ru.dbotthepony.mc.otm.core.times import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.shapes.BlockShapes -import ru.dbotthepony.mc.otm.tickOnceServer import kotlin.math.PI private val props = BlockBehaviour.Properties.of(Material.STONE, MaterialColor.COLOR_BLUE).requiresCorrectToolForDrops().strength(3f, 600.0f) @@ -120,8 +120,8 @@ class BlockGravitationStabilizer : RotatableMatteryBlock(props), EntityBlock { ) { super.neighborChanged(state, level, pos, sender, sender_pos, flag) - tickOnceServer(level) { - if (level.getBlockState(pos).block !is BlockGravitationStabilizer) return@tickOnceServer + addPreWorldTickerOnce(level) { + if (level.getBlockState(pos).block !is BlockGravitationStabilizer) return@addPreWorldTickerOnce val bb = getBoundingBlock(level, state, pos) if (bb.block !is BlockGravitationStabilizerLens) { @@ -181,8 +181,8 @@ class BlockGravitationStabilizerLens : RotatableMatteryBlock(props) { ) { super.neighborChanged(state, level, pos, sender, sender_pos, flag) - tickOnceServer(level) { - if (level.getBlockState(pos).block !is BlockGravitationStabilizerLens) return@tickOnceServer + addPreWorldTickerOnce(level) { + if (level.getBlockState(pos).block !is BlockGravitationStabilizerLens) return@addPreWorldTickerOnce val bb = getBoundingBlock(level, state, pos) if (bb.block !is BlockGravitationStabilizer) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageBusBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageBusBlock.kt index c6103aff4..07ec88c29 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageBusBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/StorageBusBlock.kt @@ -9,10 +9,9 @@ import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.entity.BlockEntityTicker import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.BlockState -import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity +import ru.dbotthepony.mc.otm.addPreWorldTickerOnce import ru.dbotthepony.mc.otm.block.entity.StorageBusBlockEntity import ru.dbotthepony.mc.otm.registry.MBlockEntities -import ru.dbotthepony.mc.otm.tickOnceServer import ru.dbotthepony.mc.otm.unaryMinus class StorageBusBlock : RotatableMatteryBlock(), EntityBlock { @@ -51,7 +50,7 @@ class StorageBusBlock : RotatableMatteryBlock(), EntityBlock { val tile = level.getBlockEntity(pos) if (tile is StorageBusBlockEntity) { - tickOnceServer(level) { + addPreWorldTickerOnce(level) { tile.checkSurroundings() } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt index 1ce2a7c15..a8aff8b56 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt @@ -81,7 +81,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override val defaultDisplayName: Component get() = MACHINE_NAME - override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? { + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return DriveRackMenu(containerID, inventory, this) } @@ -101,6 +101,11 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : cell.revive() } + override fun setRemoved() { + super.setRemoved() + cell.destroy(level) + } + companion object { private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.drive_rack") private val STORAGE = ImpreciseFraction(80_000) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ItemMonitorBlockEntity.kt index c0468440f..fe8f29334 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ItemMonitorBlockEntity.kt @@ -59,6 +59,11 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : cell.revive() } + override fun setRemoved() { + super.setRemoved() + cell.destroy(level) + } + companion object { private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.item_monitor") } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt index 31ca49146..d4b280222 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt @@ -22,6 +22,7 @@ import net.minecraft.nbt.ByteTag import net.minecraft.network.chat.Component import net.minecraft.world.level.Level import net.minecraftforge.common.capabilities.Capability +import ru.dbotthepony.mc.otm.addPreWorldTickerOnce import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.set @@ -70,32 +71,32 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc protected fun tickOnce(func: Runnable) { val level = level - if (level != null) ru.dbotthepony.mc.otm.tickOnce(level) { if (!isRemoved) func.run() } + if (level != null) addPreWorldTickerOnce(level) { if (!isRemoved) func.run() } } protected fun tickOnceServer(func: Runnable) { val level = level - if (level is ServerLevel) ru.dbotthepony.mc.otm.tickOnce(level) { if (!isRemoved) func.run() } + if (level is ServerLevel) addPreWorldTickerOnce(level) { if (!isRemoved) func.run() } } protected fun tickOnceClient(func: Runnable) { val level = level - if (level is ClientLevel) ru.dbotthepony.mc.otm.tickOnce(level) { if (!isRemoved) func.run() } + if (level is ClientLevel) addPreWorldTickerOnce(level) { if (!isRemoved) func.run() } } protected fun tickOnce(func: (Level) -> Unit) { val level = level - if (level != null) ru.dbotthepony.mc.otm.tickOnce(level) { if (!isRemoved) func(level) } + if (level != null) addPreWorldTickerOnce(level) { if (!isRemoved) func(level) } } protected fun tickOnceServer(func: (ServerLevel) -> Unit) { val level = level - if (level is ServerLevel) ru.dbotthepony.mc.otm.tickOnce(level) { if (!isRemoved) func(level) } + if (level is ServerLevel) addPreWorldTickerOnce(level) { if (!isRemoved) func(level) } } protected fun tickOnceClient(func: (ClientLevel) -> Unit) { val level = level - if (level is ClientLevel) ru.dbotthepony.mc.otm.tickOnce(level) { if (!isRemoved) func(level) } + if (level is ClientLevel) addPreWorldTickerOnce(level) { if (!isRemoved) func(level) } } protected fun getAndBind( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt index 30c71a681..375b848dc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt @@ -333,6 +333,11 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter component?.scan() } + override fun setRemoved() { + super.setRemoved() + cell.destroy(level) + } + fun checkSurroundings() { val front = blockPos + blockState.getValue(RotatableMatteryBlock.FACING_FULL) val storage = level?.getBlockEntity(front)?.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)?.let { if (it.isPresent) it else null } 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 93618fa88..e102d0862 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Abstract6Graph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Abstract6Graph.kt @@ -1,27 +1,51 @@ package ru.dbotthepony.mc.otm.graph +import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap 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.OverdriveThatMatters +import ru.dbotthepony.mc.otm.IConditionalTickable +import ru.dbotthepony.mc.otm.addPreWorldTicker import ru.dbotthepony.mc.otm.core.plus -import ru.dbotthepony.mc.otm.tickUntil import java.util.* import kotlin.collections.ArrayList -abstract class Abstract6Graph { +abstract class Abstract6Graph : IConditionalTickable { @JvmField protected val _nodes = ArrayList>() fun size() = _nodes.size + private val tickable = ArrayList>() + @JvmField - val nodes = Collections.unmodifiableCollection(_nodes) + val nodes: Collection> = Collections.unmodifiableCollection(_nodes) + + /** + * Allows storing arbitrary data by external code + */ + @JvmField + val userData = Object2ObjectAVLTreeMap() abstract fun onNodeRemoved(node: Graph6Node) abstract fun onNodeAdded(node: Graph6Node) + override val canTick: Boolean + get() = _nodes.size > 0 + + override fun tick() { + for (i in tickable.size - 1 downTo 0) { + val node = tickable[i] + + if (node.canTick) { + node.tick() + } else { + tickable.removeAt(i) + } + } + } + fun removeNode(node: Graph6Node) { if (!_nodes.contains(node)) throw IllegalStateException("Not containing node $node") @@ -29,6 +53,10 @@ abstract class Abstract6Graph { _nodes.remove(node) node.graph = null onNodeRemoved(node) + + if (node.canTick) { + tickable.remove(node) + } } fun addNode(node: Graph6Node) { @@ -38,6 +66,10 @@ abstract class Abstract6Graph { _nodes.add(node) node.graph = this onNodeAdded(node) + + if (node.canTick) { + tickable.add(node) + } } fun merge(other: Abstract6Graph): Abstract6Graph { @@ -65,9 +97,16 @@ abstract class Abstract6Graph { nodeGetter: (BlockEntity) -> Graph6Node?, factory: () -> Abstract6Graph ) { - tickUntil(level) { - !node.valid || discover(level, blockPos, node, nodeGetter, factory) - } + addPreWorldTicker(level, object : IConditionalTickable { + override fun tick() { + discovered = discover(level, blockPos, node, nodeGetter, factory) + } + + private var discovered = false + + override val canTick: Boolean + get() = !discovered && node.valid + }) } @JvmStatic 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 27b558425..00b296d69 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/Graph6Node.kt @@ -1,6 +1,8 @@ package ru.dbotthepony.mc.otm.graph import net.minecraft.core.Direction +import ru.dbotthepony.mc.otm.IConditionalTickable +import ru.dbotthepony.mc.otm.ITickable interface GraphNodeListener { fun onNeighbourTop(node: Graph6Node<*>) = onNeighbour(node, Direction.UP) @@ -23,7 +25,7 @@ interface GraphNodeListener { } // Вершина графа, содержит то, к какому графу принадлежит, соседей и своё "значение" -class Graph6Node(@JvmField val value: T, graph: Abstract6Graph? = null) { +class Graph6Node(@JvmField val value: T, graph: Abstract6Graph? = null) : IConditionalTickable { var graph: Abstract6Graph? = null init { @@ -182,6 +184,23 @@ class Graph6Node(@JvmField val value: T, graph: Abstract6Graph? = null) { } } + override val canTick: Boolean + get() { + return if (value is IConditionalTickable) { + value.canTick + } else { + value is ITickable + } + } + + override fun tick() { + if (value is ITickable) { + value.tick() + } else { + throw ClassCastException("$value is not tickable") + } + } + var seen: Int = 0 private fun _flood(): List> { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt index fe2a08682..969d0a149 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.graph.storage +import net.minecraft.world.level.Level import net.minecraftforge.common.util.LazyOptional import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.storage.IStorage @@ -117,4 +118,12 @@ open class BasicStorageGraphNode : IStorageGraphNode { fun get(): LazyOptional { return if (valid) resolver else LazyOptional.empty() } -} \ No newline at end of file + + fun destroy(level: Level?) { + if (level != null) { + storageNode.destroy { StorageNetworkGraph(level) } + } else { + storageGraph?.removeNode(storageNode) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt index 662e9bf76..37be683b8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt @@ -3,20 +3,19 @@ package ru.dbotthepony.mc.otm.graph.storage import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import net.minecraft.server.level.ServerLevel +import net.minecraft.world.level.Level import net.minecraft.world.level.block.entity.BlockEntity +import ru.dbotthepony.mc.otm.addPreServerTicker +import ru.dbotthepony.mc.otm.addPreWorldTicker import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.graph.Abstract6Graph import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.orNull import ru.dbotthepony.mc.otm.storage.* -class StorageNetworkGraph : Abstract6Graph() { +class StorageNetworkGraph(private val level: Level) : Abstract6Graph() { private val virtualComponents = Object2ObjectArrayMap, VirtualComponent<*>>() - fun insertStack(obj: T, simulate: Boolean): T { - return (getVirtualComponent(StorageRegistry.get(obj::class.java)) as VirtualComponent).insertStack(obj, simulate) - } - /** * Returns a [VirtualComponent] representing [type] storage */ @@ -31,6 +30,8 @@ class StorageNetworkGraph : Abstract6Graph() { return virtualComponents.computeIfAbsent(StorageRegistry.get(type), Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent } + private var addedTicker = false + fun add(storage: IStorage) { getVirtualComponent(storage.storageType).add(storage) } @@ -43,6 +44,11 @@ class StorageNetworkGraph : Abstract6Graph() { for (identity in node.value.fetchComponents()) { add(identity) } + + if (!addedTicker) { + addedTicker = true + addPreWorldTicker(level, this) + } } override fun onNodeRemoved(node: Graph6Node) { @@ -63,9 +69,8 @@ class StorageNetworkGraph : Abstract6Graph() { node, fun(_tile): Graph6Node? { return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode - }, - ::StorageNetworkGraph - ) + } + ) { StorageNetworkGraph(tile.level!!) } } @JvmStatic @@ -80,8 +85,7 @@ class StorageNetworkGraph : Abstract6Graph() { fun(_tile): Graph6Node? { return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode }, - ::StorageNetworkGraph - ) + ) { StorageNetworkGraph(tile.level!!) } } } } \ No newline at end of file