New graph implementation
This commit is contained in:
parent
ebc41b808a
commit
5f16804feb
@ -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<IMatterGraphNode> MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
public static final Capability<MatterNode> MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
@ -49,7 +49,7 @@ public class MatteryCapability {
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
public static final Capability<IStorageGraphNode> STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
public static final Capability<StorageNode> 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);
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
private var valid = true
|
||||
override val matterNode = Graph6Node<IMatterGraphNode>(this)
|
||||
private val resolverNode = LazyOptional.of { this }
|
||||
|
||||
override fun invalidateCaps() {
|
||||
super.invalidateCaps()
|
||||
valid = false
|
||||
}
|
||||
|
||||
override fun reviveCaps() {
|
||||
super.reviveCaps()
|
||||
valid = true
|
||||
}
|
||||
|
||||
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
if (valid) {
|
||||
if (cap === MatteryCapability.MATTER_NODE)
|
||||
return resolverNode.cast()
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
override fun onNeighbour(node: Graph6Node<*>, direction: Direction) {
|
||||
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)
|
||||
|
||||
if (newState !== 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 = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false)
|
||||
|
||||
if (newState !== blockState && SERVER_IS_LIVE)
|
||||
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
|
||||
}
|
||||
|
||||
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 attachComponents(to: StorageNetworkGraph) {}
|
||||
override fun removeComponents(from: StorageNetworkGraph) {}
|
||||
override val storageNode = Graph6Node<IStorageGraphNode>(this)
|
||||
|
||||
override fun invalidateCaps() {
|
||||
super.invalidateCaps()
|
||||
valid = false
|
||||
}
|
||||
|
||||
override fun reviveCaps() {
|
||||
super.reviveCaps()
|
||||
valid = true
|
||||
}
|
||||
|
||||
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
if (valid) {
|
||||
if (cap === MatteryCapability.STORAGE_NODE)
|
||||
return resolverNode.cast()
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
StorageNetworkGraph.discoverFull(this, storageNode)
|
||||
}
|
||||
|
||||
override fun onNeighbour(node: Graph6Node<*>, direction: Direction) {
|
||||
override fun onNeighbour(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) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
exposeGlobally(MatteryCapability.STORAGE_NODE, storageNode)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<IMatterGraphNode>(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)
|
||||
|
@ -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<IMatterGraphNode>(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) {
|
||||
|
@ -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<IMatterGraphNode>(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)
|
||||
}
|
||||
}
|
||||
|
@ -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<MatterDecomposerBlockEntity.DecomposerJob>(MBlockEntities.MATTER_DECOMPOSER, pos, state, ::DecomposerJob), IMatterGraphNode {
|
||||
: MatteryWorkerBlockEntity<MatterDecomposerBlockEntity.DecomposerJob>(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<IMatterGraphNode>(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)
|
||||
|
@ -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<CompoundTag> {
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
@ -55,7 +56,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
}
|
||||
|
||||
private val listeners = ArrayList<MatterPanelMenu>()
|
||||
override val matterNode = Graph6Node<IMatterGraphNode>(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<UUID, ReplicationTask>()
|
||||
@ -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)
|
||||
|
@ -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<MatterRecyclerBlockEntity.RecyclerJob>(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, ::RecyclerJob), IMatterGraphNode {
|
||||
: MatteryWorkerBlockEntity<MatterRecyclerBlockEntity.RecyclerJob>(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<IMatterGraphNode>(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) {
|
||||
|
@ -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<MatterReplicatorBlockEntity.ReplicatorJob>(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,44 +100,13 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
}
|
||||
|
||||
val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES)
|
||||
override val matterNode = Graph6Node<IMatterGraphNode>(this)
|
||||
val matter = MatterStorageImpl(this::matterLevelUpdated, FlowDirection.INPUT, ::MATTER_CAPACITY)
|
||||
val container = MatteryContainer(this::itemContainerUpdated, 5).also(::addDroppableContainer)
|
||||
val itemHandler = container.handler(HandlerFilter.OnlyOut)
|
||||
|
||||
init {
|
||||
exposeEnergyGlobally(energy)
|
||||
exposeItemsGlobally(itemHandler)
|
||||
exposeGlobally(MatteryCapability.MATTER, matter)
|
||||
exposeGlobally(MatteryCapability.MATTER_NODE, this)
|
||||
|
||||
savetable(::energy, ENERGY_KEY)
|
||||
savetable(::matter, MATTER_STORAGE_KEY)
|
||||
savetable(::container, INVENTORY_KEY)
|
||||
}
|
||||
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
return MatterReplicatorMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: ReplicatorJob): Status {
|
||||
if (job.asDust) {
|
||||
job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING)
|
||||
|
||||
if (!job.matterValue.isZero) {
|
||||
return Status.FAILURE_WAIT
|
||||
}
|
||||
|
||||
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
|
||||
return Status.SUCCESS
|
||||
}
|
||||
|
||||
if (!container.fullyAddItem(job.itemStack, FIRST_ACTUAL_OUTPUT_SLOT .. LAST_ACTUAL_OUTPUT_SLOT)) {
|
||||
return Status.FAILURE_ITEM
|
||||
}
|
||||
|
||||
(matterNode.graph as MatterNetworkGraph?)?.notifyTaskCompletion(job.task.id)
|
||||
return Status.SUCCESS
|
||||
val matterNode = object : MatterNode() {
|
||||
override fun getMatterHandler(): IMatterStorage {
|
||||
return matter
|
||||
}
|
||||
|
||||
override fun onMatterTaskCreated(task: IReplicationTask<*>) {
|
||||
@ -155,17 +126,51 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
isIdling = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
exposeEnergyGlobally(energy)
|
||||
exposeItemsGlobally(itemHandler)
|
||||
exposeGlobally(MatteryCapability.MATTER, matter)
|
||||
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
|
||||
|
||||
savetable(::energy, ENERGY_KEY)
|
||||
savetable(::matter, MATTER_STORAGE_KEY)
|
||||
savetable(::container, INVENTORY_KEY)
|
||||
}
|
||||
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
return MatterReplicatorMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun onJobFinish(job: ReplicatorJob): Status {
|
||||
if (job.asDust) {
|
||||
job.matterValue = moveMatterAsDustIntoContainer(job.matterValue, container, OUTPUT_DUST_MAIN, OUTPUT_DUST_STACKING)
|
||||
|
||||
if (!job.matterValue.isZero) {
|
||||
return Status.FAILURE_WAIT
|
||||
}
|
||||
|
||||
matterNode.graph.notifyTaskCompletion(job.task.id)
|
||||
return Status.SUCCESS
|
||||
}
|
||||
|
||||
if (!container.fullyAddItem(job.itemStack, FIRST_ACTUAL_OUTPUT_SLOT .. LAST_ACTUAL_OUTPUT_SLOT)) {
|
||||
return Status.FAILURE_ITEM
|
||||
}
|
||||
|
||||
matterNode.graph.notifyTaskCompletion(job.task.id)
|
||||
return Status.SUCCESS
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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<MatteryWorkerBlockEntity.ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::ItemJob), IMatterGraphNode {
|
||||
MatteryWorkerBlockEntity<MatteryWorkerBlockEntity.ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::ItemJob) {
|
||||
|
||||
val container = MatteryContainer(this::itemContainerUpdated, 1).also(::addDroppableContainer)
|
||||
val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES)
|
||||
@ -47,16 +47,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
}
|
||||
})
|
||||
|
||||
init {
|
||||
exposeItemsGlobally(itemHandler)
|
||||
exposeEnergyGlobally(energy)
|
||||
exposeGlobally(MatteryCapability.MATTER_NODE, this)
|
||||
|
||||
savetable(::container, INVENTORY_KEY)
|
||||
savetable(::energy, ENERGY_KEY)
|
||||
}
|
||||
|
||||
// IMatterGraphNode
|
||||
val matterNode = object : MatterNode() {
|
||||
override fun onPatternAdded(state: IPatternState) {
|
||||
if (idleReason == IdleReason.OBSERVING) {
|
||||
isIdling = false
|
||||
@ -74,18 +65,25 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
isIdling = false
|
||||
}
|
||||
}
|
||||
// /IMatterGraphNode
|
||||
}
|
||||
|
||||
override val matterNode: Graph6Node<IMatterGraphNode> = Graph6Node(this)
|
||||
init {
|
||||
exposeItemsGlobally(itemHandler)
|
||||
exposeEnergyGlobally(energy)
|
||||
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
|
||||
|
||||
savetable(::container, INVENTORY_KEY)
|
||||
savetable(::energy, ENERGY_KEY)
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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<IMatterGraphNode>(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!!)
|
||||
matterNode.graph.onPatternAdded(status.newState!!)
|
||||
} else {
|
||||
graph.onPatternUpdated(status.newState!!, status.oldState!!)
|
||||
}
|
||||
matterNode.graph.onPatternUpdated(status.newState!!, status.oldState!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<ItemStackWrapper>? = 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
|
||||
}
|
||||
}
|
||||
|
@ -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<ItemStackWrapper> {
|
||||
@ -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() {
|
||||
|
@ -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<T>(
|
||||
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<T>(
|
||||
}
|
||||
}
|
||||
|
||||
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<T>(
|
||||
|
||||
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<T>
|
||||
@ -117,7 +109,6 @@ abstract class AbstractStorageImportExport<T>(
|
||||
}
|
||||
|
||||
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<Pair<UUID, ItemStackWrapper>>
|
||||
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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 <T : Any> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
if (cap === MatteryCapability.STORAGE_NODE)
|
||||
return cell.get().cast()
|
||||
return holder.get()
|
||||
|
||||
return LazyOptional.empty()
|
||||
}
|
||||
@ -286,8 +296,8 @@ fun attachCapabilities(event: AttachCapabilitiesEvent<BlockEntity>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LOHolder.kt
Normal file
20
src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LOHolder.kt
Normal file
@ -0,0 +1,20 @@
|
||||
package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
|
||||
class LOHolder<T : Any>(val value: T) {
|
||||
private var lazyOptional: LazyOptional<T> = LazyOptional.of { value }
|
||||
|
||||
fun invalidate() {
|
||||
lazyOptional.invalidate()
|
||||
}
|
||||
|
||||
fun revive() {
|
||||
lazyOptional.invalidate()
|
||||
lazyOptional = LazyOptional.of { value }
|
||||
}
|
||||
|
||||
fun <T> get(): LazyOptional<T> {
|
||||
return lazyOptional.cast()
|
||||
}
|
||||
}
|
@ -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<T> : IConditionalTickable {
|
||||
protected val nodes = ArrayList<Graph6Node<T>>()
|
||||
fun size() = nodes.size
|
||||
private val tickable = ArrayList<Graph6Node<T>>()
|
||||
val nodeList: Collection<Graph6Node<T>> = Collections.unmodifiableCollection(nodes)
|
||||
open class Abstract6Graph<N : Graph6Node<N, G>, G : Abstract6Graph<N, G>> : IConditionalTickable {
|
||||
private val nodesInternal = ArrayList<N>()
|
||||
private val conditional = ArrayList<IConditionalTickable>()
|
||||
private val always = ArrayList<ITickable>()
|
||||
|
||||
protected val nodes: List<N> = 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<UUID, Any>()
|
||||
|
||||
abstract fun onNodeRemoved(node: Graph6Node<T>)
|
||||
abstract fun onNodeAdded(node: Graph6Node<T>)
|
||||
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()
|
||||
}
|
||||
|
||||
fun removeNode(node: Graph6Node<T>) {
|
||||
if (!nodes.remove(node))
|
||||
throw IllegalStateException("Not containing node $node")
|
||||
|
||||
node.graph = null
|
||||
onNodeRemoved(node)
|
||||
tickable.remove(node)
|
||||
return innerTick() || always.isNotEmpty() || conditional.isNotEmpty()
|
||||
}
|
||||
|
||||
fun addNode(node: Graph6Node<T>) {
|
||||
if (nodes.contains(node))
|
||||
throw IllegalStateException("Already containing node $node")
|
||||
fun addNode(node: N): Boolean {
|
||||
if (node in nodesInternal)
|
||||
return false
|
||||
|
||||
nodesInternal.add(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<T>): Abstract6Graph<T> {
|
||||
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<N>) {
|
||||
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 <T> discoverFull(
|
||||
level: ServerLevel,
|
||||
blockPos: BlockPos,
|
||||
node: Graph6Node<T>,
|
||||
nodeGetter: (BlockEntity) -> Graph6Node<T>?,
|
||||
factory: () -> Abstract6Graph<T>
|
||||
) {
|
||||
level.addTicker {
|
||||
!discover(level, blockPos, node, nodeGetter, factory) && node.valid
|
||||
}
|
||||
private val graphs = ArrayList<WeakReference<Abstract6Graph<*, *>>>()
|
||||
private val next = ArrayList<WeakReference<Abstract6Graph<*, *>>>()
|
||||
|
||||
fun tick() {
|
||||
if (next.isNotEmpty()) {
|
||||
graphs.addAll(next)
|
||||
next.clear()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <T> discover(
|
||||
level: ServerLevel,
|
||||
blockPos: BlockPos,
|
||||
node: Graph6Node<T>,
|
||||
nodeGetter: (BlockEntity) -> Graph6Node<T>?,
|
||||
factory: () -> Abstract6Graph<T>
|
||||
): Boolean {
|
||||
var fullDiscovery = true
|
||||
val iterator = graphs.iterator()
|
||||
|
||||
node.nullifyConnections()
|
||||
for (value in iterator) {
|
||||
val graph = value.get()
|
||||
|
||||
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 || !graph.tick()) {
|
||||
graph?.isTicking = false
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// мы нашли граф рядом
|
||||
if (_graph != null) {
|
||||
node.graph = _graph
|
||||
_graph.addNode(node)
|
||||
} else {
|
||||
// графов рядом нет, создаем свой
|
||||
_graph = factory()
|
||||
node.graph = _graph
|
||||
_graph.addNode(node)
|
||||
}
|
||||
}
|
||||
|
||||
// теперь снова смотрим на соседей, если у них нет графа - присоединяем к своему
|
||||
// если у них есть граф - слияем его со своим или свой с его
|
||||
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 != 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fullDiscovery
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<N : Graph6Node<N, G>, G : Abstract6Graph<N, G>>(val graphFactory: () -> G) {
|
||||
private val neighbours = EnumMap<Direction, N>(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<T>(@JvmField val value: T, graph: Abstract6Graph<T>? = null) : IConditionalTickable {
|
||||
var graph: Abstract6Graph<T>? = null
|
||||
|
||||
init {
|
||||
this.graph = graph
|
||||
}
|
||||
|
||||
var top: Graph6Node<T>? = 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<T>? = 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<T>? = 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<T>? = 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<T>? = 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<T>? = 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<T>, 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<GraphFlooder<T>> {
|
||||
val list = ArrayList<GraphFlooder<T>>()
|
||||
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<GraphFlooder<T>> {
|
||||
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<T>): List<GraphFlooder<T>> {
|
||||
if (!valid || !SERVER_IS_LIVE) return emptyList()
|
||||
|
||||
top?.bottom = null
|
||||
bottom?.top = null
|
||||
left?.right = null
|
||||
right?.left = null
|
||||
front?.back = null
|
||||
back?.front = null
|
||||
|
||||
graph?.removeNode(this)
|
||||
|
||||
var num = 0
|
||||
|
||||
if (top != null) num++
|
||||
if (bottom != null) num++
|
||||
if (left != null) num++
|
||||
if (right != null) num++
|
||||
if (front != null) num++
|
||||
if (back != null) num++
|
||||
|
||||
if (num < 2) {
|
||||
return emptyList()
|
||||
init {
|
||||
graph.addNode(this as N)
|
||||
}
|
||||
|
||||
val paths = _flood()
|
||||
private var seen: Int = 0
|
||||
|
||||
if (paths.size < 2) {
|
||||
return paths
|
||||
operator fun get(direction: Direction): N? = neighbours[direction]
|
||||
|
||||
operator fun set(direction: Direction, node: N?) {
|
||||
set(direction, node, false)
|
||||
}
|
||||
|
||||
var biggest = paths[0]
|
||||
fun set(direction: Direction, node: N?, allowReplacement: Boolean) {
|
||||
check(isValid) { "Can not neighbour any node while this node is invalid" }
|
||||
|
||||
for (i in 1 until paths.size) {
|
||||
if (biggest.size() < paths[i].size()) {
|
||||
biggest = paths[i]
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
for (flooder in paths) {
|
||||
if (flooder == biggest) continue
|
||||
var top: N?
|
||||
get() = neighbours[Direction.UP]
|
||||
set(value) {
|
||||
set(Direction.UP, value)
|
||||
}
|
||||
|
||||
val graph = factory()
|
||||
var bottom: N?
|
||||
get() = neighbours[Direction.DOWN]
|
||||
set(value) {
|
||||
set(Direction.DOWN, value)
|
||||
}
|
||||
|
||||
for (node in flooder.nodes) {
|
||||
node.graph?.removeNode(node)
|
||||
graph.addNode(node)
|
||||
var south: N?
|
||||
get() = neighbours[Direction.SOUTH]
|
||||
set(value) {
|
||||
set(Direction.SOUTH, value)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
fun discover(
|
||||
level: ServerLevel,
|
||||
blockPos: BlockPos,
|
||||
nodeGetter: (BlockEntity) -> N?
|
||||
) {
|
||||
if (!isValid) return
|
||||
|
||||
level.addTicker {
|
||||
isValid && !discoverStep(level, blockPos, nodeGetter)
|
||||
}
|
||||
}
|
||||
|
||||
fun discover(
|
||||
level: ServerLevel,
|
||||
blockPos: BlockPos,
|
||||
capability: Capability<out N>
|
||||
) {
|
||||
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<out N>) {
|
||||
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 fullDiscovery
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val setter = Graph6Node<*, *>::graph::set
|
||||
private val nextSeen = AtomicInteger()
|
||||
private val directions = Direction.values()
|
||||
|
||||
private fun <N : Graph6Node<N, G>, G : Abstract6Graph<N, G>> 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<N>
|
||||
val small: ArrayList<N>
|
||||
|
||||
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 <N : Graph6Node<N, G>, G : Abstract6Graph<N, G>> flood(startingNode: N, seen: Int): ArrayList<N> {
|
||||
val unopen = ArrayList<N>()
|
||||
val result = ArrayList<N>()
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.graph
|
||||
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class GraphFlooder<T>(val startNode: Graph6Node<T>, @JvmField val seen: Int = nextSeen++) {
|
||||
var flooded = false
|
||||
private set
|
||||
|
||||
private val _nodes = ArrayList<Graph6Node<T>>()
|
||||
|
||||
@JvmField
|
||||
val nodes = Collections.unmodifiableCollection(_nodes)!!
|
||||
|
||||
fun size() = _nodes.size
|
||||
|
||||
private fun flood(node: Graph6Node<T>) {
|
||||
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 <T> floodIf(node: Graph6Node<T>?, seen: Int, runnable: (GraphFlooder<T>) -> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<IMatterGraphNode>
|
||||
val matterGraph: MatterNetworkGraph? get() = matterNode.graph as MatterNetworkGraph?
|
||||
}
|
@ -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<IMatterGraphNode>(), IMatterGraphListener {
|
||||
private val listeners = HashSet<IMatterGraphListener>()
|
||||
class MatterGraph : Abstract6Graph<MatterNode, MatterGraph>(), IMatterGraphListener {
|
||||
private val listeners = ObjectOpenHashSet<IMatterGraphListener>()
|
||||
|
||||
fun addListener(listener: IMatterGraphListener) = listeners.add(listener)
|
||||
fun removeListener(listener: IMatterGraphListener) = listeners.remove(listener)
|
||||
|
||||
override fun onNodeRemoved(node: Graph6Node<IMatterGraphNode>) {
|
||||
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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>) {
|
||||
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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), IMatterGraphListe
|
||||
return doInsertPattern(state, false, simulate)
|
||||
}
|
||||
|
||||
val tasks: Stream<out IReplicationTask<*>> get() {
|
||||
return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.replicationTasks }.toTypedArray())
|
||||
val tasks: Stream<IReplicationTask<*>> get() {
|
||||
return nodes.stream().map { it.getTaskHandler()?.replicationTasks }.filterNotNull().flatMap { it }
|
||||
}
|
||||
|
||||
val allTasks: Stream<out IReplicationTask<*>> get() {
|
||||
return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.allReplicationTasks }.toTypedArray())
|
||||
val allTasks: Stream<IReplicationTask<*>> get() {
|
||||
return nodes.stream().map { it.getTaskHandler()?.allReplicationTasks }.filterNotNull().flatMap { it }
|
||||
}
|
||||
|
||||
val patterns: Stream<out IPatternState> get() {
|
||||
return nodes.stream().map { it.value.getPatternHandler()?.patterns }.filterNotNull().flatMap { it }
|
||||
val patterns: Stream<IPatternState> 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), IMatterGraphListe
|
||||
|
||||
fun findPattern(predicate: Predicate<IPatternState>): 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<IMatterGraphNode>(), 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<IMatterGraphNode>(), 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 <T : IReplicationTask<*>> 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<IMatterGraphNode>) {
|
||||
if (tile.level !is ServerLevel)
|
||||
return
|
||||
|
||||
return discoverFull(
|
||||
tile.level!! as ServerLevel,
|
||||
tile.blockPos,
|
||||
node,
|
||||
fun(_tile): Graph6Node<IMatterGraphNode>? {
|
||||
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<IMatterGraphNode>): Boolean {
|
||||
if (tile.level !is ServerLevel)
|
||||
return false
|
||||
|
||||
return discover(
|
||||
tile.level!! as ServerLevel,
|
||||
tile.blockPos,
|
||||
node,
|
||||
fun(_tile): Graph6Node<IMatterGraphNode>? {
|
||||
val resolve = _tile.getCapability(MatteryCapability.MATTER_NODE)
|
||||
|
||||
return if (resolve.isPresent) {
|
||||
resolve.resolve().get().matterNode
|
||||
} else {
|
||||
null
|
||||
}
|
||||
},
|
||||
::MatterNetworkGraph
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<MatterNode, MatterGraph>(::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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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<IStorageGraphNode>
|
||||
val storageGraph: StorageNetworkGraph? get() = storageNode.graph as StorageNetworkGraph?
|
||||
}
|
@ -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<IStorageGraphNode>() {
|
||||
class StorageGraph : Abstract6Graph<StorageNode, StorageGraph>() {
|
||||
private val virtualComponents = Object2ObjectArrayMap<StorageStackType<*>, VirtualComponent<*>>()
|
||||
val powerDemandingNodes = LinkedList<IMatteryEnergyStorage>()
|
||||
|
||||
/**
|
||||
* Returns a [VirtualComponent] representing [type] storage
|
||||
@ -31,8 +32,6 @@ class StorageNetworkGraph(private val level: Level) : Abstract6Graph<IStorageGra
|
||||
return virtualComponents.computeIfAbsent(StorageRegistry.get(type), Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent<T>
|
||||
}
|
||||
|
||||
private var addedTicker = false
|
||||
|
||||
fun <T : IStorageStack> add(storage: IStorage<T>) {
|
||||
getVirtualComponent(storage.storageType).add(storage)
|
||||
}
|
||||
@ -46,50 +45,12 @@ class StorageNetworkGraph(private val level: Level) : Abstract6Graph<IStorageGra
|
||||
return (virtual as VirtualComponent<T>).contains(storage)
|
||||
}
|
||||
|
||||
override fun onNodeAdded(node: Graph6Node<IStorageGraphNode>) {
|
||||
node.value.attachComponents(this)
|
||||
|
||||
if (!addedTicker) {
|
||||
addedTicker = true
|
||||
level.addTickerPre(this)
|
||||
}
|
||||
override fun onNodeAdded(node: StorageNode) {
|
||||
node.attachComponents(this)
|
||||
}
|
||||
|
||||
override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) {
|
||||
node.value.removeComponents(this)
|
||||
override fun onNodeRemoved(node: StorageNode) {
|
||||
node.removeComponents(this)
|
||||
}
|
||||
|
||||
val powerDemandingNodes = LinkedList<IMatteryEnergyStorage>()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun discoverFull(tile: BlockEntity, node: Graph6Node<IStorageGraphNode>) {
|
||||
if (tile.level !is ServerLevel)
|
||||
return
|
||||
|
||||
return discoverFull(
|
||||
tile.level as ServerLevel,
|
||||
tile.blockPos,
|
||||
node,
|
||||
fun(_tile): Graph6Node<IStorageGraphNode>? {
|
||||
return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode
|
||||
}
|
||||
) { StorageNetworkGraph(tile.level!!) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun discover(tile: BlockEntity, node: Graph6Node<IStorageGraphNode>): Boolean {
|
||||
if (tile.level !is ServerLevel)
|
||||
return false
|
||||
|
||||
return discover(
|
||||
tile.level as ServerLevel,
|
||||
tile.blockPos,
|
||||
node,
|
||||
fun(_tile): Graph6Node<IStorageGraphNode>? {
|
||||
return _tile.getCapability(MatteryCapability.STORAGE_NODE).orNull()?.storageNode
|
||||
},
|
||||
) { StorageNetworkGraph(tile.level!!) }
|
||||
}
|
||||
}
|
||||
}
|
@ -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<IStorageGraphNode> { this }
|
||||
private var valid = true
|
||||
open class StorageNode(private val energyDemander: IMatteryEnergyStorage? = null) : Graph6Node<StorageNode, StorageGraph>(::StorageGraph) {
|
||||
protected val components = ArrayList<IStorage<*>>()
|
||||
|
||||
/**
|
||||
@ -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<IStorageGraphNode>(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 <T : IStorageStack, U : IStorage<T>> computeIfAbsent(identity: StorageStackType<T>, provider: (StorageStackType<T>) -> 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()
|
||||
|
||||
val storageGraph = storageGraph
|
||||
|
||||
if (storageGraph != null) {
|
||||
override fun invalidate() {
|
||||
for (component in components) {
|
||||
storageGraph.remove(component)
|
||||
}
|
||||
graph.remove(component)
|
||||
}
|
||||
}
|
||||
|
||||
open fun revive() {
|
||||
if (valid) return
|
||||
valid = true
|
||||
resolver = LazyOptional.of { this }
|
||||
|
||||
val storageGraph = storageGraph
|
||||
|
||||
if (storageGraph != null && !manualAttaching) {
|
||||
override fun revive() {
|
||||
if (!manualAttaching) {
|
||||
for (component in components) {
|
||||
storageGraph.add(component)
|
||||
graph.add(component)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun get(): LazyOptional<IStorageGraphNode> {
|
||||
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)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
val grid = tile.matterNode.graph
|
||||
initialSend = true
|
||||
sendNetwork(PatternsChangePacket(true, grid.patterns.toList()))
|
||||
}
|
||||
|
||||
sendNetwork(TasksChangePacket(true, tile.allReplicationTasks.toList()))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user