Storage power supplier block

This commit is contained in:
DBotThePony 2022-05-10 21:43:53 +07:00
parent 45f63d4702
commit ba17a812e3
Signed by: DBot
GPG Key ID: DCC23B5715498507
14 changed files with 504 additions and 249 deletions

View File

@ -360,6 +360,9 @@ object DataGen {
tile(MBlocks.BATTERY_BANK, TileNbtCopy("container"))
tile(MBlocks.DRIVE_VIEWER, TileNbtCopy("energy"), TileNbtCopy("container"), TileNbtCopy("battery_container"))
tile(MBlocks.STORAGE_BUS, TileNbtCopy("energy"), TileNbtCopy("battery_container"))
tile(MBlocks.STORAGE_POWER_SUPPLIER, TileNbtCopy("energy"), TileNbtCopy("battery_container"), TileNbtCopy("power_supplied"))
tile(MBlocks.MATTER_DECOMPOSER, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags)
tile(MBlocks.MATTER_REPLICATOR, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags)
tile(MBlocks.MATTER_RECYCLER, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags)

View File

@ -0,0 +1,28 @@
package ru.dbotthepony.mc.otm.block
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.StoragePowerSupplierBlockEntity
import ru.dbotthepony.mc.otm.registry.MBlockEntities
class StoragePowerSupplierBlock : RotatableMatteryBlock(), EntityBlock {
override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity {
return StoragePowerSupplierBlockEntity(p_153215_, p_153216_)
}
override fun <T : BlockEntity?> getTicker(
p_153212_: Level,
p_153213_: BlockState,
p_153214_: BlockEntityType<T>
): BlockEntityTicker<T>? {
if (p_153212_.isClientSide || p_153214_ !== MBlockEntities.STORAGE_POWER_SUPPLIER)
return null
return BlockEntityTicker { _, _, _, tile -> if (tile is StoragePowerSupplierBlockEntity) tile.tick() }
}
}

View File

@ -49,7 +49,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
}
}
val cell = BasicStorageGraphNode()
val cell = BasicStorageGraphNode(energy)
override fun load(nbt: CompoundTag) {
super.load(nbt)
@ -73,6 +73,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
fun tick() {
batteryChargeLoop()
cell.tickEnergyDemanding()
}
override val defaultDisplayName: Component

View File

@ -22,11 +22,12 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities
class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryPoweredBlockEntity(MBlockEntities.ITEM_MONITOR, p_155229_, p_155230_) {
val cell = BasicStorageGraphNode()
override val energy = WorkerEnergyStorage(this)
val cell = BasicStorageGraphNode(energy)
fun tick() {
batteryChargeLoop()
cell.tickEnergyDemanding()
}
override val defaultDisplayName: Component

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.network.chat.Component
@ -50,248 +49,6 @@ private fun Long.clamp(): Int {
return this.toInt()
}
private class ItemHandlerComponent(private val parent: IItemHandler) : IStorageComponent<ItemStackWrapper> {
override val storageType: StorageStackType<ItemStackWrapper>
get() = OverdriveThatMatters.INSTANCE.ITEM_STORAGE()
private val listeners = ArrayList<IStorageListener<ItemStackWrapper>>()
override fun addListener(listener: IStorageListener<ItemStackWrapper>): Boolean {
if (!listeners.contains(listener)) {
listeners.add(listener)
return true
}
return false
}
override fun removeListener(listener: IStorageListener<ItemStackWrapper>): Boolean {
return listeners.remove(listener)
}
private var scanned = arrayOfNulls<ItemStack>(0)
private var scannedMap = arrayOfNulls<TrackedTuple>(0)
private val tuples = HashMap<ItemStackWrapper, TrackedTuple>()
private val index = HashMap<UUID, TrackedTuple>()
private fun removeTracked(slot: Int) {
scanned[slot] = null
val scannedMap = checkNotNull(scannedMap[slot]) { "Not tracking slot $slot" }
this.scannedMap[slot] = null
val item = scannedMap.children[slot] ?: throw IllegalStateException("${scannedMap.id} does not track $slot")
scannedMap.children.remove(slot)
val count = scannedMap.stack.count
scannedMap.stack.count -= item.stack.count
if (scannedMap.stack.count.isPositive) {
for (listener in listeners) {
listener.changeStack(scannedMap, count)
}
} else {
for (listener in listeners) {
listener.removeStack(scannedMap)
}
index.remove(scannedMap.id)
val key = scannedMap.stack.key()
tuples.remove(key) ?: throw IllegalStateException("Item tuple is not present for slot $slot at ${scannedMap.stack}")
}
}
private fun diffTracked(slot: Int, diff: Int) {
val scannedMap = checkNotNull(scannedMap[slot]) { "Not tracking slot $slot" }
val item = scannedMap.children[slot] ?: throw IllegalStateException("${scannedMap.id} does not track $slot")
val oldCount = scannedMap.stack.count
item.stack.count += diff
scannedMap.stack.count += diff
for (listener in listeners) {
listener.changeStack(scannedMap.stack, scannedMap.id, oldCount)
}
}
private fun addTracked(slot: Int, stack: ItemStack) {
check(scannedMap[slot] == null) { "Already tracking slot $slot" }
val storageStack = ItemStackWrapper(stack)
val key = storageStack.key()
var tuple: TrackedTuple? = tuples[key]
val added = tuple == null
var oldCount = ImpreciseFraction.ZERO
if (added) {
tuple = TrackedTuple(storageStack, UUID.randomUUID())
index[tuple.id] = tuple
tuples[key] = tuple
} else {
oldCount = tuple!!.stack.count
tuple.stack.count += stack.count
}
tuple.children[slot] = SlotTuple(slot, stack.copy())
scanned[slot] = tuple.children[slot].stack
scannedMap[slot] = tuple
if (added) {
for (listener in listeners) {
listener.addStack(tuple.stack, tuple.id, this)
}
} else {
for (listener in listeners) {
listener.changeStack(tuple.stack, tuple.id, oldCount)
}
}
}
private fun sizeScan() {
if (scanned.size != parent.slots) {
val old = scanned
val oldMap = scannedMap
if (scanned.size < parent.slots) {
// grow
scanned = arrayOfNulls(parent.slots)
scannedMap = arrayOfNulls(parent.slots)
for ((i, item) in old.withIndex()) {
scanned[i] = item
}
for ((i, item) in oldMap.withIndex()) {
scannedMap[i] = item
}
} else {
// shrink
for (i in parent.slots until scanned.size) {
removeTracked(i)
}
scanned = arrayOfNulls(parent.slots)
scannedMap = arrayOfNulls(parent.slots)
for (i in 0 until parent.slots) {
scanned[i] = old[i]
scannedMap[i] = oldMap[i]
}
}
}
}
fun scan(slot: Int) {
val current = parent[slot].let { if (it.isEmpty) null else it }
val last = scanned[slot]
if (current == null && last != null) {
removeTracked(slot)
} else if (current != null && last == null) {
addTracked(slot, current)
} else if (current != null && last != null) {
if (!ItemStack.isSameItemSameTags(current, last)) {
removeTracked(slot)
addTracked(slot, current)
} else if (current.count != last.count) {
diffTracked(slot, current.count - last.count)
}
}
}
fun scan() {
sizeScan()
for (slot in 0 until parent.slots) {
scan(slot)
}
}
override fun insertStack(stack: ItemStackWrapper, simulate: Boolean): ItemStackWrapper {
var leftover = stack.copy()
for (slot in 0 until parent.slots) {
val oldCount = leftover.count
leftover = ItemStackWrapper(parent.insertItem(slot, leftover.stack, simulate))
if (oldCount != leftover.count && !simulate) {
scan(slot)
}
if (leftover.isEmpty) {
break
}
}
return leftover
}
override fun getStack(id: UUID): ItemStackWrapper {
return index[id]?.stack ?: ItemStackWrapper.EMPTY
}
override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): ItemStackWrapper {
@Suppress("NAME_SHADOWING")
val amount = amount.floor()
if (!amount.isPositive)
return ItemStackWrapper.EMPTY
val intAmount = amount.toLong()
val tuple = index[id] ?: return ItemStackWrapper.EMPTY
var totalExtracted = 0L
val iter = tuple.children.values.iterator()
val listCopy = Array(tuple.children.values.size) {
iter.next()
}
val copy = tuple.stack.copy()
for (stack in listCopy) {
val extracted = parent.extractItem(stack.slot, stack.stack.count.coerceAtMost((intAmount - totalExtracted).clamp()), true)
if (extracted.isEmpty) {
// dummy condition
continue
} else if (tuple.stack.sameItem(extracted)) {
if (!simulate) {
parent.extractItem(stack.slot, stack.stack.count.coerceAtMost((intAmount - totalExtracted).clamp()), false)
}
totalExtracted += extracted.count
if (extracted.count != 0 && !simulate) {
scan(stack.slot)
}
if (totalExtracted >= intAmount) {
break
}
} else {
// O SHI~
scan(stack.slot)
}
}
if (totalExtracted == 0L) {
return ItemStackWrapper.EMPTY
}
copy.count = ImpreciseFraction(totalExtracted)
return copy
}
override fun getStacks(): Collection<IStorageTuple<ItemStackWrapper>> {
val listing = ArrayList<IStorageTuple<ItemStackWrapper>>(index.size)
for (tuple in index.values) {
listing.add(StorageTuple(tuple.id, tuple.stack))
}
return listing
}
}
class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_BUS, blockPos, blockState) {
override val defaultDisplayName: Component
get() = MACHINE_NAME
@ -302,7 +59,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
override val energy = WorkerEnergyStorage(this)
val cell = BasicStorageGraphNode()
val cell = BasicStorageGraphNode(energy)
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
@ -314,8 +71,10 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
tickOnceServer(this::checkSurroundings)
}
private var valid = true
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
return if (cap === MatteryCapability.STORAGE_NODE) {
return if (valid && cap === MatteryCapability.STORAGE_NODE) {
cell.get().cast()
} else super.getCapability(cap, side)
}
@ -323,23 +82,28 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
override fun invalidateCaps() {
super.invalidateCaps()
cell.invalidate()
valid = false
}
override fun reviveCaps() {
super.reviveCaps()
cell.revive()
valid = true
}
private var neighbour: LazyOptional<IItemHandler>? = null
private var component: ItemHandlerComponent? = null
fun tick() {
batteryChargeLoop()
component?.scan()
cell.tickEnergyDemanding()
}
override fun setRemoved() {
super.setRemoved()
cell.destroy(level)
valid = false
}
fun checkSurroundings() {
@ -376,4 +140,269 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
companion object {
private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_BUS}")
}
private inner class ItemHandlerComponent(private val parent: IItemHandler) : IStorageComponent<ItemStackWrapper> {
override val storageType: StorageStackType<ItemStackWrapper>
get() = OverdriveThatMatters.INSTANCE.ITEM_STORAGE()
private val listeners = ArrayList<IStorageListener<ItemStackWrapper>>()
override fun addListener(listener: IStorageListener<ItemStackWrapper>): Boolean {
if (!listeners.contains(listener)) {
listeners.add(listener)
return true
}
return false
}
override fun removeListener(listener: IStorageListener<ItemStackWrapper>): Boolean {
return listeners.remove(listener)
}
private var scanned = arrayOfNulls<ItemStack>(0)
private var scannedMap = arrayOfNulls<TrackedTuple>(0)
private val tuples = HashMap<ItemStackWrapper, TrackedTuple>()
private val index = HashMap<UUID, TrackedTuple>()
private fun removeTracked(slot: Int) {
scanned[slot] = null
val scannedMap = checkNotNull(scannedMap[slot]) { "Not tracking slot $slot" }
this.scannedMap[slot] = null
val item = scannedMap.children[slot] ?: throw IllegalStateException("${scannedMap.id} does not track $slot")
scannedMap.children.remove(slot)
val count = scannedMap.stack.count
scannedMap.stack.count -= item.stack.count
if (scannedMap.stack.count.isPositive) {
for (listener in listeners) {
listener.changeStack(scannedMap, count)
}
} else {
for (listener in listeners) {
listener.removeStack(scannedMap)
}
index.remove(scannedMap.id)
val key = scannedMap.stack.key()
tuples.remove(key) ?: throw IllegalStateException("Item tuple is not present for slot $slot at ${scannedMap.stack}")
}
}
private fun diffTracked(slot: Int, diff: Int) {
val scannedMap = checkNotNull(scannedMap[slot]) { "Not tracking slot $slot" }
val item = scannedMap.children[slot] ?: throw IllegalStateException("${scannedMap.id} does not track $slot")
val oldCount = scannedMap.stack.count
item.stack.count += diff
scannedMap.stack.count += diff
for (listener in listeners) {
listener.changeStack(scannedMap.stack, scannedMap.id, oldCount)
}
}
private fun addTracked(slot: Int, stack: ItemStack) {
check(scannedMap[slot] == null) { "Already tracking slot $slot" }
val storageStack = ItemStackWrapper(stack)
val key = storageStack.key()
var tuple: TrackedTuple? = tuples[key]
val added = tuple == null
var oldCount = ImpreciseFraction.ZERO
if (added) {
tuple = TrackedTuple(storageStack, UUID.randomUUID())
index[tuple.id] = tuple
tuples[key] = tuple
} else {
oldCount = tuple!!.stack.count
tuple.stack.count += stack.count
}
tuple.children[slot] = SlotTuple(slot, stack.copy())
scanned[slot] = tuple.children[slot].stack
scannedMap[slot] = tuple
if (added) {
for (listener in listeners) {
listener.addStack(tuple.stack, tuple.id, this)
}
} else {
for (listener in listeners) {
listener.changeStack(tuple.stack, tuple.id, oldCount)
}
}
}
private fun sizeScan() {
if (scanned.size != parent.slots) {
val old = scanned
val oldMap = scannedMap
if (scanned.size < parent.slots) {
// grow
scanned = arrayOfNulls(parent.slots)
scannedMap = arrayOfNulls(parent.slots)
for ((i, item) in old.withIndex()) {
scanned[i] = item
}
for ((i, item) in oldMap.withIndex()) {
scannedMap[i] = item
}
} else {
// shrink
for (i in parent.slots until scanned.size) {
removeTracked(i)
}
scanned = arrayOfNulls(parent.slots)
scannedMap = arrayOfNulls(parent.slots)
for (i in 0 until parent.slots) {
scanned[i] = old[i]
scannedMap[i] = oldMap[i]
}
}
}
}
fun scan(slot: Int) {
val current = parent[slot].let { if (it.isEmpty) null else it }
val last = scanned[slot]
if (current == null && last != null) {
removeTracked(slot)
} else if (current != null && last == null) {
addTracked(slot, current)
} else if (current != null && last != null) {
if (!ItemStack.isSameItemSameTags(current, last)) {
removeTracked(slot)
addTracked(slot, current)
} else if (current.count != last.count) {
diffTracked(slot, current.count - last.count)
}
}
}
fun scan() {
sizeScan()
for (slot in 0 until parent.slots) {
scan(slot)
}
}
override fun insertStack(stack: ItemStackWrapper, simulate: Boolean): ItemStackWrapper {
if (energy.batteryLevel.isZero)
return stack
val maxPossibleDemand = stack.count * OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation
val maxExtractEnergy = energy.extractEnergyInner(maxPossibleDemand, true)
var leftover: ItemStackWrapper
if (maxExtractEnergy == maxPossibleDemand) {
leftover = stack.copy()
} else {
leftover = stack.copy().also {
it.count = (maxExtractEnergy / OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation).floor()
}
}
for (slot in 0 until parent.slots) {
val oldCount = leftover.count
leftover = ItemStackWrapper(parent.insertItem(slot, leftover.stack, simulate))
if (oldCount != leftover.count && !simulate) {
energy.extractEnergyInner((oldCount - leftover.count) * OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation, false)
scan(slot)
}
if (leftover.isEmpty) {
break
}
}
return leftover
}
override fun getStack(id: UUID): ItemStackWrapper {
return index[id]?.stack ?: ItemStackWrapper.EMPTY
}
override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): ItemStackWrapper {
@Suppress("NAME_SHADOWING")
var amount = amount.floor()
if (!amount.isPositive)
return ItemStackWrapper.EMPTY
val maxPossibleDemand = amount * OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation
val maxExtractEnergy = energy.extractEnergyInner(maxPossibleDemand, true)
if (maxPossibleDemand != maxExtractEnergy) {
amount = (maxExtractEnergy / OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation).floor()
}
val intAmount = amount.toLong()
val tuple = index[id] ?: return ItemStackWrapper.EMPTY
var totalExtracted = 0L
val iter = tuple.children.values.iterator()
val listCopy = Array(tuple.children.values.size) {
iter.next()
}
val copy = tuple.stack.copy()
for (stack in listCopy) {
val extracted = parent.extractItem(stack.slot, stack.stack.count.coerceAtMost((intAmount - totalExtracted).clamp()), true)
if (extracted.isEmpty) {
// dummy condition
continue
} else if (tuple.stack.sameItem(extracted)) {
if (!simulate) {
parent.extractItem(stack.slot, extracted.count, false)
}
totalExtracted += extracted.count
if (extracted.count != 0 && !simulate) {
scan(stack.slot)
energy.extractEnergyInner(OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation * extracted.count, false)
}
if (totalExtracted >= intAmount) {
break
}
} else {
// O SHI~
scan(stack.slot)
}
}
if (totalExtracted == 0L) {
return ItemStackWrapper.EMPTY
}
copy.count = ImpreciseFraction(totalExtracted)
return copy
}
override fun getStacks(): Collection<IStorageTuple<ItemStackWrapper>> {
val listing = ArrayList<IStorageTuple<ItemStackWrapper>>(index.size)
for (tuple in index.values) {
listing.add(StorageTuple(tuple.id, tuple.stack))
}
return listing
}
}
}

View File

@ -0,0 +1,130 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.Level
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.OverdriveThatMatters
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.set
class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_POWER_SUPPLIER, blockPos, blockState) {
override val defaultDisplayName: Component
get() = MACHINE_NAME
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
return null
}
val cell = BasicStorageGraphNode()
var powerSupplied = ImpreciseFraction.ZERO
private set
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode)
}
}
private var valid = true
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
return if (valid && cap === MatteryCapability.STORAGE_NODE) {
cell.get().cast()
} else super.getCapability(cap, side)
}
override fun invalidateCaps() {
super.invalidateCaps()
cell.invalidate()
valid = false
}
override fun reviveCaps() {
super.reviveCaps()
cell.revive()
valid = true
}
override fun setRemoved() {
super.setRemoved()
cell.destroy(level)
valid = false
}
fun tick() {
batteryChargeLoop()
if (energy.batteryLevel.isZero)
return
val graph = cell.storageGraph ?: return
if (graph.powerDemandingNodes.isEmpty())
return
var demand = ImpreciseFraction.ZERO
var i = 0
val available = energy.batteryLevel.coerceAtMost(MAX_IO)
for (demanding in graph.powerDemandingNodes) {
val received = demanding.receiveEnergyOuter(available, true)
if (received.isPositive) {
demand += received
i++
}
}
if (demand.isZero) {
return
} else if (demand < available) {
for (demanding in graph.powerDemandingNodes) {
powerSupplied += energy.transferInner(demanding, available, false)
}
} else {
val forEach = available / i
for (demanding in graph.powerDemandingNodes) {
powerSupplied += energy.transferInner(demanding, forEach, false)
}
}
}
override val energy = WorkerEnergyStorage(this, MAX_POWER, MAX_IO)
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
nbt["power_supplied"] = powerSupplied.serializeNBT()
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt["power_supplied"]?.let { powerSupplied = ImpreciseFraction.deserializeNBT(it) }
}
companion object {
private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_POWER_SUPPLIER}")
private val MAX_POWER = ImpreciseFraction(100_000)
private val MAX_IO = ImpreciseFraction(320)
}
}

View File

@ -179,4 +179,30 @@ interface IMatteryEnergyStorage : IEnergyStorage {
override fun canReceive(): Boolean {
return receiveEnergyOuter(ImpreciseFraction.ONE, true) > ImpreciseFraction.ZERO
}
}
fun transferInner(other: IMatteryEnergyStorage, amount: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
if (!amount.isPositive)
return ImpreciseFraction.ZERO
val extracted = extractEnergyInner(amount, true)
val received = other.receiveEnergyOuter(extracted, simulate)
if (!simulate)
extractEnergyInner(received, false)
return received
}
fun transferOuter(other: IMatteryEnergyStorage, amount: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
if (!amount.isPositive)
return ImpreciseFraction.ZERO
val extracted = extractEnergyOuter(amount, true)
val received = other.receiveEnergyOuter(extracted, simulate)
if (!simulate)
extractEnergyInner(received, false)
return received
}
}

View File

@ -2,13 +2,14 @@ package ru.dbotthepony.mc.otm.graph.storage
import net.minecraft.world.level.Level
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.storage.IStorage
import ru.dbotthepony.mc.otm.storage.IStorageStack
import ru.dbotthepony.mc.otm.storage.StorageStackType
import java.util.*
open class BasicStorageGraphNode : IStorageGraphNode {
open class BasicStorageGraphNode(private val energyDemander: IMatteryEnergyStorage? = null) : IStorageGraphNode {
private var resolver = LazyOptional.of<IStorageGraphNode> { this }
private var valid = true
protected val components = ArrayList<IStorage<*>>()
@ -25,7 +26,16 @@ open class BasicStorageGraphNode : IStorageGraphNode {
@Suppress("LeakingThis")
final override val storageNode = Graph6Node<IStorageGraphNode>(this)
private var demandingEnergy = false
override fun attachComponents(to: StorageNetworkGraph) {
if (energyDemander != null) {
if (!demandingEnergy && energyDemander.missingPower.isPositive) {
demandingEnergy = true
to.powerDemandingNodes.add(energyDemander)
}
}
if (manualAttaching) {
return
}
@ -35,10 +45,27 @@ open class BasicStorageGraphNode : IStorageGraphNode {
}
}
fun tickEnergyDemanding() {
energyDemander ?: throw IllegalStateException("No energy demander")
if (!demandingEnergy && storageGraph != null && energyDemander.missingPower.isPositive) {
demandingEnergy = true
storageGraph!!.powerDemandingNodes.add(energyDemander)
} else if (demandingEnergy && storageGraph != null && !energyDemander.missingPower.isPositive) {
demandingEnergy = false
storageGraph!!.powerDemandingNodes.remove(energyDemander)
}
}
override fun removeComponents(from: StorageNetworkGraph) {
for (component in components) {
from.remove(component)
}
if (energyDemander != null) {
from.powerDemandingNodes.remove(energyDemander)
demandingEnergy = false
}
}
@Suppress("unchecked_cast")

View File

@ -7,11 +7,13 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity
import ru.dbotthepony.mc.otm.addPreServerTicker
import ru.dbotthepony.mc.otm.addPreWorldTicker
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.graph.Abstract6Graph
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.orNull
import ru.dbotthepony.mc.otm.storage.*
import java.util.LinkedList
class StorageNetworkGraph(private val level: Level) : Abstract6Graph<IStorageGraphNode>() {
private val virtualComponents = Object2ObjectArrayMap<StorageStackType<*>, VirtualComponent<*>>()
@ -58,6 +60,8 @@ class StorageNetworkGraph(private val level: Level) : Abstract6Graph<IStorageGra
node.value.removeComponents(this)
}
val powerDemandingNodes = LinkedList<IMatteryEnergyStorage>()
companion object {
@JvmStatic
fun discoverFull(tile: BlockEntity, node: Graph6Node<IStorageGraphNode>) {

View File

@ -40,6 +40,7 @@ object MBlockEntities {
val MATTER_RECYCLER: BlockEntityType<*> by registry.register(MNames.MATTER_RECYCLER) { BlockEntityType.Builder.of(::MatterRecyclerBlockEntity, MBlocks.MATTER_RECYCLER).build(null) }
val STORAGE_BUS: BlockEntityType<*> by registry.register(MNames.STORAGE_BUS) { BlockEntityType.Builder.of(::StorageBusBlockEntity, MBlocks.STORAGE_BUS).build(null) }
val STORAGE_POWER_SUPPLIER: BlockEntityType<*> by registry.register(MNames.STORAGE_POWER_SUPPLIER) { BlockEntityType.Builder.of(::StoragePowerSupplierBlockEntity, MBlocks.STORAGE_POWER_SUPPLIER).build(null) }
val DEBUG_EXPLOSION_SMALL: BlockEntityType<*> by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockEntityType.Builder.of(::BlockEntityExplosionDebugger, MBlocks.DEBUG_EXPLOSION_SMALL).build(null) }
val DEBUG_SPHERE_POINTS: BlockEntityType<*> by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockEntityType.Builder.of(::BlockEntitySphereDebugger, MBlocks.DEBUG_SPHERE_POINTS).build(null) }

View File

@ -57,6 +57,7 @@ object MBlocks {
val DRIVE_RACK: Block by registry.register(MNames.DRIVE_RACK) { DriveRackBlock() }
val ITEM_MONITOR: Block by registry.register(MNames.ITEM_MONITOR) { ItemMonitorBlock() }
val STORAGE_CABLE: Block by registry.register(MNames.STORAGE_CABLE) { StorageCableBlock() }
val STORAGE_POWER_SUPPLIER: Block by registry.register(MNames.STORAGE_POWER_SUPPLIER) { StoragePowerSupplierBlock() }
val DEBUG_EXPLOSION_SMALL: Block by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockExplosionDebugger() }
val DEBUG_SPHERE_POINTS: Block by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockSphereDebugger() }

View File

@ -51,6 +51,7 @@ object MItems {
val DRIVE_RACK: Item by registry.register(MNames.DRIVE_RACK) { BlockItem(MBlocks.DRIVE_RACK, DEFAULT_PROPERTIES) }
val ITEM_MONITOR: Item by registry.register(MNames.ITEM_MONITOR) { BlockItem(MBlocks.ITEM_MONITOR, DEFAULT_PROPERTIES) }
val STORAGE_CABLE: Item by registry.register(MNames.STORAGE_CABLE) { BlockItem(MBlocks.STORAGE_CABLE, DEFAULT_PROPERTIES) }
val STORAGE_POWER_SUPPLIER: Item by registry.register(MNames.STORAGE_POWER_SUPPLIER) { BlockItem(MBlocks.STORAGE_POWER_SUPPLIER, DEFAULT_PROPERTIES) }
val GRAVITATION_STABILIZER: Item by registry.register(MNames.GRAVITATION_STABILIZER) {
object : BlockItem(MBlocks.GRAVITATION_STABILIZER, DEFAULT_PROPERTIES) {

View File

@ -24,6 +24,7 @@ object MNames {
const val MATTER_RECYCLER = "matter_recycler" // нужен рецепт
const val STORAGE_CABLE = "storage_cable" // нужен рецепт
const val STORAGE_POWER_SUPPLIER = "storage_power_supplier" // нужен рецепт
const val DEBUG_EXPLOSION_SMALL = "debug_explosion_small"
const val DEBUG_SPHERE_POINTS = "debug_sphere_points"

View File

@ -236,6 +236,8 @@
"block.overdrive_that_matters.tritanium_raw_block": "Raw Tritanium Block",
"block.overdrive_that_matters.storage_cable": "Storage Cable",
"block.overdrive_that_matters.storage_power_supplier": "Storage Power Supplier",
"block.overdrive_that_matters.storage_bus": "Storage Bus",
"item.overdrive_that_matters.pill_android": "Android Pill",
"item.overdrive_that_matters.pill_humane": "Humane Pill",