Storage power supplier block
This commit is contained in:
parent
45f63d4702
commit
ba17a812e3
@ -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)
|
||||
|
@ -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() }
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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>) {
|
||||
|
@ -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) }
|
||||
|
@ -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() }
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user