Improve ticker, actually remove nodes from storage graph
This commit is contained in:
parent
d4aa8cd7ee
commit
7152108cc8
@ -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 once = tick_once.remove(event.world)
|
val it2 = preWorldTickOnce.remove(event.world)
|
||||||
|
|
||||||
if (once != null)
|
if (it2 != null) {
|
||||||
for (ticker in once)
|
for (i in it2.size - 1 downTo 0) {
|
||||||
ticker.run()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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 }
|
||||||
|
@ -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
|
||||||
|
@ -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>> {
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -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!!) }
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user