Improve ticker, actually remove nodes from storage graph

This commit is contained in:
DBotThePony 2022-03-21 23:40:22 +07:00
parent d4aa8cd7ee
commit 7152108cc8
Signed by: DBot
GPG Key ID: DCC23B5715498507
12 changed files with 261 additions and 88 deletions

View File

@ -1,89 +1,177 @@
@file:Suppress("unused", "UNUSED_PARAMETER")
package ru.dbotthepony.mc.otm 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.minecraft.world.level.Level
import net.minecraftforge.event.TickEvent import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.TickEvent.ServerTickEvent
import net.minecraftforge.event.TickEvent.WorldTickEvent import net.minecraftforge.event.TickEvent.WorldTickEvent
import net.minecraftforge.event.server.ServerAboutToStartEvent import net.minecraftforge.event.server.ServerAboutToStartEvent
import net.minecraftforge.event.server.ServerStoppingEvent import net.minecraftforge.event.server.ServerStoppingEvent
import net.minecraftforge.eventbus.api.EventPriority import net.minecraftforge.eventbus.api.EventPriority
import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.LogicalSide
import java.util.* import java.util.*
import java.util.function.Consumer import kotlin.collections.ArrayList
import java.util.function.Supplier
private val tick_until = WeakHashMap<Level, ArrayList<Supplier<Boolean>>>() private val preServerTick = ArrayList<IConditionalTickable>()
private val tick_once = WeakHashMap<Level, ArrayList<Runnable>>() private val postServerTick = ArrayList<IConditionalTickable>()
private val preServerTickOnce = ArrayList<ITickable>()
private val postServerTickOnce = ArrayList<ITickable>()
@SubscribeEvent(priority = EventPriority.HIGHEST) private val preWorldTick = WeakHashMap<Level, ArrayList<IConditionalTickable>>()
@Suppress("unused") private val postWorldTick = WeakHashMap<Level, ArrayList<IConditionalTickable>>()
fun onServerStarting(event: ServerAboutToStartEvent?) { private val preWorldTickOnce = WeakHashMap<Level, ArrayList<ITickable>>()
tick_until.clear() private val postWorldTickOnce = WeakHashMap<Level, ArrayList<ITickable>>()
fun interface ITickable {
fun tick()
} }
@SubscribeEvent(priority = EventPriority.HIGHEST) interface IConditionalTickable : ITickable {
@Suppress("unused") /**
fun onServerStopping(event: ServerStoppingEvent?) { * Once this returns false, it should stay false.
tick_until.clear() *
* If it suddenly turns true after being false, result is undefined.
*/
val canTick: Boolean
} }
@SubscribeEvent(priority = EventPriority.LOWEST) @SubscribeEvent(priority = EventPriority.LOWEST)
@Suppress("unused") fun onServerTick(event: ServerTickEvent) {
fun onPreTick(event: WorldTickEvent) { if (event.phase === TickEvent.Phase.START) {
if (event.phase != TickEvent.Phase.START || event.side != LogicalSide.SERVER) return for (i in preServerTick.size - 1 downTo 0) {
val ticker = preServerTick[i]
// удаляем список сразу что бы если кто-либо добавит туда элементы у нас была "копия" if (!ticker.canTick) {
val until = tick_until.remove(event.world) preServerTick.removeAt(i)
} else {
if (until != null) { ticker.tick()
for (i in until.indices.reversed()) {
if (until[i].get()) {
until.removeAt(i)
} }
} }
if (until.size != 0) { for (i in preServerTickOnce.size - 1 downTo 0) {
val replaced = tick_until.put(event.world, until) preServerTickOnce[i].tick()
preServerTickOnce.removeAt(i)
}
} else {
for (i in postServerTick.size - 1 downTo 0) {
val ticker = postServerTick[i]
if (replaced != null) { if (!ticker.canTick) {
until.addAll(replaced) 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<Boolean>) { fun addPreWorldTicker(level: Level, ticker: IConditionalTickable) {
tick_until.computeIfAbsent(level) { ArrayList() }.add(ticker) preWorldTick.computeIfAbsent(level) { ArrayList() }.add(ticker)
} }
fun tickUntilServer(level: Level, ticker: Supplier<Boolean>) { fun addPostWorldTicker(level: Level, ticker: IConditionalTickable) {
if (level is ServerLevel) postWorldTick.computeIfAbsent(level) { ArrayList() }.add(ticker)
tick_until.computeIfAbsent(level) { ArrayList() }.add(ticker)
} }
fun tickUntilClient(level: Level, ticker: Supplier<Boolean>) { fun addPreWorldTickerOnce(level: Level, ticker: ITickable) {
if (level is ClientLevel) preWorldTickOnce.computeIfAbsent(level) { ArrayList() }.add(ticker)
tick_until.computeIfAbsent(level) { ArrayList() }.add(ticker)
} }
fun tickOnce(level: Level, ticker: Runnable) { fun addPostWorldTickerOnce(level: Level, ticker: ITickable) {
tick_once.computeIfAbsent(level) { ArrayList() }.add(ticker) postWorldTickOnce.computeIfAbsent(level) { ArrayList() }.add(ticker)
} }
fun tickOnceServer(level: Level, ticker: Runnable) { private fun clear() {
if (level is ServerLevel) preServerTick.clear()
tick_once.computeIfAbsent(level) { ArrayList() }.add(ticker) postServerTick.clear()
preWorldTick.clear()
postWorldTick.clear()
preServerTickOnce.clear()
postServerTickOnce.clear()
preWorldTickOnce.clear()
postWorldTickOnce.clear()
} }
fun tickOnceClient(level: Level, ticker: Runnable) { @SubscribeEvent(priority = EventPriority.HIGHEST)
if (level is ClientLevel) fun onServerStarting(event: ServerAboutToStartEvent?) {
tick_once.computeIfAbsent(level) { ArrayList() }.add(ticker) clear()
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
fun onServerStopping(event: ServerStoppingEvent?) {
clear()
} }

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block 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.level.block.state.StateDefinition
import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape 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.ChemicalGeneratorBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes import ru.dbotthepony.mc.otm.shapes.BlockShapes
import ru.dbotthepony.mc.otm.tickOnceServer
class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock { class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock {
override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity { override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity {
@ -55,7 +54,7 @@ class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock {
val tile = level.getBlockEntity(pos) val tile = level.getBlockEntity(pos)
if (tile is ChemicalGeneratorBlockEntity) { if (tile is ChemicalGeneratorBlockEntity) {
tickOnceServer(level) { addPreWorldTickerOnce(level) {
tile.checkSurroundings() tile.checkSurroundings()
} }
} }

View File

@ -22,6 +22,7 @@ import net.minecraft.world.level.material.MaterialColor
import net.minecraft.world.level.material.PushReaction import net.minecraft.world.level.material.PushReaction
import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape 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.GravitationStabilizerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.block.entity.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.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.shapes.BlockShapes import ru.dbotthepony.mc.otm.shapes.BlockShapes
import ru.dbotthepony.mc.otm.tickOnceServer
import kotlin.math.PI import kotlin.math.PI
private val props = BlockBehaviour.Properties.of(Material.STONE, MaterialColor.COLOR_BLUE).requiresCorrectToolForDrops().strength(3f, 600.0f) 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) super.neighborChanged(state, level, pos, sender, sender_pos, flag)
tickOnceServer(level) { addPreWorldTickerOnce(level) {
if (level.getBlockState(pos).block !is BlockGravitationStabilizer) return@tickOnceServer if (level.getBlockState(pos).block !is BlockGravitationStabilizer) return@addPreWorldTickerOnce
val bb = getBoundingBlock(level, state, pos) val bb = getBoundingBlock(level, state, pos)
if (bb.block !is BlockGravitationStabilizerLens) { if (bb.block !is BlockGravitationStabilizerLens) {
@ -181,8 +181,8 @@ class BlockGravitationStabilizerLens : RotatableMatteryBlock(props) {
) { ) {
super.neighborChanged(state, level, pos, sender, sender_pos, flag) super.neighborChanged(state, level, pos, sender, sender_pos, flag)
tickOnceServer(level) { addPreWorldTickerOnce(level) {
if (level.getBlockState(pos).block !is BlockGravitationStabilizerLens) return@tickOnceServer if (level.getBlockState(pos).block !is BlockGravitationStabilizerLens) return@addPreWorldTickerOnce
val bb = getBoundingBlock(level, state, pos) val bb = getBoundingBlock(level, state, pos)
if (bb.block !is BlockGravitationStabilizer) { if (bb.block !is BlockGravitationStabilizer) {

View File

@ -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.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState 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.block.entity.StorageBusBlockEntity
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.tickOnceServer
import ru.dbotthepony.mc.otm.unaryMinus import ru.dbotthepony.mc.otm.unaryMinus
class StorageBusBlock : RotatableMatteryBlock(), EntityBlock { class StorageBusBlock : RotatableMatteryBlock(), EntityBlock {
@ -51,7 +50,7 @@ class StorageBusBlock : RotatableMatteryBlock(), EntityBlock {
val tile = level.getBlockEntity(pos) val tile = level.getBlockEntity(pos)
if (tile is StorageBusBlockEntity) { if (tile is StorageBusBlockEntity) {
tickOnceServer(level) { addPreWorldTickerOnce(level) {
tile.checkSurroundings() tile.checkSurroundings()
} }
} }

View File

@ -81,7 +81,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override val defaultDisplayName: Component override val defaultDisplayName: Component
get() = MACHINE_NAME 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) return DriveRackMenu(containerID, inventory, this)
} }
@ -101,6 +101,11 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
cell.revive() cell.revive()
} }
override fun setRemoved() {
super.setRemoved()
cell.destroy(level)
}
companion object { companion object {
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.drive_rack") private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.drive_rack")
private val STORAGE = ImpreciseFraction(80_000) private val STORAGE = ImpreciseFraction(80_000)

View File

@ -59,6 +59,11 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
cell.revive() cell.revive()
} }
override fun setRemoved() {
super.setRemoved()
cell.destroy(level)
}
companion object { companion object {
private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.item_monitor") private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.item_monitor")
} }

View File

@ -22,6 +22,7 @@ import net.minecraft.nbt.ByteTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.addPreWorldTickerOnce
import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set import ru.dbotthepony.mc.otm.set
@ -70,32 +71,32 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
protected fun tickOnce(func: Runnable) { protected fun tickOnce(func: Runnable) {
val level = level 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) { protected fun tickOnceServer(func: Runnable) {
val level = level 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) { protected fun tickOnceClient(func: Runnable) {
val level = level 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) { protected fun tickOnce(func: (Level) -> Unit) {
val level = level 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) { protected fun tickOnceServer(func: (ServerLevel) -> Unit) {
val level = level 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) { protected fun tickOnceClient(func: (ClientLevel) -> Unit) {
val level = level 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 <T> getAndBind( protected fun <T> getAndBind(

View File

@ -333,6 +333,11 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
component?.scan() component?.scan()
} }
override fun setRemoved() {
super.setRemoved()
cell.destroy(level)
}
fun checkSurroundings() { fun checkSurroundings() {
val front = blockPos + blockState.getValue(RotatableMatteryBlock.FACING_FULL) 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 } val storage = level?.getBlockEntity(front)?.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)?.let { if (it.isPresent) it else null }

View File

@ -1,27 +1,51 @@
package ru.dbotthepony.mc.otm.graph package ru.dbotthepony.mc.otm.graph
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.SectionPos import net.minecraft.core.SectionPos
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.block.entity.BlockEntity 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.core.plus
import ru.dbotthepony.mc.otm.tickUntil
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
abstract class Abstract6Graph<T> { abstract class Abstract6Graph<T> : IConditionalTickable {
@JvmField @JvmField
protected val _nodes = ArrayList<Graph6Node<T>>() protected val _nodes = ArrayList<Graph6Node<T>>()
fun size() = _nodes.size fun size() = _nodes.size
private val tickable = ArrayList<Graph6Node<T>>()
@JvmField @JvmField
val nodes = Collections.unmodifiableCollection(_nodes) val nodes: Collection<Graph6Node<T>> = Collections.unmodifiableCollection(_nodes)
/**
* Allows storing arbitrary data by external code
*/
@JvmField
val userData = Object2ObjectAVLTreeMap<UUID, Any>()
abstract fun onNodeRemoved(node: Graph6Node<T>) abstract fun onNodeRemoved(node: Graph6Node<T>)
abstract fun onNodeAdded(node: Graph6Node<T>) abstract fun onNodeAdded(node: Graph6Node<T>)
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<T>) { fun removeNode(node: Graph6Node<T>) {
if (!_nodes.contains(node)) if (!_nodes.contains(node))
throw IllegalStateException("Not containing node $node") throw IllegalStateException("Not containing node $node")
@ -29,6 +53,10 @@ abstract class Abstract6Graph<T> {
_nodes.remove(node) _nodes.remove(node)
node.graph = null node.graph = null
onNodeRemoved(node) onNodeRemoved(node)
if (node.canTick) {
tickable.remove(node)
}
} }
fun addNode(node: Graph6Node<T>) { fun addNode(node: Graph6Node<T>) {
@ -38,6 +66,10 @@ abstract class Abstract6Graph<T> {
_nodes.add(node) _nodes.add(node)
node.graph = this node.graph = this
onNodeAdded(node) onNodeAdded(node)
if (node.canTick) {
tickable.add(node)
}
} }
fun merge(other: Abstract6Graph<T>): Abstract6Graph<T> { fun merge(other: Abstract6Graph<T>): Abstract6Graph<T> {
@ -65,9 +97,16 @@ abstract class Abstract6Graph<T> {
nodeGetter: (BlockEntity) -> Graph6Node<T>?, nodeGetter: (BlockEntity) -> Graph6Node<T>?,
factory: () -> Abstract6Graph<T> factory: () -> Abstract6Graph<T>
) { ) {
tickUntil(level) { addPreWorldTicker(level, object : IConditionalTickable {
!node.valid || discover(level, blockPos, node, nodeGetter, factory) override fun tick() {
} discovered = discover(level, blockPos, node, nodeGetter, factory)
}
private var discovered = false
override val canTick: Boolean
get() = !discovered && node.valid
})
} }
@JvmStatic @JvmStatic

View File

@ -1,6 +1,8 @@
package ru.dbotthepony.mc.otm.graph package ru.dbotthepony.mc.otm.graph
import net.minecraft.core.Direction import net.minecraft.core.Direction
import ru.dbotthepony.mc.otm.IConditionalTickable
import ru.dbotthepony.mc.otm.ITickable
interface GraphNodeListener { interface GraphNodeListener {
fun onNeighbourTop(node: Graph6Node<*>) = onNeighbour(node, Direction.UP) fun onNeighbourTop(node: Graph6Node<*>) = onNeighbour(node, Direction.UP)
@ -23,7 +25,7 @@ interface GraphNodeListener {
} }
// Вершина графа, содержит то, к какому графу принадлежит, соседей и своё "значение" // Вершина графа, содержит то, к какому графу принадлежит, соседей и своё "значение"
class Graph6Node<T>(@JvmField val value: T, graph: Abstract6Graph<T>? = null) { class Graph6Node<T>(@JvmField val value: T, graph: Abstract6Graph<T>? = null) : IConditionalTickable {
var graph: Abstract6Graph<T>? = null var graph: Abstract6Graph<T>? = null
init { init {
@ -182,6 +184,23 @@ class Graph6Node<T>(@JvmField val value: T, graph: Abstract6Graph<T>? = 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 var seen: Int = 0
private fun _flood(): List<GraphFlooder<T>> { private fun _flood(): List<GraphFlooder<T>> {

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.graph.storage package ru.dbotthepony.mc.otm.graph.storage
import net.minecraft.world.level.Level
import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.storage.IStorage import ru.dbotthepony.mc.otm.storage.IStorage
@ -117,4 +118,12 @@ open class BasicStorageGraphNode : IStorageGraphNode {
fun get(): LazyOptional<IStorageGraphNode> { fun get(): LazyOptional<IStorageGraphNode> {
return if (valid) resolver else LazyOptional.empty() return if (valid) resolver else LazyOptional.empty()
} }
fun destroy(level: Level?) {
if (level != null) {
storageNode.destroy { StorageNetworkGraph(level) }
} else {
storageGraph?.removeNode(storageNode)
}
}
} }

View File

@ -3,20 +3,19 @@ package ru.dbotthepony.mc.otm.graph.storage
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity 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.capability.MatteryCapability
import ru.dbotthepony.mc.otm.graph.Abstract6Graph import ru.dbotthepony.mc.otm.graph.Abstract6Graph
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.orNull import ru.dbotthepony.mc.otm.orNull
import ru.dbotthepony.mc.otm.storage.* import ru.dbotthepony.mc.otm.storage.*
class StorageNetworkGraph : Abstract6Graph<IStorageGraphNode>() { class StorageNetworkGraph(private val level: Level) : Abstract6Graph<IStorageGraphNode>() {
private val virtualComponents = Object2ObjectArrayMap<StorageStackType<*>, VirtualComponent<*>>() private val virtualComponents = Object2ObjectArrayMap<StorageStackType<*>, VirtualComponent<*>>()
fun <T : IStorageStack> insertStack(obj: T, simulate: Boolean): T {
return (getVirtualComponent(StorageRegistry.get(obj::class.java)) as VirtualComponent<T>).insertStack(obj, simulate)
}
/** /**
* Returns a [VirtualComponent] representing [type] storage * Returns a [VirtualComponent] representing [type] storage
*/ */
@ -31,6 +30,8 @@ class StorageNetworkGraph : Abstract6Graph<IStorageGraphNode>() {
return virtualComponents.computeIfAbsent(StorageRegistry.get(type), Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent<T> return virtualComponents.computeIfAbsent(StorageRegistry.get(type), Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent<T>
} }
private var addedTicker = false
fun <T : IStorageStack> add(storage: IStorage<T>) { fun <T : IStorageStack> add(storage: IStorage<T>) {
getVirtualComponent(storage.storageType).add(storage) getVirtualComponent(storage.storageType).add(storage)
} }
@ -43,6 +44,11 @@ class StorageNetworkGraph : Abstract6Graph<IStorageGraphNode>() {
for (identity in node.value.fetchComponents()) { for (identity in node.value.fetchComponents()) {
add(identity) add(identity)
} }
if (!addedTicker) {
addedTicker = true
addPreWorldTicker(level, this)
}
} }
override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) { override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) {
@ -63,9 +69,8 @@ class StorageNetworkGraph : Abstract6Graph<IStorageGraphNode>() {
node, node,
fun(_tile): Graph6Node<IStorageGraphNode>? { fun(_tile): Graph6Node<IStorageGraphNode>? {
return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode
}, }
::StorageNetworkGraph ) { StorageNetworkGraph(tile.level!!) }
)
} }
@JvmStatic @JvmStatic
@ -80,8 +85,7 @@ class StorageNetworkGraph : Abstract6Graph<IStorageGraphNode>() {
fun(_tile): Graph6Node<IStorageGraphNode>? { fun(_tile): Graph6Node<IStorageGraphNode>? {
return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode
}, },
::StorageNetworkGraph ) { StorageNetworkGraph(tile.level!!) }
)
} }
} }
} }