Storage bus test, storage api improvements

This commit is contained in:
DBotThePony 2022-03-21 19:57:09 +07:00
parent e5b419f78f
commit d4aa8cd7ee
Signed by: DBot
GPG Key ID: DCC23B5715498507
18 changed files with 546 additions and 29 deletions

View File

@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode;
import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode;
import ru.dbotthepony.mc.otm.storage.IStorageStack;
public class MatteryCapability {
public static final Capability<IMatteryEnergyStorage> ENERGY = CapabilityManager.get(new CapabilityToken<>() {});
@ -17,7 +18,7 @@ public class MatteryCapability {
public static final Capability<IMatterGraphNode> MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IPatternStorage> PATTERN = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatteryDrive> DRIVE = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatteryDrive<IStorageStack>> DRIVE = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IStorageGraphNode> STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IStrictEnergyHandler> MEKANISM_ENERGY = CapabilityManager.get(new CapabilityToken<>() {});

View File

@ -21,6 +21,7 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.CapabilityEnergy
import net.minecraftforge.items.IItemHandler
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import java.util.*
import java.util.function.Consumer
@ -112,6 +113,7 @@ val CompoundTag.uuids get() = CompoundTagUUID(this)
operator fun Container.set(index: Int, value: ItemStack) = setItem(index, value)
operator fun Container.get(index: Int): ItemStack = getItem(index)
operator fun IItemHandler.get(index: Int): ItemStack = getStackInSlot(index)
operator fun JsonObject.set(s: String, value: JsonElement) = add(s, value)

View File

@ -51,7 +51,7 @@ class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock {
) {
super.neighborChanged(state, level, pos, sender, sender_pos, flag)
if (!level.isClientSide && level is ServerLevel) {
if (!level.isClientSide) {
val tile = level.getBlockEntity(pos)
if (tile is ChemicalGeneratorBlockEntity) {

View File

@ -0,0 +1,60 @@
package ru.dbotthepony.mc.otm.block
import net.minecraft.core.BlockPos
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
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.ChemicalGeneratorBlockEntity
import ru.dbotthepony.mc.otm.block.entity.StorageBusBlockEntity
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.tickOnceServer
import ru.dbotthepony.mc.otm.unaryMinus
class StorageBusBlock : RotatableMatteryBlock(), EntityBlock {
override val hasFreeRotation: Boolean get() = true
override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity {
return StorageBusBlockEntity(p_153215_, p_153216_)
}
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
return super.getStateForPlacement(context)?.setValue(FACING_FULL, -context.clickedFace)
}
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_BUS)
return null
return BlockEntityTicker { _, _, _, tile -> if (tile is StorageBusBlockEntity) tile.tick() }
}
override fun neighborChanged(
state: BlockState,
level: Level,
pos: BlockPos,
sender: Block,
sender_pos: BlockPos,
flag: Boolean
) {
super.neighborChanged(state, level, pos, sender, sender_pos, flag)
if (!level.isClientSide) {
val tile = level.getBlockEntity(pos)
if (tile is StorageBusBlockEntity) {
tickOnceServer(level) {
tile.checkSurroundings()
}
}
}
}
}

View File

@ -24,7 +24,10 @@ import ru.dbotthepony.mc.otm.menu.DriveRackMenu
import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.storage.IStorageStack
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import ru.dbotthepony.mc.otm.storage.PoweredVirtualComponent
import ru.dbotthepony.mc.otm.storage.StorageStackType
class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryPoweredBlockEntity(MBlockEntities.DRIVE_RACK, p_155229_, p_155230_) {
@ -36,11 +39,15 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
super.setChanged(slot, new, old)
old.getCapability(MatteryCapability.DRIVE).ifPresent {
cell.computeIfAbsent(it.storageType) {PoweredVirtualComponent(it, energy)}.remove(it)
cell.computeIfAbsent(it.storageType) {
PoweredVirtualComponent(it, energy)
}.remove(it)
}
new.getCapability(MatteryCapability.DRIVE).ifPresent {
cell.computeIfAbsent(it.storageType) {PoweredVirtualComponent(it, energy)}.add(it)
cell.computeIfAbsent(it.storageType) {
PoweredVirtualComponent(it, energy)
}.add(it)
}
}
}

View File

@ -22,7 +22,6 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities
class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryPoweredBlockEntity(MBlockEntities.ITEM_MONITOR, p_155229_, p_155230_) {
@JvmField
val cell = BasicStorageGraphNode()
override val energy = WorkerEnergyStorage(this)

View File

@ -0,0 +1,366 @@
package ru.dbotthepony.mc.otm.block.entity
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
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.item.ItemStack
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 net.minecraftforge.items.CapabilityItemHandler
import net.minecraftforge.items.IItemHandler
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
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.core.plus
import ru.dbotthepony.mc.otm.get
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.orThrow
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.storage.*
import java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.ArrayList
private class SlotTuple(val slot: Int, val stack: ItemStack)
private class TrackedTuple(val stack: ItemStackWrapper, val id: UUID) {
val children = Int2ObjectAVLTreeMap<SlotTuple>()
}
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 partitioned = Long2ObjectAVLTreeMap<ArrayList<TrackedTuple>>()
private val index = Object2ObjectAVLTreeMap<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.stack, scannedMap.id, count)
}
} else {
for (listener in listeners) {
listener.removeStack(scannedMap.stack, scannedMap.id)
}
index.remove(scannedMap.id)
}
}
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 listing = partitioned.computeIfAbsent(ItemStackWrapper.partitionKey(stack.item), Long2ObjectFunction { ArrayList() })
var tuple: TrackedTuple? = null
for (storedTuple in listing) {
if (ItemStack.isSameItemSameTags(stack, storedTuple.stack.stack)) {
tuple = storedTuple
break
}
}
val added = tuple == null
var oldCount = ImpreciseFraction.ZERO
if (added) {
val storageStack = ItemStackWrapper(stack.copy())
tuple = TrackedTuple(storageStack, UUID.randomUUID())
index[tuple.id] = tuple
listing.add(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.toInt()
val tuple = index[id] ?: return ItemStackWrapper.EMPTY
var totalExtracted = 0
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), true)
if (extracted.isEmpty) {
// dummy condition
continue
} else if (ItemStack.isSameItemSameTags(extracted, tuple.stack.stack)) {
if (!simulate) {
parent.extractItem(stack.slot, stack.stack.count.coerceAtMost(intAmount - totalExtracted), false)
}
totalExtracted += extracted.count
if (extracted.count != 0 && !simulate) {
scan(stack.slot)
}
if (totalExtracted >= intAmount) {
break
}
} else {
// O SHI~
scan(stack.slot)
}
}
if (totalExtracted == 0) {
return ItemStackWrapper.EMPTY
}
copy.setCount(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
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
return null
}
override val energy = WorkerEnergyStorage(this)
val cell = BasicStorageGraphNode()
override fun setLevel(p_155231_: Level) {
super.setLevel(p_155231_)
if (p_155231_ is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode)
}
tickOnceServer(this::checkSurroundings)
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
return if (cap === MatteryCapability.STORAGE_NODE) {
cell.get().cast()
} else super.getCapability(cap, side)
}
override fun invalidateCaps() {
super.invalidateCaps()
cell.invalidate()
}
override fun reviveCaps() {
super.reviveCaps()
cell.revive()
}
private var neighbour: LazyOptional<IItemHandler>? = null
private var component: ItemHandlerComponent? = null
fun tick() {
component?.scan()
}
fun checkSurroundings() {
val front = blockPos + blockState.getValue(RotatableMatteryBlock.FACING_FULL)
val storage = level?.getBlockEntity(front)?.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)?.let { if (it.isPresent) it else null }
if (neighbour != storage) {
neighbour = storage
if (storage != null) {
val ref = WeakReference(this)
storage.addListener {
val self = ref.get() ?: return@addListener
if (self.neighbour === it)
self.checkSurroundings()
}
component?.let(cell::removeStorageComponent)
component = ItemHandlerComponent(storage.orThrow())
component!!.let(cell::addStorageComponent)
} else {
component?.let(cell::removeStorageComponent)
component = null
}
}
}
companion object {
private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_BUS}")
}
}

View File

@ -48,11 +48,12 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
for (state in listing) {
if (state.stack.sameItem(stack)) {
if (!simulate) {
val oldCount = state.stack.count
state.stack.grow(maxInsert)
storedCount += maxInsert
for (listener in listeners) {
listener.changeStack(state.id, state.stack.count)
listener.changeStack(state.stack, state.id, oldCount)
}
isDirty = true
@ -115,7 +116,7 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
storedDifferentStacks--
for (listener in listeners) {
listener.removeStack(get.id)
listener.removeStack(get.stack, get.id)
}
if (listing.size == 0) {
@ -123,12 +124,13 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
}
}
storedCount = storedCount.minus(amount)
storedCount -= amount
val oldCount = get.stack.count
get.stack.shrink(amount)
if (!get.stack.count.isZero) {
for (listener in listeners) {
listener.changeStack(get.id, get.stack.count)
listener.changeStack(get.stack, get.id, oldCount)
}
}

View File

@ -327,6 +327,13 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do
return 31 * (decimal - decimal % EPSILON).hashCode() + whole.hashCode()
}
fun floor(): ImpreciseFraction {
if (decimal == 0.0)
return this
return ImpreciseFraction(whole)
}
fun toString(decimals: Int): String {
if (isNaN)
return "NaN"

View File

@ -39,21 +39,79 @@ open class BasicStorageGraphNode : IStorageGraphNode {
}
components.add(component)
if (valid)
storageGraph?.add(component)
}
fun removeStorageComponent(component: IStorage<*>) {
var indexOf = -1
for ((i, component1) in components.withIndex()) {
if (component === component1 || component1.storageType === component.storageType) {
indexOf = i
break
}
}
if (indexOf == -1) {
return
}
val self = components[indexOf]
components.removeAt(indexOf)
if (valid)
storageGraph?.remove(self)
}
fun removeStorageComponent(component: StorageStackType<*>) {
var indexOf = -1
for ((i, component1) in components.withIndex()) {
if (component1.storageType === component) {
indexOf = i
break
}
}
if (indexOf == -1) {
return
}
val self = components[indexOf]
components.removeAt(indexOf)
if (valid)
storageGraph?.remove(self)
}
fun invalidate() {
if (!valid) return
valid = false
resolver.invalidate()
// detachStorage();
val storageGraph = storageGraph
if (storageGraph != null) {
for (component in components) {
storageGraph.remove(component)
}
}
}
fun revive() {
if (valid) return
valid = true
resolver = LazyOptional.of { this }
// attachStorage();
val storageGraph = storageGraph
if (storageGraph != null) {
for (component in components) {
storageGraph.add(component)
}
}
}
fun get(): LazyOptional<IStorageGraphNode> {

View File

@ -78,7 +78,7 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
}
override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageView<ItemStackWrapper>) = addObject(stack.stack, id)
override fun changeStack(id: UUID, newCount: ImpreciseFraction) = changeObject(id, newCount.toInt())
override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: ImpreciseFraction) = changeObject(id, stack.count.toInt())
protected fun network(fn: () -> Any) {
if (!remote) {
@ -86,7 +86,7 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
}
}
override fun removeStack(id: UUID) {
override fun removeStack(stack: ItemStackWrapper, id: UUID) {
val get = upstream_state[id] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id!")
upstream_state.remove(id)
state.remove(get.id)

View File

@ -39,6 +39,8 @@ object MBlockEntities {
val GRAVITATION_STABILIZER: BlockEntityType<*> by registry.register(MNames.GRAVITATION_STABILIZER) { BlockEntityType.Builder.of(::GravitationStabilizerBlockEntity, MBlocks.GRAVITATION_STABILIZER).build(null) }
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 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

@ -55,6 +55,8 @@ object MBlocks {
val PLATE_PRESS: Block by registry.register(MNames.PLATE_PRESS) { PlatePressBlock() }
val MATTER_RECYCLER: Block by registry.register(MNames.MATTER_RECYCLER) { MatterRecyclerBlock() }
val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS) { StorageBusBlock() }
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

@ -48,6 +48,9 @@ object MItems {
val CHEMICAL_GENERATOR: Item by registry.register(MNames.CHEMICAL_GENERATOR) { BlockItem(MBlocks.CHEMICAL_GENERATOR, DEFAULT_PROPERTIES) }
val PLATE_PRESS: Item by registry.register(MNames.PLATE_PRESS) { BlockItem(MBlocks.PLATE_PRESS, DEFAULT_PROPERTIES) }
val MATTER_RECYCLER: Item by registry.register(MNames.MATTER_RECYCLER) { BlockItem(MBlocks.MATTER_RECYCLER, DEFAULT_PROPERTIES) }
val STORAGE_BUS: Item by registry.register(MNames.STORAGE_BUS) { BlockItem(MBlocks.STORAGE_BUS, DEFAULT_PROPERTIES) }
val GRAVITATION_STABILIZER: Item by registry.register(MNames.GRAVITATION_STABILIZER) {
object : BlockItem(MBlocks.GRAVITATION_STABILIZER, DEFAULT_PROPERTIES) {
override fun appendHoverText(

View File

@ -31,6 +31,8 @@ object MNames {
const val GRAVITATION_STABILIZER_LENS = "gravitation_stabilizer_lens"
const val CARGO_CRATE = "cargo_crate" // нужен рецепт?
const val STORAGE_BUS = "storage_bus"
// building blocks
const val TRITANIUM_BLOCK = "tritanium_block"
const val TRITANIUM_STRIPED_BLOCK = "tritanium_striped_block"

View File

@ -92,6 +92,8 @@ interface IStorageView<T : IStorageStack> : IStorageTrigger<T> {
fun getStack(id: UUID): T
/**
* If tuple does not exist, returns empty stack
*
* @param id identifier of stack to extract
* @param amount amount of units to extract
* @param simulate whenever to simulate the action or not
@ -134,7 +136,7 @@ interface IStorageView<T : IStorageStack> : IStorageTrigger<T> {
fun removeListenerAuto(listener: IStorageListener<T>): Boolean {
if (removeListener(listener)) {
for (stack in getStacks()) {
listener.removeStack(stack.id)
listener.removeStack(stack.stack, stack.id)
}
return true
@ -153,12 +155,12 @@ interface IStorageListener<T : IStorageStack> {
/**
* Fired on whenever an object is changes on listener we subscribed to
*/
fun changeStack(id: UUID, newCount: ImpreciseFraction)
fun changeStack(stack: T, id: UUID, oldCount: ImpreciseFraction)
/**
* Fired on whenever an object is removed from listener we subscribed to
*/
fun removeStack(id: UUID)
fun removeStack(stack: T, id: UUID)
}
interface IStorageTuple<T : IStorageStack> {

View File

@ -9,7 +9,7 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
class ItemStackWrapper(val stack: ItemStack) : IStorageStack {
operator fun component1() = stack
override fun copy(): IStorageStack {
override fun copy(): ItemStackWrapper {
return ItemStackWrapper(stack.copy())
}
@ -40,6 +40,6 @@ class ItemStackWrapper(val stack: ItemStack) : IStorageStack {
@JvmField
val EMPTY = ItemStackWrapper(ItemStack.EMPTY)
fun partitionKey(item: Item) = (ForgeRegistries.ITEMS as ForgeRegistry<Item>?)?.getID(item)?.toLong() ?: System.identityHashCode(item).toLong()
fun partitionKey(item: Item) = (ForgeRegistries.ITEMS as? ForgeRegistry<Item>)?.getID(item)?.toLong() ?: System.identityHashCode(item).toLong()
}
}

View File

@ -99,9 +99,11 @@ open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : ISto
check(!remoteByUUID.containsKey(id)) { "Already tracking tuple with id $id" }
val items = partitions.computeIfAbsent(stack.partitionKey, Long2ObjectFunction { ArrayList() })
var local: LocalTuple<T>? = null
var oldCount = ImpreciseFraction.ZERO
for (item in items) {
if (item.stack.sameItem(stack)) {
oldCount = item.stack.count
item.stack.grow(stack.count)
local = item
break
@ -126,25 +128,27 @@ open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : ISto
}
} else {
for (listener in listeners) {
listener.changeStack(local.id, local.stack.count)
listener.changeStack(local.stack, local.id, oldCount)
}
}
}
override fun changeStack(id: UUID, newCount: ImpreciseFraction) {
assert(newCount > ImpreciseFraction.ZERO)
override fun changeStack(stack: T, id: UUID, oldCount: ImpreciseFraction) {
require(stack.count.isPositive)
val tuple = remoteByUUID[id] ?: throw IllegalStateException("No such tuple with id $id")
val diff = newCount - tuple.obj.count
tuple.obj.count = newCount
val diff = stack.count - tuple.obj.count
tuple.obj.count = stack.count
@Suppress("NAME_SHADOWING") val oldCount = tuple.local.stack.count
tuple.local.stack.grow(diff)
for (listener in listeners) {
listener.changeStack(tuple.local.id, tuple.local.stack.count)
listener.changeStack(tuple.local.stack, tuple.local.id, oldCount)
}
}
override fun removeStack(id: UUID) {
override fun removeStack(stack: T, id: UUID) {
val tuple = remoteByUUID[id] ?: throw IllegalStateException("No such tuple with id $id")
val key = tuple.local.stack.partitionKey
@ -162,7 +166,7 @@ open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : ISto
partitions[key]!!.remove(tuple.local)
for (listener in listeners) {
listener.removeStack(tuple.local.id)
listener.removeStack(tuple.local.stack, tuple.local.id)
}
}
}
@ -200,7 +204,7 @@ open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : ISto
var extracted = ImpreciseFraction.ZERO
val copy = tuple.stack.copy() as T
for (remote_tuple in tuple.tuples) {
for (remote_tuple in tuple.tuples.let { Array(it.size) { i -> it[i] } }) {
extracted += remote_tuple.extractCount(toExtract - extracted, simulate)
if (extracted >= toExtract)
@ -219,7 +223,7 @@ open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : ISto
open class PoweredVirtualComponent<T : IStorageStack>(type: StorageStackType<T>, val energyProvider: () -> IMatteryEnergyStorage) : VirtualComponent<T>(type) {
constructor(type: Class<T>, energyStorage: IMatteryEnergyStorage) : this(StorageRegistry.get(type), {energyStorage})
constructor(type: StorageStackType<T>, energyStorage: IMatteryEnergyStorage) : this(type, {energyStorage})
constructor(other: VirtualComponent<T>, energyStorage: IMatteryEnergyStorage) : this(other.storageType.identity, energyStorage) {
constructor(other: IStorage<T>, energyStorage: IMatteryEnergyStorage) : this(other.storageType.identity, energyStorage) {
add(other)
}