New graph implementation

This commit is contained in:
DBotThePony 2023-03-24 20:25:35 +07:00
parent ebc41b808a
commit 5f16804feb
Signed by: DBot
GPG Key ID: DCC23B5715498507
36 changed files with 808 additions and 1146 deletions

View File

@ -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.IMatterStorage;
import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider; import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage; import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode; import ru.dbotthepony.mc.otm.graph.matter.MatterNode;
import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode; import ru.dbotthepony.mc.otm.graph.storage.StorageNode;
import top.theillusivec4.curios.api.type.capability.ICurio; import top.theillusivec4.curios.api.type.capability.ICurio;
import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler;
@ -33,7 +33,7 @@ public class MatteryCapability {
@Nonnull @Nonnull
@NotNull @NotNull
public static final Capability<IMatterGraphNode> MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<MatterNode> MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {});
@Nonnull @Nonnull
@NotNull @NotNull
@ -49,7 +49,7 @@ public class MatteryCapability {
@Nonnull @Nonnull
@NotNull @NotNull
public static final Capability<IStorageGraphNode> STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<StorageNode> STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {});
@Nonnull @Nonnull
@NotNull @NotNull
@ -67,10 +67,10 @@ public class MatteryCapability {
event.register(IMatteryEnergyStorage.class); event.register(IMatteryEnergyStorage.class);
event.register(MatteryPlayerCapability.class); event.register(MatteryPlayerCapability.class);
event.register(IMatterStorage.class); event.register(IMatterStorage.class);
event.register(IMatterGraphNode.class); event.register(MatterNode.class);
event.register(IPatternStorage.class); event.register(IPatternStorage.class);
event.register(IReplicationTaskProvider.class); event.register(IReplicationTaskProvider.class);
event.register(IMatteryDrive.class); event.register(IMatteryDrive.class);
event.register(IStorageGraphNode.class); event.register(StorageNode.class);
} }
} }

View File

@ -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.IConditionalTickable
import ru.dbotthepony.mc.otm.core.util.ITickable import ru.dbotthepony.mc.otm.core.util.ITickable
import ru.dbotthepony.mc.otm.core.util.TickList import ru.dbotthepony.mc.otm.core.util.TickList
import ru.dbotthepony.mc.otm.graph.Abstract6Graph
import java.util.* import java.util.*
private val preServerTick = TickList() private val preServerTick = TickList()
@ -145,6 +146,8 @@ fun onServerTick(event: ServerTickEvent) {
preServerTick.tick() preServerTick.tick()
} else { } else {
postServerTick.tick() postServerTick.tick()
// чтоб не плодить кучу подписчиков, вызовем напрямую отсюда
Abstract6Graph.tick()
} }
} }

View File

@ -2,135 +2,81 @@ package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block 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.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.SERVER_IS_LIVE
import ru.dbotthepony.mc.otm.block.CableBlock import ru.dbotthepony.mc.otm.block.CableBlock
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.MatterNode
import ru.dbotthepony.mc.otm.graph.GraphNodeListener import ru.dbotthepony.mc.otm.graph.storage.StorageGraph
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.storage.StorageNode
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.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
class MatterCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : class MatterCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.MATTER_CABLE, p_155229_, p_155230_) {
BlockEntity(MBlockEntities.MATTER_CABLE, p_155229_, p_155230_), IMatterGraphNode, GraphNodeListener { val matterNode = object : MatterNode() {
override fun onNeighbour(direction: Direction) {
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) {
val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true)
if (newState !== blockState && SERVER_IS_LIVE) if (newState !== blockState && SERVER_IS_LIVE)
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) 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) val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false)
if (newState !== blockState && SERVER_IS_LIVE) if (newState !== blockState && SERVER_IS_LIVE)
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) 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() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
} }
class StorageCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : class StorageCableBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.STORAGE_CABLE, p_155229_, p_155230_) {
BlockEntity(MBlockEntities.STORAGE_CABLE, p_155229_, p_155230_), IStorageGraphNode, GraphNodeListener { val storageNode = object : StorageNode() {
override fun attachComponents(to: StorageGraph) {}
override fun removeComponents(from: StorageGraph) {}
private var valid = true override fun onNeighbour(direction: Direction) {
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) {
val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true)
if (newState !== blockState && SERVER_IS_LIVE) if (newState !== blockState && SERVER_IS_LIVE)
level!!.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) 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) val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false)
if (newState !== blockState && SERVER_IS_LIVE) if (newState !== blockState && SERVER_IS_LIVE)
level!!.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) 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() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
storageNode.isValid = false
val level = level!!
storageNode.destroy {
StorageNetworkGraph(level)
}
} }
} }

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.nbt.StringTag import net.minecraft.nbt.StringTag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu 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.math.defineDecimal
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.util.WriteOnce import ru.dbotthepony.mc.otm.core.util.WriteOnce
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.matter.IMatterValue import ru.dbotthepony.mc.otm.matter.IMatterValue
import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.matter.MatterManager
import ru.dbotthepony.mc.otm.menu.matter.ItemRepairerMenu import ru.dbotthepony.mc.otm.menu.matter.ItemRepairerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MNames 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) val repairContainer = MatteryContainer(::containerChanged, 1).also(::addDroppableContainer)
private var matterPerTick = Decimal.ZERO private var matterPerTick = Decimal.ZERO
@ -48,13 +47,13 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt
var canNotWork = false var canNotWork = false
override val matterNode = Graph6Node<IMatterGraphNode>(this)
val matter = MatterStorageImpl(::setChangedLight, FlowDirection.INPUT, ::CAPACITY) val matter = MatterStorageImpl(::setChangedLight, FlowDirection.INPUT, ::CAPACITY)
val matterNode = SimpleMatterNode(matter = matter)
val energy = WorkerEnergyStorage(::setChangedLight, ENERGY_VALUES) val energy = WorkerEnergyStorage(::setChangedLight, ENERGY_VALUES)
init { init {
exposeGlobally(MatteryCapability.MATTER, matter) exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, this) exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetables.stateful(::repairContainer) savetables.stateful(::repairContainer)
savetables.stateful(::matter) savetables.stateful(::matter)
@ -83,10 +82,10 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt
} }
} }
return (matterNode.graph as MatterNetworkGraph?) return matterNode.graph
?.patterns .patterns
?.filter { stack.item.isValidRepairItem(stack, ItemStack(it.item, 1)) } .filter { stack.item.isValidRepairItem(stack, ItemStack(it.item, 1)) }
?.findFirst()?.orElse(null).let { .findFirst().orElse(null).let {
if (it == null) { if (it == null) {
IMatterValue.ZERO IMatterValue.ZERO
} else { } else {
@ -105,20 +104,14 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt
return ItemRepairerMenu(containerID, inventory, this) return ItemRepairerMenu(containerID, inventory, this)
} }
override fun getMatterHandler(): IMatterStorage {
return matter
}
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
} }
private fun containerChanged() { 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) { if (found != null) {
@Suppress("name_shadowing") @Suppress("name_shadowing")
@ -187,7 +180,7 @@ class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matt
} }
if (matter.storedMatter < matterPerTick) { if (matter.storedMatter < matterPerTick) {
val graph = matterNode.graph as MatterNetworkGraph? val graph = matterNode.graph as MatterGraph?
if (graph != null) { if (graph != null) {
val toDrain = (matterPerTick * EXTRACT_TICKS.coerceAtMost(item.damageValue)).coerceAtLeast(Decimal.ZERO).coerceAtMost(matter.missingMatter) val toDrain = (matterPerTick * EXTRACT_TICKS.coerceAtMost(item.damageValue)).coerceAtLeast(Decimal.ZERO).coerceAtMost(matter.missingMatter)

View File

@ -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.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.core.* 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.Decimal
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
import ru.dbotthepony.mc.otm.core.math.defineDecimal 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) : 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) val energy = WorkerEnergyStorage(this, ENERGY_VALUES)
var isBottling: Boolean = true var isBottling: Boolean = true
@ -110,9 +109,11 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
} }
val matterNode = SimpleMatterNode(matter = matter)
init { init {
exposeGlobally(MatteryCapability.MATTER, matter) exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, this) exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
exposeItemsGlobally(itemHandler) exposeItemsGlobally(itemHandler)
savetables.bool(::isBottling) savetables.bool(::isBottling)
@ -126,15 +127,9 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
private var initialCapacity: Decimal? = null private var initialCapacity: Decimal? = null
private var lastWorkStack: ItemStack? = null private var lastWorkStack: ItemStack? = null
override fun getMatterHandler(): IMatterStorage {
return matter
}
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
} }
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { 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() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun tick() { override fun tick() {
@ -212,7 +207,7 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
initialCapacity = capability!!.storedMatter initialCapacity = capability!!.storedMatter
} }
val graph = matterNode.graph as MatterNetworkGraph? val graph = matterNode.graph as MatterGraph?
if (capability != null) { if (capability != null) {
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.WORKING) { if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.WORKING) {

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity.matter package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu 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.immutableList
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.ifPresentK import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities 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 var gaugeLevel by synchronizer.float().property
private set private set
override val matterNode = Graph6Node<IMatterGraphNode>(this) val matterNode = SimpleMatterNode(matter = this)
override val canSetMatterLevel: Boolean override val canSetMatterLevel: Boolean
get() = false get() = false
@ -137,7 +134,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
init { init {
savetable(::container, INVENTORY_KEY) savetable(::container, INVENTORY_KEY)
exposeGlobally(MatteryCapability.MATTER, this) exposeGlobally(MatteryCapability.MATTER, this)
exposeGlobally(MatteryCapability.MATTER_NODE, this) exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
} }
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { 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() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
}
override fun getMatterHandler(): IMatterStorage {
return this
} }
} }

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu 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.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.ForgeConfigSpec 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.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection 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.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage 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.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.container.HandlerFilter
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.container.MatteryContainer
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.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.core.math.defineDecimal
import ru.dbotthepony.mc.otm.core.math.getDecimal import ru.dbotthepony.mc.otm.core.math.getDecimal
import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.math.set
import ru.dbotthepony.mc.otm.core.nbt.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.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 { fun moveMatterAsDustIntoContainer(_matterValue: Decimal, container: MatteryContainer, OUTPUT_DUST_MAIN: Int, OUTPUT_DUST_STACKING: Int): Decimal {
var matterValue = _matterValue var matterValue = _matterValue
@ -91,7 +88,7 @@ fun moveMatterAsDustIntoContainer(_matterValue: Decimal, container: MatteryConta
} }
class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) 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 { class DecomposerJob : Job {
val toDust: Boolean val toDust: Boolean
@ -127,13 +124,12 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
savetable(::energy, ENERGY_KEY) savetable(::energy, ENERGY_KEY)
} }
override val matterNode = Graph6Node<IMatterGraphNode>(this)
val matter = MatterStorageImpl(::setChangedLight, FlowDirection.OUTPUT, ::CAPACITY) val matter = MatterStorageImpl(::setChangedLight, FlowDirection.OUTPUT, ::CAPACITY)
val matterNode = SimpleMatterNode(matter = matter)
init { init {
exposeGlobally(MatteryCapability.MATTER, matter) exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, this) exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetable(::matter, MATTER_STORAGE_KEY) savetable(::matter, MATTER_STORAGE_KEY)
} }
@ -199,24 +195,18 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
}
override fun getMatterHandler(): IMatterStorage {
return matter
} }
override fun tick() { override fun tick() {
super.tick() super.tick()
val grid = matterNode.graph as MatterNetworkGraph? ?: return val grid = matterNode.graph as MatterGraph? ?: return
if (!matter.storedMatter.isZero) { if (!matter.storedMatter.isZero) {
val diff = matter.extractMatterInner(matter.storedMatter, true) val diff = matter.extractMatterInner(matter.storedMatter, true)

View File

@ -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.nbt.set
import ru.dbotthepony.mc.otm.core.util.ItemSorter import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.graph.matter.MatterNode
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.ArrayList import java.util.ArrayList
import java.util.stream.Stream import java.util.stream.Stream
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : 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> { class PlayerSettings(var sorter: ItemSorter = ItemSorter.DEFAULT, var ascending: Boolean = true) : INBTSerializable<CompoundTag> {
override fun serializeNBT(): CompoundTag { override fun serializeNBT(): CompoundTag {
@ -55,7 +56,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
private val listeners = ArrayList<MatterPanelMenu>() private val listeners = ArrayList<MatterPanelMenu>()
override val matterNode = Graph6Node<IMatterGraphNode>(this) val matterNode = SimpleMatterNode(tasks = this)
fun attachMenu(menu: MatterPanelMenu) { fun attachMenu(menu: MatterPanelMenu) {
listeners.add(menu) listeners.add(menu)
@ -70,24 +71,18 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
init { init {
exposeGlobally(MatteryCapability.MATTER_NODE, this) exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
exposeGlobally(MatteryCapability.TASK, this) exposeGlobally(MatteryCapability.TASK, this)
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
} }
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
}
override fun getTaskHandler(): IReplicationTaskProvider {
return this
} }
private val _tasks = HashMap<UUID, ReplicationTask>() private val _tasks = HashMap<UUID, ReplicationTask>()
@ -101,7 +96,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
override fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? { 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) { for ((key, task) in _tasks) {
if (task.required > 0) { if (task.required > 0) {
@ -127,7 +122,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val oldTask = localTask val oldTask = localTask
localTask = localTask.finish() localTask = localTask.finish()
val graph = matterNode.graph as MatterNetworkGraph? val graph = matterNode.graph as MatterGraph?
// Задача полностью выполнена // Задача полностью выполнена
if (localTask.required <= 0 && localTask.inProgress <= 0) { if (localTask.required <= 0 && localTask.inProgress <= 0) {
@ -196,7 +191,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val task = _tasks[id] ?: return val task = _tasks[id] ?: return
_tasks.remove(id) _tasks.remove(id)
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskRemoved(task) (matterNode.graph as MatterGraph?)?.onMatterTaskRemoved(task)
listeners.forEach { it.taskRemoved(task) } listeners.forEach { it.taskRemoved(task) }
setChanged() 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) val task = ReplicationTask(UUID.randomUUID(), state.id, state.item, 0, 0, count)
_tasks[task.id] = task _tasks[task.id] = task
(matterNode.graph as MatterNetworkGraph?)?.onMatterTaskCreated(task) (matterNode.graph as MatterGraph?)?.onMatterTaskCreated(task)
listeners.forEach { it.taskUpdated(task) } listeners.forEach { it.taskUpdated(task) }
setChanged() setChanged()
@ -215,7 +210,7 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
override fun dropAllTasks() { override fun dropAllTasks() {
val graph = matterNode.graph as MatterNetworkGraph? val graph = matterNode.graph as MatterGraph?
for (task in _tasks.values) { for (task in _tasks.values) {
graph?.onMatterTaskRemoved(task) graph?.onMatterTaskRemoved(task)

View File

@ -23,8 +23,7 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.item.MatterDustItem import ru.dbotthepony.mc.otm.item.MatterDustItem
import ru.dbotthepony.mc.otm.menu.matter.MatterRecyclerMenu import ru.dbotthepony.mc.otm.menu.matter.MatterRecyclerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities 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.util.WriteOnce
import ru.dbotthepony.mc.otm.core.math.getDecimal import ru.dbotthepony.mc.otm.core.math.getDecimal
import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.math.set
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) 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 { class RecyclerJob : Job {
var totalMatter: Decimal var totalMatter: Decimal
@ -72,13 +72,9 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
val container = MatteryContainer(this::itemContainerUpdated, 1).also(::addDroppableContainer) 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) val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_CONFIG)
override fun getMatterHandler(): IMatterStorage {
return matter
}
private val itemHandler = container.handler(object : HandlerFilter { private val itemHandler = container.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean { override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return stack.item is MatterDustItem return stack.item is MatterDustItem
@ -93,7 +89,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
exposeItemsGlobally(itemHandler) exposeItemsGlobally(itemHandler)
exposeEnergyGlobally(energy) exposeEnergyGlobally(energy)
exposeGlobally(MatteryCapability.MATTER, matter) exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, this) exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetable(::energy, ENERGY_KEY) savetable(::energy, ENERGY_KEY)
savetable(::container, INVENTORY_KEY) savetable(::container, INVENTORY_KEY)
savetable(::matter, MATTER_STORAGE_KEY) savetable(::matter, MATTER_STORAGE_KEY)
@ -101,14 +97,12 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
} }
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
@ -155,7 +149,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
override fun tick() { override fun tick() {
super.tick() super.tick()
val graph = matterNode.graph as MatterNetworkGraph? ?: return val graph = matterNode.graph as MatterGraph? ?: return
val received = graph.receiveMatter(matter.storedMatter, false) val received = graph.receiveMatter(matter.storedMatter, false)
if (!received.isZero) { if (!received.isZero) {

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu 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.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.ForgeConfigSpec 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.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection 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.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer 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.container.HandlerFilter
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.container.MatteryContainer
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.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
import ru.dbotthepony.mc.otm.core.math.defineDecimal 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.math.set
import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.core.nbt.set 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.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) : class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryWorkerBlockEntity<MatterReplicatorBlockEntity.ReplicatorJob>(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_, { 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) { } catch(err: NoSuchElementException) {
null null
} }
}), IMatterGraphNode { }) {
class ReplicatorJob : ItemJob { class ReplicatorJob : ItemJob {
val matterPerTick: Decimal val matterPerTick: Decimal
@ -98,44 +100,13 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES) val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES)
override val matterNode = Graph6Node<IMatterGraphNode>(this)
val matter = MatterStorageImpl(this::matterLevelUpdated, FlowDirection.INPUT, ::MATTER_CAPACITY) val matter = MatterStorageImpl(this::matterLevelUpdated, FlowDirection.INPUT, ::MATTER_CAPACITY)
val container = MatteryContainer(this::itemContainerUpdated, 5).also(::addDroppableContainer) val container = MatteryContainer(this::itemContainerUpdated, 5).also(::addDroppableContainer)
val itemHandler = container.handler(HandlerFilter.OnlyOut) val itemHandler = container.handler(HandlerFilter.OnlyOut)
init { val matterNode = object : MatterNode() {
exposeEnergyGlobally(energy) override fun getMatterHandler(): IMatterStorage {
exposeItemsGlobally(itemHandler) return matter
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
} }
override fun onMatterTaskCreated(task: IReplicationTask<*>) { override fun onMatterTaskCreated(task: IReplicationTask<*>) {
@ -155,17 +126,51 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
isIdling = false 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() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
} }
override fun jobUpdated(oldJob: ReplicatorJob?, newJob: ReplicatorJob?) { 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) var visualItemStack by synchronizer.item(observe = false)
private set private set
var visualProgress by synchronizer.float() var visualProgress by synchronizer.float().property
private set private set
var renderRotation = 0f var renderRotation = 0f
@ -188,8 +193,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return null to IdleReason.POWER return null to IdleReason.POWER
} }
val graph = matterNode.graph as MatterNetworkGraph? ?: return null to null val allocation = matterNode.graph.allocateTask(simulate = false) ?: return null to IdleReason.OBSERVING
val allocation = graph.allocateTask(simulate = false) ?: return null to IdleReason.OBSERVING
val stack = allocation.task.stack(1) val stack = allocation.task.stack(1)
val matter = MatterManager.get(stack) 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 { override fun onWorkTick(requiredPower: Decimal, extractedPower: Decimal, ticksAdvanced: Double, job: ReplicatorJob): Status {
val drainPerTick = job.matterPerTick * ticksAdvanced val drainPerTick = job.matterPerTick * ticksAdvanced
val graph = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT_FAST
if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) { if (matter.extractMatterInner(drainPerTick, true) < drainPerTick) {
// в машине недостаточно материи // в машине недостаточно материи
@ -219,7 +222,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (drainPerTick > matter.maxStoredMatter) { if (drainPerTick > matter.maxStoredMatter) {
// в тик требуется больше материи, чем её может хранить репликатор // в тик требуется больше материи, чем её может хранить репликатор
val toExtract = drainPerTick - matter.extractMatterInner(drainPerTick, true) val toExtract = drainPerTick - matter.extractMatterInner(drainPerTick, true)
val drain = graph.extractMatter(toExtract, true) val drain = matterNode.graph.extractMatter(toExtract, true)
if (drain != toExtract) { if (drain != toExtract) {
// недостаточно материи в сети // недостаточно материи в сети
@ -228,12 +231,12 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
// достаточно материи в сети + внутри машины // достаточно материи в сети + внутри машины
matter.extractMatterInner(drainPerTick, false) matter.extractMatterInner(drainPerTick, false)
graph.extractMatter(drain, false) matterNode.graph.extractMatter(drain, false)
return Status.SUCCESS return Status.SUCCESS
} else { } else {
// в тик требуется меньше материи, чем её может хранить репликатор // в тик требуется меньше материи, чем её может хранить репликатор
// примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше // примем из сети недостающее количество бака материи, или 200 тиков репликации, что меньше
val drain = graph.extractMatter((drainPerTick * DRAIN_MULT) val drain = matterNode.graph.extractMatter((drainPerTick * DRAIN_MULT)
.coerceAtMost(job.matterPerTick * (job.ticks - workTicks - ticksAdvanced)) .coerceAtMost(job.matterPerTick * (job.ticks - workTicks - ticksAdvanced))
.coerceAtLeast(Decimal.ONE) .coerceAtLeast(Decimal.ONE)
.coerceAtMost(matter.missingMatter), false) .coerceAtMost(matter.missingMatter), false)

View File

@ -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.DecimalConfigValue
import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.core.math.defineDecimal
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.matter.MatterScannerMenu import ru.dbotthepony.mc.otm.menu.matter.MatterScannerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.core.util.WriteOnce 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.matter.MatterManager
import java.util.* import java.util.*
import kotlin.math.pow import kotlin.math.pow
class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : 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 container = MatteryContainer(this::itemContainerUpdated, 1).also(::addDroppableContainer)
val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES) val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES)
@ -47,16 +47,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
}) })
init { val matterNode = object : MatterNode() {
exposeItemsGlobally(itemHandler)
exposeEnergyGlobally(energy)
exposeGlobally(MatteryCapability.MATTER_NODE, this)
savetable(::container, INVENTORY_KEY)
savetable(::energy, ENERGY_KEY)
}
// IMatterGraphNode
override fun onPatternAdded(state: IPatternState) { override fun onPatternAdded(state: IPatternState) {
if (idleReason == IdleReason.OBSERVING) { if (idleReason == IdleReason.OBSERVING) {
isIdling = false isIdling = false
@ -74,18 +65,25 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
isIdling = false 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() { override fun invalidateCaps() {
super.invalidateCaps() super.invalidateCaps()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { 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 { override fun onJobFinish(job: ItemJob): Status {
val grid = matterNode.graph as MatterNetworkGraph? ?: return Status.FAILURE_WAIT
val stack = job.itemStack val stack = job.itemStack
if (stack.isEmpty || !MatterManager.hasMatterValue(stack)) return Status.SUCCESS if (stack.isEmpty || !MatterManager.hasMatterValue(stack)) return Status.SUCCESS
var findState: IPatternState? = null 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) { if (findState == null && state.researchPercent < 1.0) {
findState = state findState = state
} else if (findState != null && findState.researchPercent < state.researchPercent && state.researchPercent < 1.0) { } 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) 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 return Status.SUCCESS
} else { } else {
return Status.FAILURE_WAIT return Status.FAILURE_WAIT
@ -129,14 +125,12 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return null to IdleReason.POWER return null to IdleReason.POWER
} }
val grid = matterNode.graph as MatterNetworkGraph? ?: return null to null
val stack = container.getItem(0) val stack = container.getItem(0)
if (stack.isEmpty || !MatterManager.canDecompose(stack)) return null to IdleReason.ITEM if (stack.isEmpty || !MatterManager.canDecompose(stack)) return null to IdleReason.ITEM
var findState: IPatternState? = null 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) { if (state.researchPercent < 1.0) {
findState = state findState = state
} else if (state.researchPercent >= 1.0) { } else if (state.researchPercent >= 1.0) {
@ -155,7 +149,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
PatternState(UUID.randomUUID(), stack.item, researchAdvance) 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 } val copy = stack.copy().also { it.count = 1 }
stack.shrink(1) stack.shrink(1)
container.setChanged() container.setChanged()
@ -168,10 +162,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel) {
MatterNetworkGraph.discoverFull(this, matterNode)
}
} }
companion object { companion object {

View File

@ -20,8 +20,8 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.core.collect.iterator import ru.dbotthepony.mc.otm.core.collect.iterator
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.ArrayList import java.util.ArrayList
import java.util.stream.Stream import java.util.stream.Stream
@ -29,24 +29,22 @@ import java.util.stream.Stream
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : 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) { val container: MatteryContainer = object : MatteryContainer(this::setChanged, 8) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
val grid = matterNode.graph as MatterNetworkGraph? if (!ItemStack.isSameItemSameTags(new, old)) {
if (grid != null && !ItemStack.isSameItemSameTags(new, old)) {
if (!old.isEmpty) { if (!old.isEmpty) {
old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.patterns.forEach { grid.onPatternRemoved(it) } cap.patterns.forEach { matterNode.graph.onPatternRemoved(it) }
} }
} }
if (!new.isEmpty) { if (!new.isEmpty) {
new.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> 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) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
matterNode.discover(this)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
}
override fun getPatternHandler(): IPatternStorage {
return this
} }
override fun invalidateCaps() { override fun invalidateCaps() {
super.invalidateCaps() super.invalidateCaps()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
init { init {
exposeGlobally(MatteryCapability.PATTERN, this) exposeGlobally(MatteryCapability.PATTERN, this)
exposeGlobally(MatteryCapability.MATTER_NODE, this) exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
exposeItemsGlobally(itemHandler) exposeItemsGlobally(itemHandler)
savetable(::container, INVENTORY_KEY) savetable(::container, INVENTORY_KEY)
@ -138,7 +130,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
matterNode.destroy(::MatterNetworkGraph) matterNode.isValid = false
} }
override fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus { override fun insertPattern(pattern: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
@ -149,14 +141,10 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (!simulate) { if (!simulate) {
setChanged() setChanged()
val graph = matterNode.graph as MatterNetworkGraph?
if (graph != null) {
if (status.isInserted) { if (status.isInserted) {
graph.onPatternAdded(status.newState!!) matterNode.graph.onPatternAdded(status.newState!!)
} else { } else {
graph.onPatternUpdated(status.newState!!, status.oldState!!) matterNode.graph.onPatternUpdated(status.newState!!, status.oldState!!)
}
} }
} }

View File

@ -9,13 +9,13 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity 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.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu 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.registry.MBlockEntities
import ru.dbotthepony.mc.otm.storage.* import ru.dbotthepony.mc.otm.storage.*
@ -41,7 +41,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
}.also(::addDroppableContainer) }.also(::addDroppableContainer)
val cell = BasicStorageGraphNode(energy) val cell = StorageNode(energy)
init { init {
savetable(::energy, ENERGY_KEY) savetable(::energy, ENERGY_KEY)
@ -52,9 +52,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
cell.discover(this)
if (level is ServerLevel)
StorageNetworkGraph.discoverFull(this, cell.storageNode)
} }
override fun tick() { override fun tick() {
@ -68,6 +66,6 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
cell.destroy(level) cell.isValid = false
} }
} }

View File

@ -30,8 +30,8 @@ import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.graph.storage.StorageNode
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph import ru.dbotthepony.mc.otm.graph.storage.StorageGraph
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.container.set
@ -188,13 +188,13 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
var poweredView: PoweredVirtualComponent<ItemStackWrapper>? = null var poweredView: PoweredVirtualComponent<ItemStackWrapper>? = null
private set private set
val cell = object : BasicStorageGraphNode(energy) { val cell = object : StorageNode(energy) {
override fun attachComponents(to: StorageNetworkGraph) { override fun attachComponents(to: StorageGraph) {
super.attachComponents(to) super.attachComponents(to)
poweredView = PoweredVirtualComponent(to.getVirtualComponent(ITEM_STORAGE), energy) poweredView = PoweredVirtualComponent(to.getVirtualComponent(ITEM_STORAGE), energy)
} }
override fun removeComponents(from: StorageNetworkGraph) { override fun removeComponents(from: StorageGraph) {
super.removeComponents(from) super.removeComponents(from)
poweredView?.removeListeners() poweredView?.removeListeners()
poweredView = null poweredView = null
@ -499,13 +499,11 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
cell.discover(this)
if (level is ServerLevel)
StorageNetworkGraph.discoverFull(this, cell.storageNode)
} }
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
cell.destroy(level) cell.isValid = false
} }
} }

View File

@ -4,8 +4,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction 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.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu 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.isPositive
import ru.dbotthepony.mc.otm.core.math.isZero import ru.dbotthepony.mc.otm.core.math.isZero
import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.storage.StorageNode
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.menu.storage.StorageBusMenu import ru.dbotthepony.mc.otm.menu.storage.StorageBusMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.storage.* import ru.dbotthepony.mc.otm.storage.*
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.math.BigInteger import java.math.BigInteger
import java.util.* import java.util.*
import java.util.stream.Stream 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 SlotTuple(val slot: Int, val stack: ItemStack)
private class TrackedTuple(override val stack: ItemStackWrapper, override val id: UUID) : IStorageTuple<ItemStackWrapper> { 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) savetable(::energy, ENERGY_KEY)
} }
val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(energy), GraphNodeListener { val cell: StorageNode = object : StorageNode(energy) {
override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { override fun onNeighbour(direction: Direction) {
val newState = this@StorageBusBlockEntity.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) val newState = this@StorageBusBlockEntity.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true)
if (newState !== this@StorageBusBlockEntity.blockState && SERVER_IS_LIVE) if (newState !== this@StorageBusBlockEntity.blockState && SERVER_IS_LIVE)
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS) 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) val newState = this@StorageBusBlockEntity.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false)
if (newState !== this@StorageBusBlockEntity.blockState && SERVER_IS_LIVE) if (newState !== this@StorageBusBlockEntity.blockState && SERVER_IS_LIVE)
@ -109,11 +100,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
cell.discover(this)
if (level is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode)
}
tickList.once(this::checkSurroundings) tickList.once(this::checkSurroundings)
} }
@ -128,7 +115,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
cell.destroy(level) cell.isValid = false
} }
fun checkSurroundings() { fun checkSurroundings() {

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.block.entity.storage
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.network.chat.Component 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.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu 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.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.core.TranslatableComponent 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.RelativeSide
import ru.dbotthepony.mc.otm.core.math.toIntSafe import ru.dbotthepony.mc.otm.core.math.toIntSafe
import ru.dbotthepony.mc.otm.core.orNull import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.storage.StorageNode
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.menu.storage.StorageExporterMenu import ru.dbotthepony.mc.otm.menu.storage.StorageExporterMenu
import ru.dbotthepony.mc.otm.menu.storage.StorageImporterMenu import ru.dbotthepony.mc.otm.menu.storage.StorageImporterMenu
import ru.dbotthepony.mc.otm.once import ru.dbotthepony.mc.otm.once
@ -62,8 +57,8 @@ abstract class AbstractStorageImportExport<T>(
savetable(::energy, ENERGY_KEY) savetable(::energy, ENERGY_KEY)
} }
val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(energy), GraphNodeListener { val cell: StorageNode = object : StorageNode(energy) {
override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { override fun onNeighbour(direction: Direction) {
level?.once { level?.once {
if (!isRemoved) { if (!isRemoved) {
val newState = this@AbstractStorageImportExport.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, true) 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 { level?.once {
if (!isRemoved) { if (!isRemoved) {
val newState = this@AbstractStorageImportExport.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false) val newState = this@AbstractStorageImportExport.blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[direction]!!, false)
@ -93,15 +88,12 @@ abstract class AbstractStorageImportExport<T>(
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
cell.destroy(level) cell.isValid = false
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
cell.discover(this)
if (level is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode)
}
} }
protected abstract val targetCapability: Capability<T> protected abstract val targetCapability: Capability<T>
@ -117,7 +109,6 @@ abstract class AbstractStorageImportExport<T>(
} }
companion object { companion object {
val MAX_POWER = Decimal(10_000)
const val FILTER_KEY = "filter" const val FILTER_KEY = "filter"
} }
} }
@ -155,7 +146,7 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : A
if (redstoneControl.isBlockedByRedstone || !filter.match(stack)) if (redstoneControl.isBlockedByRedstone || !filter.match(stack))
return 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) val maxMove = energy.extractEnergyExact(ITEM_STORAGE.energyPerOperation, stack.count.toBigInteger(), true)
if (maxMove == BigInteger.ZERO) if (maxMove == BigInteger.ZERO)
@ -195,8 +186,7 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : A
val target = target.get().orNull() val target = target.get().orNull()
if (nextTick <= 0 && target != null && enoughEnergy) { if (nextTick <= 0 && target != null && enoughEnergy) {
val graph = cell.storageGraph ?: return val items = cell.graph.getVirtualComponent(ITEM_STORAGE)
val items = graph.getVirtualComponent(ITEM_STORAGE)
if (lastSlot >= target.slots) { if (lastSlot >= target.slots) {
lastSlot = 0 lastSlot = 0
@ -227,7 +217,6 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : A
companion object { companion object {
const val MAX_MOVE_PER_OPERATION = 4 const val MAX_MOVE_PER_OPERATION = 4
private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_IMPORTER}")
private const val INTERVAL = 5 private const val INTERVAL = 5
const val MAX_FILTERS = 6 * 3 const val MAX_FILTERS = 6 * 3
} }
@ -271,7 +260,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
override val filter = ItemFilter(MAX_FILTERS) { _, _, _ -> override val filter = ItemFilter(MAX_FILTERS) { _, _, _ ->
relevantTuples.clear() relevantTuples.clear()
val component = cell.storageGraph?.getVirtualComponent(ITEM_STORAGE) ?: return@ItemFilter val component = cell.graph.getVirtualComponent(ITEM_STORAGE)
for (tuple in component.stacks) { for (tuple in component.stacks) {
addStack(tuple, component) addStack(tuple, component)
@ -291,7 +280,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
private val exportStacks: Stream<Pair<UUID, ItemStackWrapper>> private val exportStacks: Stream<Pair<UUID, ItemStackWrapper>>
get() { 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] } return relevantTuples.stream().map { it to view[it] }
} }
@ -308,8 +297,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
val target = target.get().orNull() val target = target.get().orNull()
if (nextTick <= 0 && target != null && enoughEnergy) { if (nextTick <= 0 && target != null && enoughEnergy) {
val graph = cell.storageGraph ?: return val items = cell.graph.getVirtualComponent(ITEM_STORAGE)
val items = graph.getVirtualComponent(ITEM_STORAGE)
if (lastSlot >= target.slots) { if (lastSlot >= target.slots) {
lastSlot = 0 lastSlot = 0

View File

@ -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.capability.energy.transferChecked
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.graph.storage.StorageNode
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph import ru.dbotthepony.mc.otm.graph.storage.StorageGraph
import ru.dbotthepony.mc.otm.menu.storage.StoragePowerSupplierMenu import ru.dbotthepony.mc.otm.menu.storage.StoragePowerSupplierMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
@ -23,7 +23,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState
return StoragePowerSupplierMenu(containerID, inventory, this) return StoragePowerSupplierMenu(containerID, inventory, this)
} }
val cell = BasicStorageGraphNode() val cell = StorageNode()
val energy = WorkerEnergyStorage(this, MachinesConfig.STORAGE_POWER_SUPPLIER) val energy = WorkerEnergyStorage(this, MachinesConfig.STORAGE_POWER_SUPPLIER)
init { init {
@ -42,15 +42,12 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
cell.discover(this)
if (level is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode)
}
} }
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
cell.destroy(level) cell.isValid = false
} }
override fun tick() { override fun tick() {
@ -62,9 +59,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState
if (energy.batteryLevel.isZero) if (energy.batteryLevel.isZero)
return return
val graph = cell.storageGraph ?: return if (cell.graph.powerDemandingNodes.isEmpty())
if (graph.powerDemandingNodes.isEmpty())
return return
var demand = Decimal.ZERO var demand = Decimal.ZERO
@ -72,7 +67,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState
val available = energy.batteryLevel.coerceAtMost(MachinesConfig.STORAGE_POWER_SUPPLIER.throughput) 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) val received = demanding.receiveEnergy(available, true)
if (received.isPositive) { if (received.isPositive) {
@ -84,13 +79,13 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState
if (demand.isZero) { if (demand.isZero) {
return return
} else if (demand < available) { } else if (demand < available) {
for (demanding in graph.powerDemandingNodes) { for (demanding in cell.graph.powerDemandingNodes) {
powerPassed += energy.transferChecked(demanding, available, false) powerPassed += energy.transferChecked(demanding, available, false)
} }
} else { } else {
val forEach = available / i val forEach = available / i
for (demanding in graph.powerDemandingNodes) { for (demanding in cell.graph.powerDemandingNodes) {
powerPassed += energy.transferChecked(demanding, forEach, false) powerPassed += energy.transferChecked(demanding, forEach, false)
} }
} }

View File

@ -21,8 +21,9 @@ import ru.dbotthepony.mc.otm.onceServer
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
import ru.dbotthepony.mc.otm.core.math.isPositive import ru.dbotthepony.mc.otm.core.math.isPositive
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.core.util.LOHolder
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.storage.* import ru.dbotthepony.mc.otm.storage.*
import java.math.BigInteger import java.math.BigInteger
import java.util.UUID import java.util.UUID
@ -206,14 +207,14 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit
private var frequencyAccess: QIOFrequencyAccess? = null private var frequencyAccess: QIOFrequencyAccess? = null
private var wasAttached = false private var wasAttached = false
val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(), ITickable { val cell: StorageNode = object : StorageNode(), ITickable {
init { init {
manualAttaching = true manualAttaching = true
} }
override fun tick() { override fun tick() {
if (tile.isRemoved) { if (tile.isRemoved) {
destroy(tile.level) isValid = false
return return
} }
@ -225,9 +226,7 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit
val lastFrequency = lastFrequency ?: throw IllegalStateException("lastFrequency is null") val lastFrequency = lastFrequency ?: throw IllegalStateException("lastFrequency is null")
checkNotNull(storageGraph) { graph.userData.remove(key(lastFrequency))
"Unexpected internal state (expected storage graph to be present, something detached $this from storage grid, but did not call removeComponents())"
}.userData.remove(key(lastFrequency))
} }
frequencyAccess?.let(this::removeStorageComponent) frequencyAccess?.let(this::removeStorageComponent)
@ -240,17 +239,16 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit
val frequencyAccess = frequencyAccess ?: return val frequencyAccess = frequencyAccess ?: return
frequencyAccess.scan() frequencyAccess.scan()
val storageGraph = storageGraph ?: return
val key = key(frequencyAccess.parent) val key = key(frequencyAccess.parent)
if (!storageGraph.userData.containsKey(key)) { if (!graph.userData.containsKey(key)) {
storageGraph.userData[key] = true graph.userData[key] = true
wasAttached = true wasAttached = true
storageGraph.add(frequencyAccess) graph.add(frequencyAccess)
} }
} }
override fun removeComponents(from: StorageNetworkGraph) { override fun removeComponents(from: StorageGraph) {
super.removeComponents(from) super.removeComponents(from)
if (wasAttached) { if (wasAttached) {
@ -259,11 +257,23 @@ private class QIOStorage(private val tile: TileEntityQIODriveArray) : ICapabilit
wasAttached = false 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> { override fun <T : Any> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (cap === MatteryCapability.STORAGE_NODE) if (cap === MatteryCapability.STORAGE_NODE)
return cell.get().cast() return holder.get()
return LazyOptional.empty() return LazyOptional.empty()
} }
@ -286,8 +296,8 @@ fun attachCapabilities(event: AttachCapabilitiesEvent<BlockEntity>) {
event.addCapability(QIO_LOCATION, capability) event.addCapability(QIO_LOCATION, capability)
onceServer { onceServer {
if (!event.`object`.isRemoved && event.`object`.level?.isClientSide == false) { if (!event.`object`.isRemoved) {
StorageNetworkGraph.discoverFull(event.`object`, capability.cell.storageNode) capability.cell.discover(event.`object`, MatteryCapability.STORAGE_NODE)
} }
} }
} }

View 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()
}
}

View File

@ -1,178 +1,172 @@
package ru.dbotthepony.mc.otm.graph 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.util.IConditionalTickable
import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.util.ITickable
import ru.dbotthepony.mc.otm.addTicker import java.lang.ref.WeakReference
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.HashMap
abstract class Abstract6Graph<T> : IConditionalTickable { open class Abstract6Graph<N : Graph6Node<N, G>, G : Abstract6Graph<N, G>> : IConditionalTickable {
protected val nodes = ArrayList<Graph6Node<T>>() private val nodesInternal = ArrayList<N>()
fun size() = nodes.size private val conditional = ArrayList<IConditionalTickable>()
private val tickable = ArrayList<Graph6Node<T>>() private val always = ArrayList<ITickable>()
val nodeList: Collection<Graph6Node<T>> = Collections.unmodifiableCollection(nodes)
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 * Allows storing arbitrary data by external code
*/ */
@JvmField
val userData = HashMap<UUID, Any>() val userData = HashMap<UUID, Any>()
abstract fun onNodeRemoved(node: Graph6Node<T>) open fun onNodeRemoved(node: N) {}
abstract fun onNodeAdded(node: Graph6Node<T>) open fun onNodeAdded(node: N) {}
open fun onMergedInto(other: G) {}
override fun tick(): Boolean { protected open fun innerTick(): Boolean {
for (i in tickable.size - 1 downTo 0) { return false
val node = tickable[i] }
final override fun tick(): Boolean {
if (isMerged)
return false
// позволяет вершинам изменять список тикающих вершин
for (i in conditional.size - 1 downTo 0) {
val node = conditional[i]
if (!node.tick()) { 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>) { return innerTick() || always.isNotEmpty() || conditional.isNotEmpty()
if (!nodes.remove(node))
throw IllegalStateException("Not containing node $node")
node.graph = null
onNodeRemoved(node)
tickable.remove(node)
} }
fun addNode(node: Graph6Node<T>) { fun addNode(node: N): Boolean {
if (nodes.contains(node)) if (node in nodesInternal)
throw IllegalStateException("Already containing node $node") 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) 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) if (other === this)
return this return this
if (size() >= other.size()) { if (size >= other.size) {
for (node in other.nodes) { for (node in other.nodesInternal) {
nodes.add(node) nodesInternal.add(node)
node.graph = this setter.invoke(node, this as G)
onNodeAdded(node) 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 return this
} else { } else {
return other.merge(this) return other.merge(this as G, setter)
} }
} }
companion object { companion object {
fun <T> discoverFull( private val graphs = ArrayList<WeakReference<Abstract6Graph<*, *>>>()
level: ServerLevel, private val next = ArrayList<WeakReference<Abstract6Graph<*, *>>>()
blockPos: BlockPos,
node: Graph6Node<T>, fun tick() {
nodeGetter: (BlockEntity) -> Graph6Node<T>?, if (next.isNotEmpty()) {
factory: () -> Abstract6Graph<T> graphs.addAll(next)
) { next.clear()
level.addTicker {
!discover(level, blockPos, node, nodeGetter, factory) && node.valid
}
} }
@JvmStatic val iterator = graphs.iterator()
fun <T> discover(
level: ServerLevel,
blockPos: BlockPos,
node: Graph6Node<T>,
nodeGetter: (BlockEntity) -> Graph6Node<T>?,
factory: () -> Abstract6Graph<T>
): Boolean {
var fullDiscovery = true
node.nullifyConnections() for (value in iterator) {
val graph = value.get()
var _graph = node.graph if (graph == null || !graph.tick()) {
graph?.isTicking = false
// для начала найдем граф к которому будем принадлежать iterator.remove()
if (_graph == null) {
for (dir in Direction.values()) {
val offset = blockPos + dir
val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(offset.x), SectionPos.blockToSectionCoord(offset.z))
if (chunk == null) {
fullDiscovery = false
continue
}
val entity = chunk.getBlockEntity(offset)
if (entity != null) {
val getNode = nodeGetter(entity)
if (getNode?.graph != null) {
_graph = getNode.graph
break
} }
} }
} }
// мы нашли граф рядом
if (_graph != null) {
node.graph = _graph
_graph.addNode(node)
} else {
// графов рядом нет, создаем свой
_graph = factory()
node.graph = _graph
_graph.addNode(node)
}
}
// теперь снова смотрим на соседей, если у них нет графа - присоединяем к своему
// если у них есть граф - слияем его со своим или свой с его
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
}
} }
} }

View File

@ -1,313 +1,268 @@
package ru.dbotthepony.mc.otm.graph package ru.dbotthepony.mc.otm.graph
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable import net.minecraft.core.SectionPos
import ru.dbotthepony.mc.otm.core.util.ITickable import net.minecraft.server.level.ServerLevel
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE 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 { open class Graph6Node<N : Graph6Node<N, G>, G : Abstract6Graph<N, G>>(val graphFactory: () -> G) {
fun onNeighbourTop(node: Graph6Node<*>) = onNeighbour(node, Direction.UP) private val neighbours = EnumMap<Direction, N>(Direction::class.java)
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)
fun onNeighbour(node: Graph6Node<*>, direction: Direction) var graph: G = graphFactory.invoke()
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
private set private set
fun destroy(factory: () -> Abstract6Graph<T>): List<GraphFlooder<T>> { init {
if (!valid || !SERVER_IS_LIVE) return emptyList() graph.addNode(this as N)
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()
} }
val paths = _flood() private var seen: Int = 0
if (paths.size < 2) { operator fun get(direction: Direction): N? = neighbours[direction]
return paths
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) { val old = neighbours[direction]
if (biggest.size() < paths[i].size()) { if (old === node) return
biggest = paths[i]
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) { var top: N?
if (flooder == biggest) continue 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) { var south: N?
node.graph?.removeNode(node) get() = neighbours[Direction.SOUTH]
graph.addNode(node) 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
}
} }
} }

View File

@ -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)
}
}
}
}
}

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.graph.matter package ru.dbotthepony.mc.otm.graph.matter
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.graph.Graph6Node
interface IMatterGraphListener { interface IMatterGraphListener {
fun onPatternAdded(state: IPatternState) {} fun onPatternAdded(state: IPatternState) {}
@ -13,12 +12,3 @@ interface IMatterGraphListener {
fun onMatterTaskFinished(state: IReplicationTask<*>) {} fun onMatterTaskFinished(state: IReplicationTask<*>) {}
fun onMatterTaskRemoved(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?
}

View File

@ -1,30 +1,25 @@
package ru.dbotthepony.mc.otm.graph.matter package ru.dbotthepony.mc.otm.graph.matter
import com.google.common.collect.Streams import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.item.Item 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.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.core.filterNotNull import ru.dbotthepony.mc.otm.core.filterNotNull
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.graph.Abstract6Graph import ru.dbotthepony.mc.otm.graph.Abstract6Graph
import ru.dbotthepony.mc.otm.graph.Graph6Node
import java.util.* import java.util.*
import java.util.function.Predicate import java.util.function.Predicate
import java.util.stream.Stream import java.util.stream.Stream
import kotlin.collections.HashSet
@Suppress("unused") @Suppress("unused")
class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListener { class MatterGraph : Abstract6Graph<MatterNode, MatterGraph>(), IMatterGraphListener {
private val listeners = HashSet<IMatterGraphListener>() private val listeners = ObjectOpenHashSet<IMatterGraphListener>()
fun addListener(listener: IMatterGraphListener) = listeners.add(listener) fun addListener(listener: IMatterGraphListener) = listeners.add(listener)
fun removeListener(listener: IMatterGraphListener) = listeners.remove(listener) fun removeListener(listener: IMatterGraphListener) = listeners.remove(listener)
override fun onNodeRemoved(node: Graph6Node<IMatterGraphNode>) { override fun onNodeRemoved(node: MatterNode) {
val patterns = node.value.getPatternHandler() val patterns = node.getPatternHandler()
if (patterns != null) { if (patterns != null) {
for (pattern in patterns.patterns) { 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) { if (tasks != null) {
for (task in tasks.replicationTasks) { for (task in tasks.replicationTasks) {
@ -41,24 +36,24 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
} }
for (pattern in this.patterns) { for (pattern in this.patterns) {
node.value.onPatternRemoved(pattern) node.onPatternRemoved(pattern)
} }
for (task in this.tasks) { 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) { for (pattern in this.patterns) {
node.value.onPatternAdded(pattern) node.onPatternAdded(pattern)
} }
for (task in this.tasks) { for (task in this.tasks) {
node.value.onMatterTaskCreated(task) node.onMatterTaskCreated(task)
} }
val patterns = node.value.getPatternHandler() val patterns = node.getPatternHandler()
if (patterns != null) { if (patterns != null) {
for (pattern in patterns.patterns) { 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) { if (tasks != null) {
for (task in tasks.replicationTasks) { for (task in tasks.replicationTasks) {
@ -79,7 +74,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
var level = Decimal.ZERO var level = Decimal.ZERO
for (node in nodes) { for (node in nodes) {
val matter = node.value.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) { if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) {
level += matter.storedMatter level += matter.storedMatter
@ -93,7 +88,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
var level = Decimal.ZERO var level = Decimal.ZERO
for (node in nodes) { for (node in nodes) {
val matter = node.value.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) { if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) {
level += matter.maxStoredMatter level += matter.maxStoredMatter
@ -112,7 +107,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
var extracted = Decimal.ZERO var extracted = Decimal.ZERO
for (node in nodes) { for (node in nodes) {
val matter = node.value.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null) { if (matter != null) {
val value = matter.extractMatter(howMuch, simulate) val value = matter.extractMatter(howMuch, simulate)
@ -136,7 +131,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
var received = Decimal.ZERO var received = Decimal.ZERO
for (node in nodes) { for (node in nodes) {
val matter = node.value.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) { if (matter != null && matter.matterFlow == FlowDirection.BI_DIRECTIONAL) {
val value = matter.receiveMatter(howMuch, simulate) val value = matter.receiveMatter(howMuch, simulate)
@ -160,7 +155,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
var received = Decimal.ZERO var received = Decimal.ZERO
for (node in nodes) { for (node in nodes) {
val matter = node.value.getMatterHandler() val matter = node.getMatterHandler()
if (matter != null && matter.matterFlow != FlowDirection.OUTPUT) { if (matter != null && matter.matterFlow != FlowDirection.OUTPUT) {
val value = matter.receiveMatter(howMuch, simulate) 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 { private fun doInsertPattern(state: IPatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
for (node in nodes) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.getPatternHandler()
if (storage != null) { if (storage != null) {
val status = storage.insertPattern(state, onlyUpdate, simulate) val status = storage.insertPattern(state, onlyUpdate, simulate)
@ -198,23 +193,23 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
return doInsertPattern(state, false, simulate) return doInsertPattern(state, false, simulate)
} }
val tasks: Stream<out IReplicationTask<*>> get() { val tasks: Stream<IReplicationTask<*>> get() {
return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.replicationTasks }.toTypedArray()) return nodes.stream().map { it.getTaskHandler()?.replicationTasks }.filterNotNull().flatMap { it }
} }
val allTasks: Stream<out IReplicationTask<*>> get() { val allTasks: Stream<IReplicationTask<*>> get() {
return Streams.concat(*nodes.mapNotNull { it.value.getTaskHandler()?.allReplicationTasks }.toTypedArray()) return nodes.stream().map { it.getTaskHandler()?.allReplicationTasks }.filterNotNull().flatMap { it }
} }
val patterns: Stream<out IPatternState> get() { val patterns: Stream<IPatternState> get() {
return nodes.stream().map { it.value.getPatternHandler()?.patterns }.filterNotNull().flatMap { it } return nodes.stream().map { it.getPatternHandler()?.patterns }.filterNotNull().flatMap { it }
} }
val patternCount: Long get() { val patternCount: Long get() {
var value = 0L var value = 0L
for (node in nodes) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.getPatternHandler()
if (storage != null) { if (storage != null) {
value += storage.storedPatterns value += storage.storedPatterns
@ -228,7 +223,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
var value = 0L var value = 0L
for (node in nodes) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.getPatternHandler()
if (storage != null) { if (storage != null) {
value += storage.patternCapacity value += storage.patternCapacity
@ -240,7 +235,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
fun getPattern(id: UUID): IPatternState? { fun getPattern(id: UUID): IPatternState? {
for (node in nodes) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.getPatternHandler()
if (storage != null) { if (storage != null) {
val get = storage.getPattern(id) val get = storage.getPattern(id)
@ -260,7 +255,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
fun findPattern(predicate: Predicate<IPatternState>): IPatternState? { fun findPattern(predicate: Predicate<IPatternState>): IPatternState? {
for (node in nodes) { for (node in nodes) {
val storage = node.value.getPatternHandler() val storage = node.getPatternHandler()
if (storage != null) { if (storage != null) {
val find = storage.patterns.filter(predicate).findAny() val find = storage.patterns.filter(predicate).findAny()
@ -284,7 +279,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? { fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? {
for (node in nodes) { for (node in nodes) {
val tasks = node.value.getTaskHandler() val tasks = node.getTaskHandler()
if (tasks != null) { if (tasks != null) {
val allocated = tasks.allocateTask(simulate) val allocated = tasks.allocateTask(simulate)
@ -299,87 +294,41 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
} }
fun notifyTaskCompletion(taskId: UUID): Boolean { 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) { 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) for (node in listeners) node.onPatternAdded(state)
} }
override fun onPatternRemoved(state: IPatternState) { 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) for (node in listeners) node.onPatternRemoved(state)
} }
override fun onPatternUpdated(newState: IPatternState, oldState: IPatternState) { 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) for (node in listeners) node.onPatternUpdated(newState, oldState)
} }
override fun onMatterTaskCreated(task: IReplicationTask<*>) { 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) for (node in listeners) node.onMatterTaskCreated(task)
} }
override fun <T : IReplicationTask<*>> onMatterTaskUpdated(newState: T, oldState: T) { 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) for (node in listeners) node.onMatterTaskUpdated(newState, oldState)
} }
override fun onMatterTaskFinished(state: IReplicationTask<*>) { 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) for (node in listeners) node.onMatterTaskFinished(state)
} }
override fun onMatterTaskRemoved(state: IReplicationTask<*>) { 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) 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
)
}
}
} }

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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?
}

View File

@ -14,8 +14,9 @@ import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.storage.* import ru.dbotthepony.mc.otm.storage.*
import java.util.LinkedList import java.util.LinkedList
class StorageNetworkGraph(private val level: Level) : Abstract6Graph<IStorageGraphNode>() { class StorageGraph : Abstract6Graph<StorageNode, StorageGraph>() {
private val virtualComponents = Object2ObjectArrayMap<StorageStackType<*>, VirtualComponent<*>>() private val virtualComponents = Object2ObjectArrayMap<StorageStackType<*>, VirtualComponent<*>>()
val powerDemandingNodes = LinkedList<IMatteryEnergyStorage>()
/** /**
* Returns a [VirtualComponent] representing [type] storage * 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> return virtualComponents.computeIfAbsent(StorageRegistry.get(type), Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent<T>
} }
private var addedTicker = false
fun <T : IStorageStack> add(storage: IStorage<T>) { fun <T : IStorageStack> add(storage: IStorage<T>) {
getVirtualComponent(storage.storageType).add(storage) getVirtualComponent(storage.storageType).add(storage)
} }
@ -46,50 +45,12 @@ class StorageNetworkGraph(private val level: Level) : Abstract6Graph<IStorageGra
return (virtual as VirtualComponent<T>).contains(storage) return (virtual as VirtualComponent<T>).contains(storage)
} }
override fun onNodeAdded(node: Graph6Node<IStorageGraphNode>) { override fun onNodeAdded(node: StorageNode) {
node.value.attachComponents(this) node.attachComponents(this)
if (!addedTicker) {
addedTicker = true
level.addTickerPre(this)
}
} }
override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) { override fun onNodeRemoved(node: StorageNode) {
node.value.removeComponents(this) 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!!) }
}
}
} }

View File

@ -1,7 +1,7 @@
package ru.dbotthepony.mc.otm.graph.storage package ru.dbotthepony.mc.otm.graph.storage
import net.minecraft.world.level.Level import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraftforge.common.util.LazyOptional import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.storage.IStorage import ru.dbotthepony.mc.otm.storage.IStorage
@ -9,9 +9,7 @@ import ru.dbotthepony.mc.otm.storage.IStorageStack
import ru.dbotthepony.mc.otm.storage.StorageStackType import ru.dbotthepony.mc.otm.storage.StorageStackType
import java.util.* import java.util.*
open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStorage? = null) : IStorageGraphNode { open class StorageNode(private val energyDemander: IMatteryEnergyStorage? = null) : Graph6Node<StorageNode, StorageGraph>(::StorageGraph) {
private var resolver = LazyOptional.of<IStorageGraphNode> { this }
private var valid = true
protected val components = ArrayList<IStorage<*>>() protected val components = ArrayList<IStorage<*>>()
/** /**
@ -22,13 +20,12 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora
* [invalidate] and [removeComponents] still detach all components * [invalidate] and [removeComponents] still detach all components
*/ */
protected var manualAttaching = false protected var manualAttaching = false
@Suppress("LeakingThis")
final override val storageNode = Graph6Node<IStorageGraphNode>(this)
private var demandingEnergy = false 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 != null) {
if (energyDemander.missingPower.isPositive) { if (energyDemander.missingPower.isPositive) {
demandingEnergy = true demandingEnergy = true
@ -45,19 +42,13 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora
} }
} }
fun tickEnergyDemanding() { /**
energyDemander ?: throw IllegalStateException("No energy demander") * Called by storage graph on node being detached from it
*
if (!demandingEnergy && storageGraph != null && energyDemander.missingPower.isPositive) { * This is NOT called when graph is being destroyed (e.g. even by merging
demandingEnergy = true * with another graph).
storageGraph!!.powerDemandingNodes.add(energyDemander) */
} else if (demandingEnergy && storageGraph != null && !energyDemander.missingPower.isPositive) { open fun removeComponents(from: StorageGraph) {
demandingEnergy = false
storageGraph!!.powerDemandingNodes.remove(energyDemander)
}
}
override fun removeComponents(from: StorageNetworkGraph) {
for (component in components) { for (component in components) {
from.remove(component) 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") @Suppress("unchecked_cast")
fun <T : IStorageStack, U : IStorage<T>> computeIfAbsent(identity: StorageStackType<T>, provider: (StorageStackType<T>) -> U): U { fun <T : IStorageStack, U : IStorage<T>> computeIfAbsent(identity: StorageStackType<T>, provider: (StorageStackType<T>) -> U): U {
for (component in components) { for (component in components) {
@ -90,8 +93,8 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora
components.add(component) components.add(component)
if (valid && !manualAttaching) if (isValid && !manualAttaching)
storageGraph?.add(component) graph.add(component)
} }
fun removeStorageComponent(component: IStorage<*>) { fun removeStorageComponent(component: IStorage<*>) {
@ -111,8 +114,8 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora
val self = components[indexOf] val self = components[indexOf]
components.removeAt(indexOf) components.removeAt(indexOf)
if (valid) if (isValid)
storageGraph?.remove(self) graph.remove(self)
} }
fun removeStorageComponent(component: StorageStackType<*>) { fun removeStorageComponent(component: StorageStackType<*>) {
@ -132,47 +135,25 @@ open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStora
val self = components[indexOf] val self = components[indexOf]
components.removeAt(indexOf) components.removeAt(indexOf)
if (valid && !manualAttaching) if (isValid && !manualAttaching)
storageGraph?.remove(self) graph.remove(self)
} }
open fun invalidate() { override fun invalidate() {
if (!valid) return
valid = false
resolver.invalidate()
val storageGraph = storageGraph
if (storageGraph != null) {
for (component in components) { for (component in components) {
storageGraph.remove(component) graph.remove(component)
}
} }
} }
open fun revive() { override fun revive() {
if (valid) return if (!manualAttaching) {
valid = true
resolver = LazyOptional.of { this }
val storageGraph = storageGraph
if (storageGraph != null && !manualAttaching) {
for (component in components) { for (component in components) {
storageGraph.add(component) graph.add(component)
} }
} }
} }
fun get(): LazyOptional<IStorageGraphNode> { fun discover(blockEntity: BlockEntity) {
return if (valid) resolver else LazyOptional.empty() discover(blockEntity, MatteryCapability.STORAGE_NODE)
}
fun destroy(level: Level?) {
if (level != null) {
storageNode.destroy { StorageNetworkGraph(level) }
} else {
storageGraph?.removeNode(storageNode)
}
} }
} }

View File

@ -45,8 +45,8 @@ class MatterBottlerMenu @JvmOverloads constructor(
storageSlots = immutableList(6) { index -> storageSlots = immutableList(6) { index ->
object : MatterySlot(container, index) { object : MatterySlot(container, index) {
override fun mayPlace(p_40231_: ItemStack): Boolean { override fun mayPlace(itemStack: ItemStack): Boolean {
val cap = p_40231_.getCapability(MatteryCapability.MATTER).orNull() ?: return false val cap = itemStack.getCapability(MatteryCapability.MATTER).orNull() ?: return false
if (workFlow.value) { if (workFlow.value) {
return index < 3 && cap.canReceiveMatter return index < 3 && cap.canReceiveMatter

View File

@ -29,9 +29,9 @@ class MatterCapacitorBankMenu @JvmOverloads constructor(
} else { } else {
matterGauge = LevelGaugeWidget(this, tile) matterGauge = LevelGaugeWidget(this, tile)
totalMatterGauge = LevelGaugeWidget(this, { totalMatterGauge = LevelGaugeWidget(this, {
tile.matterGraph?.getMatterStorageLevel() ?: Decimal.ZERO tile.matterNode.graph.getMatterStorageLevel()
}, { }, {
tile.matterGraph?.getMatterStorageMaxLevel() ?: Decimal.ZERO tile.matterNode.graph.getMatterStorageMaxLevel()
}) })
} }

View File

@ -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.ItemSorter
import ru.dbotthepony.mc.otm.core.util.codec import ru.dbotthepony.mc.otm.core.util.codec
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener 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.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.network.*
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
@ -176,7 +176,7 @@ class MatterPanelMenu @JvmOverloads constructor(
}) })
val totalMatterStored: Decimal by mSynchronizer.ComputedField( val totalMatterStored: Decimal by mSynchronizer.ComputedField(
getter = { tile?.matterGraph?.getMatterStorageLevel() ?: Decimal.ZERO }, getter = { tile?.matterNode?.graph?.getMatterStorageLevel() ?: Decimal.ZERO },
codec = DecimalValueCodec, codec = DecimalValueCodec,
) )
@ -278,8 +278,7 @@ class MatterPanelMenu @JvmOverloads constructor(
val tile = tile as MatterPanelBlockEntity? ?: return val tile = tile as MatterPanelBlockEntity? ?: return
val graph = tile.matterGraph ?: return val state = tile.matterNode.graph.getPattern(id)
val state = graph.getPattern(id)
if (state == null) { if (state == null) {
LOGGER.error("Received replication request from {} of {}, but it is not found in grid", ply, id) 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 initialSend = false
private var listeningGrid: MatterGraph? = null
private var listeningGrid: MatterNetworkGraph? = null
init { init {
if (tile != null) { if (tile != null) {
listeningGrid = tile.matterGraph listeningGrid = tile.matterNode.graph
tile.attachMenu(this) tile.attachMenu(this)
listeningGrid?.addListener(this) listeningGrid!!.addListener(this)
} }
} }
@ -347,13 +345,9 @@ class MatterPanelMenu @JvmOverloads constructor(
val tile = tile as MatterPanelBlockEntity? val tile = tile as MatterPanelBlockEntity?
if (tile != null) { if (tile != null) {
val grid = tile.matterGraph val grid = tile.matterNode.graph
if (grid != null) {
initialSend = true initialSend = true
sendNetwork(PatternsChangePacket(true, grid.patterns.toList())) sendNetwork(PatternsChangePacket(true, grid.patterns.toList()))
}
sendNetwork(TasksChangePacket(true, tile.allReplicationTasks.toList())) sendNetwork(TasksChangePacket(true, tile.allReplicationTasks.toList()))
} }
} }

View File

@ -1,9 +1,7 @@
package ru.dbotthepony.mc.otm.menu.matter package ru.dbotthepony.mc.otm.menu.matter
import com.google.common.collect.ImmutableList
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity
import ru.dbotthepony.mc.otm.item.MatterDustItem import ru.dbotthepony.mc.otm.item.MatterDustItem
@ -26,8 +24,8 @@ class MatterRecyclerMenu @JvmOverloads constructor(
val container = tile?.container ?: SimpleContainer(1) val container = tile?.container ?: SimpleContainer(1)
input = object : MatterySlot(container, 0) { input = object : MatterySlot(container, 0) {
override fun mayPlace(p_40231_: ItemStack): Boolean { override fun mayPlace(itemStack: ItemStack): Boolean {
return p_40231_.item is MatterDustItem && (p_40231_.item as MatterDustItem).getMatterValue(p_40231_) != null return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null
} }
} }

View File

@ -36,8 +36,8 @@ class MatterScannerMenu @JvmOverloads constructor(
if (tile != null) { if (tile != null) {
progress = ProgressGaugeWidget(this, tile::workProgress, tile::isUnableToProcess) progress = ProgressGaugeWidget(this, tile::workProgress, tile::isUnableToProcess)
patterns = LevelGaugeWidget(this, patterns = LevelGaugeWidget(this,
{ Decimal(tile.matterGraph?.patternCount ?: 0L) }, { Decimal(tile.matterNode.graph.patternCount) },
{ Decimal(tile.matterGraph?.patternCapacity ?: 0L) }) { Decimal(tile.matterNode.graph.patternCapacity) })
} else { } else {
progress = ProgressGaugeWidget(this) progress = ProgressGaugeWidget(this)
patterns = LevelGaugeWidget(this) patterns = LevelGaugeWidget(this)

View File

@ -29,9 +29,9 @@ class PatternStorageMenu @JvmOverloads constructor(
} else { } else {
storedThis = LevelGaugeWidget(this, tile) storedThis = LevelGaugeWidget(this, tile)
storedGrid = LevelGaugeWidget(this, { storedGrid = LevelGaugeWidget(this, {
Decimal(tile.matterGraph?.patternCount ?: 0) Decimal(tile.matterNode.graph.patternCount)
}, { }, {
Decimal(tile.matterGraph?.patternCapacity ?: 0) Decimal(tile.matterNode.graph.patternCapacity)
}) })
} }

View File

@ -22,7 +22,7 @@ class StoragePowerSupplierMenu @JvmOverloads constructor(
override fun broadcastChanges() { override fun broadcastChanges() {
if (tile is StoragePowerSupplierBlockEntity) { if (tile is StoragePowerSupplierBlockEntity) {
totalTransferred = tile.powerPassed totalTransferred = tile.powerPassed
activeNodes = tile.cell.storageGraph?.powerDemandingNodes?.size ?: 0 activeNodes = tile.cell.graph.powerDemandingNodes.size
} }
super.broadcastChanges() super.broadcastChanges()