diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index 084f2b459..628672e74 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -103,7 +103,7 @@ public final class OverdriveThatMatters { private void setup(final FMLCommonSetupEvent event) { MatteryNetworking.register(); - ITEM_STORAGE = StorageRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125"), false); + ITEM_STORAGE = StorageRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125")); if (ModList.get().isLoaded("mekanism")) { MinecraftForge.EVENT_BUS.register(QIOKt.class); diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt index 153b8ef01..e256fb9d2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageBusBlockEntity.kt @@ -4,7 +4,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap import net.minecraft.core.BlockPos import net.minecraft.core.Direction import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag import net.minecraft.network.chat.Component import net.minecraft.network.chat.TranslatableComponent import net.minecraft.server.level.ServerLevel @@ -26,6 +25,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.isPositive import ru.dbotthepony.mc.otm.core.plus import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.GraphNodeListener @@ -36,7 +36,9 @@ 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.math.BigInteger import java.util.* +import java.util.stream.Stream import kotlin.collections.ArrayList import kotlin.collections.HashMap @@ -186,9 +188,9 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter override val storageType: StorageStackType get() = OverdriveThatMatters.INSTANCE.ITEM_STORAGE() - private val listeners = ArrayList>() + private val listeners = ArrayList>() - override fun addListener(listener: IStorageListener): Boolean { + override fun addListener(listener: IStorageEventConsumer): Boolean { if (!listeners.contains(listener)) { listeners.add(listener) return true @@ -197,7 +199,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter return false } - override fun removeListener(listener: IStorageListener): Boolean { + override fun removeListener(listener: IStorageEventConsumer): Boolean { return listeners.remove(listener) } @@ -214,7 +216,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter 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 + scannedMap.stack.count -= item.stack.count.toBigInteger() if (scannedMap.stack.count.isPositive) { for (listener in listeners) { @@ -238,7 +240,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter val oldCount = scannedMap.stack.count item.stack.count += diff - scannedMap.stack.count += diff + scannedMap.stack.count += diff.toBigInteger() for (listener in listeners) { listener.changeStack(scannedMap.stack, scannedMap.id, oldCount) @@ -252,7 +254,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter val key = storageStack.key() var tuple: TrackedTuple? = tuples[key] val added = tuple == null - var oldCount = ImpreciseFraction.ZERO + var oldCount = BigInteger.ZERO if (added) { tuple = TrackedTuple(storageStack, UUID.randomUUID()) @@ -260,7 +262,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter tuples[key] = tuple } else { oldCount = tuple!!.stack.count - tuple.stack.count += stack.count + tuple.stack.count += stack.count.toBigInteger() } tuple.children[slot] = SlotTuple(slot, stack.copy()) @@ -343,7 +345,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter if (energy.batteryLevel.isZero || !filter.match(stack.item)) return stack - val maxPossibleDemand = stack.count * ITEM_STORAGE.energyPerOperation + val maxPossibleDemand = ITEM_STORAGE.energyPerOperation * stack.count val maxExtractEnergy = energy.extractEnergyInner(maxPossibleDemand, true) var leftover: ItemStackWrapper @@ -352,7 +354,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter leftover = stack.copy() } else { leftover = stack.copy().also { - it.count = (maxExtractEnergy / ITEM_STORAGE.energyPerOperation).floor() + it.count = (maxExtractEnergy / ITEM_STORAGE.energyPerOperation).whole } } @@ -361,7 +363,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter leftover = ItemStackWrapper(parent.insertItem(slot, leftover.stack, simulate)) if (oldCount != leftover.count && !simulate) { - energy.extractEnergyInner((oldCount - leftover.count) * ITEM_STORAGE.energyPerOperation, false) + energy.extractEnergyInner(ITEM_STORAGE.energyPerOperation * (oldCount - leftover.count), false) scan(slot) } @@ -373,22 +375,22 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter return leftover } - override fun getStack(id: UUID): ItemStackWrapper { + override fun get(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() - + override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): ItemStackWrapper { if (!amount.isPositive) return ItemStackWrapper.EMPTY - val maxPossibleDemand = amount * OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation + val maxPossibleDemand = ITEM_STORAGE.energyPerOperation * amount val maxExtractEnergy = energy.extractEnergyInner(maxPossibleDemand, true) + @Suppress("NAME_SHADOWING") + var amount = amount + if (maxPossibleDemand != maxExtractEnergy) { - amount = (maxExtractEnergy / OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation).floor() + amount = (maxExtractEnergy / ITEM_STORAGE.energyPerOperation).whole } val intAmount = amount.toLong() @@ -433,18 +435,18 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter return ItemStackWrapper.EMPTY } - copy.count = ImpreciseFraction(totalExtracted) + copy.count = totalExtracted.toBigInteger() return copy } - override fun getStacks(): Collection> { + override val stacks: Stream> get() { val listing = ArrayList>(index.size) for (tuple in index.values) { listing.add(StorageTuple(tuple.id, tuple.stack)) } - return listing + return listing.stream() } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt index 231f0d7a6..4537ec517 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/StorageInterfaces.kt @@ -3,7 +3,6 @@ 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.nbt.ListTag import net.minecraft.network.chat.Component import net.minecraft.network.chat.TranslatableComponent import net.minecraft.server.level.ServerLevel @@ -36,9 +35,9 @@ import ru.dbotthepony.mc.otm.menu.StorageImporterMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.storage.* +import java.math.BigInteger import java.util.* import java.util.stream.Stream -import kotlin.collections.HashMap import kotlin.collections.HashSet abstract class AbstractStorageImportExport( @@ -190,17 +189,17 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) return stack val view = cell.storageGraph?.getVirtualComponent(ITEM_STORAGE) ?: return stack - val maxMove = energy.extractStepInner(ITEM_STORAGE.energyPerOperation, stack.count, true) + val maxMove = energy.extractStepInnerBi(ITEM_STORAGE.energyPerOperation, stack.count, true) - if (maxMove == 0) + if (maxMove == BigInteger.ZERO) return stack - val leftover = view.insertStack(ItemStackWrapper(stack).also { it.count = maxMove.toImpreciseFraction() }, simulate) + val leftover = view.insertStack(ItemStackWrapper(stack).also { it.count = maxMove }, simulate) if (simulate) return leftover.stack - energy.extractStepInner(ITEM_STORAGE.energyPerOperation, maxMove - leftover.count.toInt(), false) + energy.extractStepInner(ITEM_STORAGE.energyPerOperation, maxMove - leftover.count, false) return leftover.stack } @@ -265,7 +264,7 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState) class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractStorageImportExport(MBlockEntities.STORAGE_EXPORTER, blockPos, blockState), - IStorageListener { + IStorageEventConsumer { override val defaultDisplayName: Component get() = MACHINE_NAME @@ -275,7 +274,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : private val relevantTuples = HashSet() - override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageView) { + override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageProvider) { if (!filter.match(stack.item)) { return } @@ -283,7 +282,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : relevantTuples.add(id) } - override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: ImpreciseFraction) { + override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: BigInteger) { // no-op } @@ -296,7 +295,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : val component = cell.storageGraph?.getVirtualComponent(ITEM_STORAGE) ?: return@ItemFilter - for (tuple in component.getStacks()) { + for (tuple in component.stacks) { addStack(tuple, component) } @@ -315,7 +314,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : private val exportStacks: Stream> get() { val view = cell.storageGraph?.getVirtualComponent(ITEM_STORAGE) ?: return Stream.empty() - return relevantTuples.stream().map { it to view.getStack(it) } + return relevantTuples.stream().map { it to view[it] } } override fun saveAdditional(nbt: CompoundTag) { @@ -353,9 +352,9 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : continue } - val exportAmountA = items.extractStack(stack.first, stack.second.count.toInt().coerceAtMost(MAX_MOVE_PER_OPERATION).toImpreciseFraction(), true).count.toInt() + val exportAmountA = items.extractStack(stack.first, stack.second.count.coerceAtMost(MAX_MOVE_PER_OPERATION), true).count - if (exportAmountA == 0) { + if (exportAmountA == BigInteger.ZERO) { continue } @@ -369,7 +368,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : if (leftover.count != exportAmount) { hit = true - exportAmount = items.extractStack(stack.first, ImpreciseFraction(exportAmount - leftover.count), false).count.toInt() + exportAmount = items.extractStack(stack.first, (exportAmount - leftover.count).toBigInteger(), false).count.toInt() resolved.insertItem(lastSlot, stack.second.stack.also { it.count = exportAmount }, false) energy.extractStepInner(ITEM_STORAGE.energyPerOperation, exportAmount, false) break @@ -387,7 +386,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : } companion object { - const val MAX_MOVE_PER_OPERATION = 4 + val MAX_MOVE_PER_OPERATION: BigInteger = BigInteger.valueOf(4L) private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_EXPORTER}") private const val INTERVAL = 5 const val MAX_FILTERS = 6 * 3 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/IMatteryEnergyStorage.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/IMatteryEnergyStorage.kt index 102ba2d0f..97071dba8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/IMatteryEnergyStorage.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/IMatteryEnergyStorage.kt @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.capability import net.minecraftforge.energy.IEnergyStorage import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import java.math.BigInteger // IEnergyStorage for direct compat with Forge Energy interface IMatteryEnergyStorage : IEnergyStorage { @@ -212,3 +213,27 @@ fun IMatteryEnergyStorage.extractStepInner(base: ImpreciseFraction, multiplier: fun IMatteryEnergyStorage.extractStepOuter(base: ImpreciseFraction, multiplier: Int, simulate: Boolean): Int { return (extractEnergyOuter(base * multiplier, simulate) / base).toInt() } + +fun IMatteryEnergyStorage.extractStepInnerBi(base: ImpreciseFraction, multiplier: Int, simulate: Boolean): BigInteger { + return (extractEnergyInner(base * multiplier, simulate) / base).whole +} + +fun IMatteryEnergyStorage.extractStepOuterBi(base: ImpreciseFraction, multiplier: Int, simulate: Boolean): BigInteger { + return (extractEnergyOuter(base * multiplier, simulate) / base).whole +} + +fun IMatteryEnergyStorage.extractStepInner(base: ImpreciseFraction, multiplier: BigInteger, simulate: Boolean): Int { + return (extractEnergyInner(base * multiplier, simulate) / base).toInt() +} + +fun IMatteryEnergyStorage.extractStepOuter(base: ImpreciseFraction, multiplier: BigInteger, simulate: Boolean): Int { + return (extractEnergyOuter(base * multiplier, simulate) / base).toInt() +} + +fun IMatteryEnergyStorage.extractStepInnerBi(base: ImpreciseFraction, multiplier: BigInteger, simulate: Boolean): BigInteger { + return (extractEnergyInner(base * multiplier, simulate) / base).whole +} + +fun IMatteryEnergyStorage.extractStepOuterBi(base: ImpreciseFraction, multiplier: BigInteger, simulate: Boolean): BigInteger { + return (extractEnergyOuter(base * multiplier, simulate) / base).whole +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/API.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/API.kt index 2e2027d7e..fc4db5c62 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/API.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/API.kt @@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.storage.IStorageComponent import ru.dbotthepony.mc.otm.storage.IStorageStack import ru.dbotthepony.mc.otm.storage.IStorageTuple import ru.dbotthepony.mc.otm.storage.ItemStackWrapper +import java.math.BigInteger import java.util.* interface IItemMatteryDrive : IMatteryDrive { @@ -25,19 +26,13 @@ interface IItemMatteryDrive : IMatteryDrive { fun findItems(stack: ItemStack): IStorageTuple? } -interface IItemViewListener { - fun addViewItem(stack: ItemStack, id_upstream: UUID) - fun changeViewItem(id_upstream: UUID, new_count: Int) - fun removeViewItem(id_upstream: UUID) -} - interface IMatteryDrive : IStorageComponent { val uuid: UUID var isDirty: Boolean - val storedCount: ImpreciseFraction - val driveCapacity: ImpreciseFraction + val storedCount: BigInteger + val driveCapacity: BigInteger // not extending INBTSerializable to avoid serializing it as forgecaps fun serializeNBT(): CompoundTag diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/AbstractMatteryDrive.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/AbstractMatteryDrive.kt index e64e7a5c7..916e50b9c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/AbstractMatteryDrive.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/AbstractMatteryDrive.kt @@ -1,21 +1,26 @@ package ru.dbotthepony.mc.otm.capability.drive -import it.unimi.dsi.fastutil.longs.Long2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap +import it.unimi.dsi.fastutil.objects.ObjectArraySet import kotlin.jvm.JvmOverloads import java.util.UUID import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.nbt.Tag +import ru.dbotthepony.mc.otm.core.BigInteger import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.isPositive +import ru.dbotthepony.mc.otm.core.serializeNBT import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.set import ru.dbotthepony.mc.otm.storage.* +import java.math.BigInteger import java.util.ArrayList import java.util.HashSet +import java.util.stream.Stream abstract class AbstractMatteryDrive @JvmOverloads constructor( - override var driveCapacity: ImpreciseFraction, + override var driveCapacity: BigInteger, override val uuid: UUID = UUID.randomUUID(), var maxDifferentStacks: Int = 0xFFFF ) : IMatteryDrive { @@ -34,13 +39,13 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor var storedDifferentStacks = 0 protected set - override var storedCount = ImpreciseFraction.ZERO + override var storedCount: BigInteger = BigInteger.ZERO protected set @Suppress("unchecked_cast") override fun insertStack(stack: T, simulate: Boolean): T { val maxInsert = driveCapacity.minus(storedCount).coerceAtMost(stack.count) - if (maxInsert <= ImpreciseFraction.ZERO) return stack + if (maxInsert <= BigInteger.ZERO) return stack val key = stack.key() val tuple = tuples[key] @@ -91,20 +96,18 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor } @Suppress("unchecked_cast") - override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T { - @Suppress("NAME_SHADOWING") - var amount = amount + override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): T { val get = tuplesByID[id] ?: return storageType.empty - if (!storageType.fractional) - amount = amount.floor() + @Suppress("NAME_SHADOWING") + var amount = amount if (!amount.isPositive) amount = get.stack.maxStackSize ?: get.stack.count amount = amount.coerceAtMost(get.stack.count) - if (amount <= ImpreciseFraction.ZERO) + if (amount <= BigInteger.ZERO) return storageType.empty val copy = get.stack.copy() as T @@ -165,11 +168,11 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor override fun deserializeNBT(nbt: CompoundTag) { tuples.clear() tuplesByID.clear() - storedCount = ImpreciseFraction.ZERO + storedCount = BigInteger.ZERO storedDifferentStacks = 0 nbt.ifHas("capacity") { - driveCapacity = ImpreciseFraction.deserializeNBT(it) + driveCapacity = BigInteger(it) } maxDifferentStacks = nbt.getInt("max_different_stacks") @@ -191,21 +194,21 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor } } - override fun getStack(id: UUID): T { + override fun get(id: UUID): T { return tuplesByID[id]?.stack ?: storageType.empty } - override fun getStacks(): List> { - return ArrayList>(tuples.size).also { it.addAll(tuples.values) } + override val stacks: Stream> get() { + return ArrayList>(tuples.size).also { it.addAll(tuples.values) }.stream() } - protected val listeners = HashSet>() + protected val listeners = ObjectArraySet>() - override fun addListener(listener: IStorageListener): Boolean { + override fun addListener(listener: IStorageEventConsumer): Boolean { return listeners.add(listener) } - override fun removeListener(listener: IStorageListener): Boolean { + override fun removeListener(listener: IStorageEventConsumer): Boolean { return listeners.remove(listener) } } \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/DrivePool.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/DrivePool.kt index 1c6066356..bcb4e7bfb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/DrivePool.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/DrivePool.kt @@ -28,13 +28,15 @@ import java.util.ArrayList * Why? * * There are several reasons: - * 0. This data can get very large very quickly, even when playing singleplayer (and much quicker and bigger when hosting a dedicated server) - * 1. This data can not be stored inside ItemStack.ForgeCaps due to it's size - * 2. This data can not be stored inside unshared (server only) nbt tag because, again, mods prone to use and interact with + * 1. This data can get very large very quickly, even when playing singleplayer (and much quicker and bigger when hosting a dedicated server) + * 2. This data can not be stored inside ItemStack.ForgeCaps due to it's size + * 3. This data can not be stored inside unshared (server only) nbt tag because, again, mods prone to use and interact with * it wrong, causing loss of stored data or mods exposing full content of a drive inside their own tag (which cause very real "NBT size too large" * network kicks, often locking players out of server/singleplayer worlds - * 3. net.minecraft.world.level.saveddata.SaveData is for storing everything inside one dat file, which + * 4. net.minecraft.world.level.saveddata.SaveData is for storing everything inside one dat file, which * is performance tanking, because we have to write *entire* NBT on each save, not the data of Drives that are dirty + * 5. Mods which check items for being stack-able even with stack size of 1 gonna compare nbt tag, + * which will be performance tanking due to clause 1. */ @Suppress("unused") object DrivePool { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/ItemMatteryDrive.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/ItemMatteryDrive.kt index 1d5a11c9d..74a66ad21 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/ItemMatteryDrive.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/drive/ItemMatteryDrive.kt @@ -8,20 +8,23 @@ import net.minecraft.world.item.Items import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.RegistryManager import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.core.BigInteger import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.serializeNBT import ru.dbotthepony.mc.otm.set import ru.dbotthepony.mc.otm.storage.IStorageTuple import ru.dbotthepony.mc.otm.storage.ItemStackWrapper import ru.dbotthepony.mc.otm.storage.StorageStackType import ru.dbotthepony.mc.otm.storage.key +import java.math.BigInteger import java.util.* import kotlin.collections.ArrayList class ItemMatteryDrive : AbstractMatteryDrive, IItemMatteryDrive { - constructor(capacity: ImpreciseFraction, max_different_stacks: Int) : super(capacity, maxDifferentStacks = max_different_stacks) - constructor(capacity: ImpreciseFraction, uuid: UUID, max_different_stacks: Int) : super(capacity, uuid, max_different_stacks) - constructor(capacity: ImpreciseFraction, uuid: UUID) : super(capacity, uuid) - constructor(capacity: ImpreciseFraction) : super(capacity) + constructor(capacity: BigInteger, max_different_stacks: Int) : super(capacity, maxDifferentStacks = max_different_stacks) + constructor(capacity: BigInteger, uuid: UUID, max_different_stacks: Int) : super(capacity, uuid, max_different_stacks) + constructor(capacity: BigInteger, uuid: UUID) : super(capacity, uuid) + constructor(capacity: BigInteger) : super(capacity) override val storageType: StorageStackType = OverdriveThatMatters.INSTANCE.ITEM_STORAGE() @@ -49,7 +52,7 @@ class ItemMatteryDrive : AbstractMatteryDrive, IItemMatteryDri val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(tag.getString("item"))) if (item != null && item !== Items.AIR) { - val count = ImpreciseFraction.deserializeNBT(tag["count"]) + val count = BigInteger(tag["count"]) val itemstack = ItemStack(item, 1) itemstack.tag = tag["data"] as? CompoundTag return ItemStackWrapper(itemstack, copy = false).also { it.count = count } @@ -76,6 +79,6 @@ class ItemMatteryDrive : AbstractMatteryDrive, IItemMatteryDri companion object { @JvmField - val DUMMY = ItemMatteryDrive(ImpreciseFraction(0), UUID(0L, 0L), 0) + val DUMMY = ItemMatteryDrive(BigInteger.ZERO, UUID(0L, 0L), 0) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt index 0aa17b7bf..af0926648 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/mekanism/QIO.kt @@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.compat.mekanism import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap import it.unimi.dsi.fastutil.objects.Object2ObjectFunction -import mekanism.api.math.MathUtils import mekanism.common.content.qio.QIOFrequency import mekanism.common.content.qio.QIOFrequency.QIOItemTypeData import mekanism.common.lib.frequency.Frequency @@ -23,11 +22,14 @@ import ru.dbotthepony.mc.otm.addPostServerTickerOnce import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.isMekanismLoaded import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.isPositive import ru.dbotthepony.mc.otm.core.toImpreciseFraction import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph import ru.dbotthepony.mc.otm.storage.* +import java.math.BigInteger import java.util.UUID +import java.util.stream.Stream private val QIO_LOCATION = ResourceLocation(OverdriveThatMatters.MOD_ID, "item_storage") @@ -46,14 +48,14 @@ private class QIOFrequencyAccess(val parent: QIOFrequency) : IStorageComponent() private val tracked = HashMap() - private val listeners = ArrayList>() + private val listeners = ArrayList>() - override fun getStack(id: UUID): ItemStackWrapper { + override fun get(id: UUID): ItemStackWrapper { return index[id]?.stack ?: ItemStackWrapper.EMPTY } - override fun getStacks(): Collection> { - return ArrayList>(index.size).also { it.addAll(index.values) } + override val stacks: Stream> get() { + return ArrayList>(index.size).also { it.addAll(index.values) }.stream() } override fun insertStack(stack: ItemStackWrapper, simulate: Boolean): ItemStackWrapper { @@ -81,11 +83,11 @@ private class QIOFrequencyAccess(val parent: QIOFrequency) : IStorageComponent): Boolean { + override fun addListener(listener: IStorageEventConsumer): Boolean { if (!listeners.contains(listener)) { listeners.add(listener) return true @@ -137,7 +139,7 @@ private class QIOFrequencyAccess(val parent: QIOFrequency) : IStorageComponent): Boolean { + override fun removeListener(listener: IStorageEventConsumer): Boolean { return listeners.remove(listener) } @@ -149,14 +151,14 @@ private class QIOFrequencyAccess(val parent: QIOFrequency) : IStorageComponent BigInteger.ZERO +inline val BigInteger.isNegative get() = this < BigInteger.ZERO + +fun BigInteger.serializeNBT(): ByteArrayTag { + return ByteArrayTag(toByteArray()) +} + +fun BigInteger(tag: Tag?): BigInteger { + if (tag !is ByteArrayTag) + return BigInteger.ZERO + + return BigInteger(tag.asByteArray) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt index 107b83c68..d53d90d52 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNetworkGraph.kt @@ -5,7 +5,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import net.minecraft.server.level.ServerLevel 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 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt index a9c04884b..435974578 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt @@ -28,15 +28,12 @@ import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.set +import java.math.BigInteger import java.util.* class PortableCondensationDriveItem(capacity: Int) : Item(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { - val capacity: ImpreciseFraction - - init { - this.capacity = ImpreciseFraction(capacity) - } + val capacity: BigInteger = capacity.toBigInteger() private inner class DriveCapability(private val stack: ItemStack) : ICapabilityProvider { private var uuid: UUID? = null @@ -48,10 +45,10 @@ class PortableCondensationDriveItem(capacity: Int) : val uuid = uuid - DrivePool.get(uuid!!, { tag: CompoundTag? -> + return@of DrivePool.get(uuid!!, { tag: CompoundTag? -> val drive = ItemMatteryDrive(capacity, uuid) drive.deserializeNBT(tag!!) - drive + return@get drive }, { ItemMatteryDrive(capacity, uuid) }) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt index c26cc1a2e..ccb932af2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt @@ -20,12 +20,14 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.isZero import ru.dbotthepony.mc.otm.core.readImpreciseFraction import ru.dbotthepony.mc.otm.core.writeImpreciseFraction import ru.dbotthepony.mc.otm.menu.FormattingHelper import ru.dbotthepony.mc.otm.network.MatteryNetworking import ru.dbotthepony.mc.otm.orNull import ru.dbotthepony.mc.otm.storage.ItemStackWrapper +import java.math.BigInteger import java.util.function.Supplier internal var building = false @@ -174,7 +176,7 @@ fun canDecompose(stack: ItemStack): Boolean { return canDecompose(stack.item) && (stack.getCapability(MatteryCapability.MATTER).orNull()?.storedMatter ?: ImpreciseFraction.ZERO).isZero && - (stack.getCapability(MatteryCapability.DRIVE).orNull()?.storedCount ?: ImpreciseFraction.ZERO).isZero + (stack.getCapability(MatteryCapability.DRIVE).orNull()?.storedCount ?: BigInteger.ZERO).isZero } private const val MAX_NESTING = 100 @@ -203,7 +205,7 @@ private fun getMatterValue(stack: ItemStack, level: Int): MatterTuple { val drive = stack.getCapability(MatteryCapability.DRIVE).orNull() if (drive != null && drive.storageType === OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) { - for (item in (drive as IMatteryDrive).getStacks()) { + for (item in (drive as IMatteryDrive).stacks) { val tuple = getMatterValue(item.stack.stack, level + 1) if (!tuple.isZero) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt index 60042b532..9eba10f71 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt @@ -18,9 +18,10 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.network.MatteryNetworking import ru.dbotthepony.mc.otm.network.SetCarriedPacket import ru.dbotthepony.mc.otm.storage.IStorageComponent -import ru.dbotthepony.mc.otm.storage.IStorageListener -import ru.dbotthepony.mc.otm.storage.IStorageView +import ru.dbotthepony.mc.otm.storage.IStorageEventConsumer +import ru.dbotthepony.mc.otm.storage.IStorageProvider import ru.dbotthepony.mc.otm.storage.ItemStackWrapper +import java.math.BigInteger import java.util.* import java.util.function.Supplier @@ -155,7 +156,7 @@ class StackRemovePacket(val id: Int, val stackID: Int) { /** * Creates a virtual, slotless container for Player to interaction with. */ -open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageListener { +open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageEventConsumer { data class NetworkedItem constructor(val id: Int, val stack: ItemStack, val upstreamId: UUID? = null) protected var nextStackID = 0 @@ -230,8 +231,8 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: return localState.values.size } - override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageView) = addObject(stack.stack, id) - override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: ImpreciseFraction) = changeObject(id, stack.count.toInt()) + override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageProvider) = addObject(stack.stack, id) + override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: BigInteger) = changeObject(id, stack.count.toInt()) protected fun network(fn: () -> Any) { if (!remote) { @@ -310,13 +311,13 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: else Math.max(1, state.stack.maxStackSize / 2) - val extracted = provider.extractStack(state.upstreamId!!, amount, true) + val extracted = provider.extractStack(state.upstreamId!!, amount.toBigInteger(), true) if (!extracted.isEmpty) { val (_, remaining) = menu.quickMoveToInventory(extracted.stack, false) if (remaining.count != extracted.count.toInt()) { - provider.extractStack(state.upstreamId, extracted.count.toInt() - remaining.count, false) + provider.extractStack(state.upstreamId, (extracted.count.toInt() - remaining.count).toBigInteger(), false) } } @@ -354,7 +355,7 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: else (state.stack.count / 2).coerceAtMost(state.stack.maxStackSize / 2).coerceAtLeast(1) - val extracted = provider.extractStack(state.upstreamId!!, amount, false) + val extracted = provider.extractStack(state.upstreamId!!, amount.toBigInteger(), false) menu.carried = extracted.stack MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(menu.carried)) menu.setRemoteCarried(menu.carried.copy()) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt index f5e677d25..aee94f2c3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt @@ -1,7 +1,9 @@ package ru.dbotthepony.mc.otm.storage import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import java.math.BigInteger import java.util.* +import java.util.stream.Stream /** * Represents a stack in storage system. @@ -19,51 +21,36 @@ interface IStorageStack { fun copy(): IStorageStack /** - * Despite count being [ImpreciseFraction], far not all items can be "fraction" - * into pieces (e.g. ItemStacks). + * Size of this storage stack * - * Consult [StorageStackType.fractional] to see if item has actual fractions. - * - * Implementation MUST [ImpreciseFraction.floor] received value if fractions - * are not supported, and NOT throw any errors. Writing fractional value is a correct - * behavior, and is used in base mod. - * - * Behavior of writing negative value is undefined. + * This is overriden in subclasses */ - var count: ImpreciseFraction + var count: BigInteger val isEmpty: Boolean /** * @return max stack size for this stack object, * null if unlimited (default) */ - val maxStackSize: ImpreciseFraction? get() = null + val maxStackSize: BigInteger? get() = null /** * Increase [count] by [amount] */ - fun grow(amount: ImpreciseFraction) { + fun grow(amount: BigInteger) { count += amount } /** * Decrease [count] by [amount] */ - fun shrink(amount: ImpreciseFraction) { + fun shrink(amount: BigInteger) { count -= amount } } -/** - * (Supposedly shallow) Copies this object and sets it's count to 1 for use as map key. - * - * Equals to next code: - * ```kotlin - * this.copy().also { it.count = ImpreciseFraction.ONE } - * ``` - */ fun T.key(): T { - return copy().also { it.count = ImpreciseFraction.ONE } as T + return copy().also { it.count = BigInteger.ONE } as T } /** @@ -76,19 +63,42 @@ interface IStorage { val storageType: StorageStackType } -interface IStorageTrigger : IStorage { +/** + * Generates events for [IStorageEventConsumer] + */ +interface IStorageEventProducer : IStorage { /** - * [listener] is [IStorageListener] which want to subscribe to our events + * [listener] is [IStorageEventConsumer] which want to subscribe to our events */ - fun addListener(listener: IStorageListener): Boolean + fun addListener(listener: IStorageEventConsumer): Boolean /** - * [listener] is [IStorageListener] which want to unsubscribe from our events + * [listener] is [IStorageEventConsumer] which want to unsubscribe from our events */ - fun removeListener(listener: IStorageListener): Boolean + fun removeListener(listener: IStorageEventConsumer): Boolean } -interface IStorageConsumer : IStorage { +/** + * Consumes events produced by [IStorageEventConsumer] + */ +interface IStorageEventConsumer { + /** + * Fired on whenever an object is added (to listener) we subscribed to + */ + fun addStack(stack: T, id: UUID, provider: IStorageProvider) + + /** + * Fired on whenever an object is changes on listener we subscribed to + */ + fun changeStack(stack: T, id: UUID, oldCount: BigInteger) + + /** + * Fired on whenever an object is removed from listener we subscribed to + */ + fun removeStack(stack: T, id: UUID) +} + +interface IStorageAcceptor : IStorage { /** * Inserts an item into system. * @return leftover, might equal to [stack] if no items were inserted @@ -96,12 +106,14 @@ interface IStorageConsumer : IStorage { fun insertStack(stack: T, simulate: Boolean): T } -interface IStorageView : IStorageTrigger { +interface IStorageProvider : IStorageEventProducer { /** * @param id identifier of stack * @return stored object (not a copy). Do not edit it. */ - fun getStack(id: UUID): T + operator fun get(id: UUID): T + + val stacks: Stream> /** * If tuple does not exist, returns empty stack @@ -111,31 +123,11 @@ interface IStorageView : IStorageTrigger { * @param simulate whenever to simulate the action or not * @return copy of object, with amount of units actually extracted */ - fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T - fun extractStack(id: UUID, amount: Int, simulate: Boolean): T = extractStack(id, ImpreciseFraction(amount), simulate) - fun extractStack(id: UUID, amount: Long, simulate: Boolean): T = extractStack(id, ImpreciseFraction(amount), simulate) + fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): T - /** - * Designed for views, for extraction with less computation overhead caused by - * copying stack extracted - * - * @param id identifier of stack to extract - * @param amount desired amount to extract - * @param simulate whenever to simulate the action or not - * @return amount extracted - */ - fun extractStackCount(id: UUID, amount: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { - return extractStack(id, amount, simulate).count - } - - fun extractStackCount(id: UUID, amount: Int, simulate: Boolean): ImpreciseFraction = extractStackCount(id, ImpreciseFraction(amount), simulate) - fun extractStackCount(id: UUID, amount: Long, simulate: Boolean): ImpreciseFraction = extractStackCount(id, ImpreciseFraction(amount), simulate) - - fun getStacks(): Collection> - - fun addListenerAuto(listener: IStorageListener): Boolean { + fun addListenerAuto(listener: IStorageEventConsumer): Boolean { if (addListener(listener)) { - for (stack in getStacks()) { + for (stack in stacks) { listener.addStack(stack.stack, stack.id, this) } @@ -145,9 +137,9 @@ interface IStorageView : IStorageTrigger { return false } - fun removeListenerAuto(listener: IStorageListener): Boolean { + fun removeListenerAuto(listener: IStorageEventConsumer): Boolean { if (removeListener(listener)) { - for (stack in getStacks()) { + for (stack in stacks) { listener.removeStack(stack.stack, stack.id) } @@ -158,33 +150,16 @@ interface IStorageView : IStorageTrigger { } } -interface IStorageListener { - /** - * Fired on whenever an object is added (to listener) we subscribed to - */ - fun addStack(stack: T, id: UUID, provider: IStorageView) +fun IStorageEventConsumer.changeStack(tuple: IStorageTuple, oldCount: BigInteger) { + changeStack(tuple.stack, tuple.id, oldCount) +} - fun addStack(tuple: IStorageTuple, provider: IStorageView) { - addStack(tuple.stack, tuple.id, provider) - } +fun IStorageEventConsumer.addStack(tuple: IStorageTuple, provider: IStorageProvider) { + addStack(tuple.stack, tuple.id, provider) +} - /** - * Fired on whenever an object is changes on listener we subscribed to - */ - fun changeStack(stack: T, id: UUID, oldCount: ImpreciseFraction) - - fun changeStack(tuple: IStorageTuple, oldCount: ImpreciseFraction) { - changeStack(tuple.stack, tuple.id, oldCount) - } - - /** - * Fired on whenever an object is removed from listener we subscribed to - */ - fun removeStack(stack: T, id: UUID) - - fun removeStack(tuple: IStorageTuple) { - removeStack(tuple.stack, tuple.id) - } +fun IStorageEventConsumer.removeStack(tuple: IStorageTuple) { + removeStack(tuple.stack, tuple.id) } interface IStorageTuple { @@ -193,12 +168,13 @@ interface IStorageTuple { } class StorageTuple(override val id: UUID, override val stack: T) : IStorageTuple -interface IStorageComponent : IStorageView, IStorageConsumer + +interface IStorageComponent : IStorageProvider, IStorageAcceptor /** * Component which (most time) proxy other components (combine their contents into single view) */ -interface IVirtualStorageComponent : IStorageComponent, IStorageListener { +interface IVirtualStorageComponent : IStorageComponent, IStorageEventConsumer { fun add(identity: IStorage) fun remove(identity: IStorage) fun contains(identity: IStorage): Boolean diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt index 0015aeecf..e9852735c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt @@ -6,6 +6,8 @@ import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistry import org.jetbrains.annotations.ApiStatus import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.isPositive +import java.math.BigInteger /** * constructors always copy its input. @@ -21,8 +23,7 @@ class ItemStackWrapper : IStorageStack { val registryName get() = item.item.registryName!! private val hash: Int - override var count: ImpreciseFraction - set(value) { field = value.floor() } + override var count: BigInteger /** * [copy] as false is used internally for fast index construction, do not specify @@ -36,7 +37,7 @@ class ItemStackWrapper : IStorageStack { this.item = item } - this.count = ImpreciseFraction(item.count) + this.count = BigInteger.valueOf(item.count.toLong()) if (copy) { this.item.count = 1 @@ -72,7 +73,7 @@ class ItemStackWrapper : IStorageStack { return hash * 31 + count.hashCode() } - override val maxStackSize get() = ImpreciseFraction(item.maxStackSize) + override val maxStackSize: BigInteger get() = BigInteger.valueOf(item.maxStackSize.toLong()) override val isEmpty: Boolean get() = item.isEmpty || !count.isPositive diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt index 1ad3bd955..a4cd6584f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt @@ -13,24 +13,9 @@ open class StorageStackType( * Speculated energy required per operation on stack with size of 1 */ open val energyPerOperation: ImpreciseFraction, - - /** - * Whenever is this stack supports fractional part (e.g. 0.5). - * - * Keep in mind fractions are imprecise and can lead to rounding errors. - * [ImpreciseFraction] class attempts to negate most of the issues - * (e.g. 0.1 + 0.2 eventually getting its 0....4 part into whole part), - * but that is about it. - * - * On design side note, storage system could have been using [Fraction], but there is an issue: - * they are **precise**. Under precise, means that anything that continuously divide/multiply them - * they become more and more "irrational", greatly slowing down operations. Worst case scenario: - * value is getting divided by [Long.MAX_VALUE] again and again, creating insanely huge divisor. - */ - open val fractional: Boolean ) { open fun energyPerOperation(stack: T): ImpreciseFraction { - return stack.count * energyPerOperation + return energyPerOperation * stack.count } open fun energyPerStorage(stack: T) = energyPerOperation(stack) @@ -56,10 +41,9 @@ object StorageRegistry { fun register( identity: Class, empty: T, - energyPerOperation: ImpreciseFraction, - fractional: Boolean + energyPerOperation: ImpreciseFraction ): StorageStackType { - return register(StorageStackType(identity, empty, energyPerOperation, fractional)) as StorageStackType + return register(StorageStackType(identity, empty, energyPerOperation)) as StorageStackType } @JvmStatic diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/VirtualComponent.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/VirtualComponent.kt index 0fafaf82c..23a207be5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/VirtualComponent.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/VirtualComponent.kt @@ -1,29 +1,31 @@ package ru.dbotthepony.mc.otm.storage -import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap -import it.unimi.dsi.fastutil.longs.Long2ObjectFunction -import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap import it.unimi.dsi.fastutil.objects.ObjectArraySet import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.isPositive +import ru.dbotthepony.mc.otm.core.isZero +import java.math.BigInteger import java.util.* +import java.util.stream.Stream import kotlin.collections.HashMap -class RemoteTuple(val obj: T, val remote_id: UUID, val provider: IStorageView, val local: LocalTuple) { - fun extract(amount: ImpreciseFraction, simulate: Boolean): T { - return provider.extractStack(remote_id, amount, simulate) - } - - fun extractCount(amount: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { - return provider.extractStackCount(remote_id, amount, simulate) +class RemoteTuple( + override val stack: T, + override val id: UUID, + val provider: IStorageProvider, + val local: LocalTuple +) : IStorageTuple { + fun extract(amount: BigInteger, simulate: Boolean): T { + return provider.extractStack(id, amount, simulate) } override fun equals(other: Any?): Boolean { - return other is RemoteTuple<*> && other.remote_id == remote_id || other is UUID && other == remote_id + return other is RemoteTuple<*> && other.id == id || other is UUID && other == id } override fun hashCode(): Int { - return remote_id.hashCode() + return id.hashCode() } } @@ -35,31 +37,31 @@ open class VirtualComponent(type: StorageStackType) : IVir override val storageType: StorageStackType = type // удаленный UUID -> Кортеж - protected val remoteByUUID = HashMap>() + protected val remoteByUUID: MutableMap> = HashMap() // локальный UUID -> Локальный кортеж - protected val localByUUID = HashMap>() + protected val localByUUID: MutableMap> = HashMap() // Стак -> Локальный кортеж стака - protected val tuples = HashMap>() + protected val tuples: MutableMap> = HashMap() // ArrayList для скорости работы - protected val listeners = ArrayList>() - protected val set = ObjectArraySet() - protected val consumers = ArrayList>() + protected val listeners: MutableSet> = ObjectArraySet() + protected val set: MutableSet> = ObjectArraySet() + protected val consumers: MutableSet> = ObjectArraySet() protected open fun onAdd(identity: IStorage) {} protected open fun onRemove(identity: IStorage) {} override fun add(identity: IStorage) { if (set.add(identity)) { - if (identity is IStorageView) { + if (identity is IStorageProvider) { identity.addListenerAuto(this) - } else if (identity is IStorageTrigger) { + } else if (identity is IStorageEventProducer) { identity.addListener(this) } - if (identity is IStorageConsumer) { + if (identity is IStorageAcceptor) { consumers.add(identity) } @@ -69,13 +71,13 @@ open class VirtualComponent(type: StorageStackType) : IVir override fun remove(identity: IStorage) { if (set.remove(identity)) { - if (identity is IStorageView) { + if (identity is IStorageProvider) { identity.removeListenerAuto(this) - } else if (identity is IStorageTrigger) { + } else if (identity is IStorageEventProducer) { identity.removeListener(this) } - if (identity is IStorageConsumer) { + if (identity is IStorageAcceptor) { consumers.remove(identity) } @@ -87,7 +89,7 @@ open class VirtualComponent(type: StorageStackType) : IVir return set.contains(identity) } - override fun addListener(listener: IStorageListener): Boolean { + override fun addListener(listener: IStorageEventConsumer): Boolean { if (!listeners.contains(listener)) { listeners.add(listener) return true @@ -96,31 +98,31 @@ open class VirtualComponent(type: StorageStackType) : IVir return false } - override fun removeListener(listener: IStorageListener): Boolean { + override fun removeListener(listener: IStorageEventConsumer): Boolean { return listeners.remove(listener) } - override fun getStack(id: UUID): T { + override fun get(id: UUID): T { return localByUUID[id]?.stack ?: this.storageType.empty } - override fun getStacks(): List> { - return ArrayList>(tuples.size).also { it.addAll(tuples.values) } + override val stacks: Stream> get() { + return ArrayList>(tuples.size).also { it.addAll(tuples.values) }.stream() } @Suppress("unchecked_cast") - override fun addStack(stack: T, id: UUID, provider: IStorageView) { + override fun addStack(stack: T, id: UUID, provider: IStorageProvider) { check(!remoteByUUID.containsKey(id)) { "Already tracking tuple with id $id" } val key = stack.key() var local: LocalTuple? = tuples[key] - var oldCount = ImpreciseFraction.ZERO + var oldCount = BigInteger.ZERO val added = local == null if (local == null) { local = LocalTuple(stack.copy() as T, UUID.randomUUID(), ArrayList>(1)) localByUUID[local.id] = local - tuples[key as T] = local + tuples[key] = local } else { oldCount = local.stack.count local.stack.grow(stack.count) @@ -141,12 +143,12 @@ open class VirtualComponent(type: StorageStackType) : IVir } } - override fun changeStack(stack: T, id: UUID, oldCount: ImpreciseFraction) { + override fun changeStack(stack: T, id: UUID, oldCount: BigInteger) { require(stack.count.isPositive) val tuple = remoteByUUID[id] ?: throw IllegalStateException("No such tuple with id $id") - val diff = stack.count - tuple.obj.count - tuple.obj.count = stack.count + val diff = stack.count - tuple.stack.count + tuple.stack.count = stack.count @Suppress("NAME_SHADOWING") val oldCount = tuple.local.stack.count tuple.local.stack.grow(diff) @@ -159,12 +161,12 @@ open class VirtualComponent(type: StorageStackType) : IVir override fun removeStack(stack: T, id: UUID) { val tuple = remoteByUUID[id] ?: throw IllegalStateException("No such tuple with id $id") - tuple.local.stack.shrink(tuple.obj.count) + tuple.local.stack.shrink(tuple.stack.count) tuple.local.tuples.remove(tuple) remoteByUUID.remove(id) - val a = tuple.local.stack.count <= ImpreciseFraction.ZERO + val a = tuple.local.stack.count <= BigInteger.ZERO val b = tuple.local.tuples.size == 0 if (a || b) { @@ -194,8 +196,8 @@ open class VirtualComponent(type: StorageStackType) : IVir } @Suppress("unchecked_cast") - override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T { - if (amount.isZero) + override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): T { + if (!amount.isPositive) return this.storageType.empty @Suppress("name_shadowing") @@ -205,18 +207,16 @@ open class VirtualComponent(type: StorageStackType) : IVir if (tuple == null || amount.isZero) return this.storageType.empty - if (!storageType.fractional) - amount = amount.floor() - if (!amount.isPositive) amount = tuple.stack.maxStackSize ?: tuple.stack.count val toExtract = tuple.stack.count.coerceAtMost(amount) - var extracted = ImpreciseFraction.ZERO + var extracted = BigInteger.ZERO val copy = tuple.stack.copy() as T for (remote_tuple in tuple.tuples.let { Array(it.size) { i -> it[i] } }) { - extracted += remote_tuple.extractCount(toExtract - extracted, simulate) + val extractedStack = remote_tuple.extract(toExtract - extracted, simulate) + extracted += extractedStack.count if (extracted >= toExtract) break @@ -238,8 +238,8 @@ open class PoweredComponent(open val parent: IStorageComponen override val storageType: StorageStackType get() = parent.storageType - override fun addListener(listener: IStorageListener) = parent.addListener(listener) - override fun removeListener(listener: IStorageListener) = parent.removeListener(listener) + override fun addListener(listener: IStorageEventConsumer) = parent.addListener(listener) + override fun removeListener(listener: IStorageEventConsumer) = parent.removeListener(listener) @Suppress("unchecked_cast") override fun insertStack(stack: T, simulate: Boolean): T { @@ -273,7 +273,7 @@ open class PoweredComponent(open val parent: IStorageComponen @Suppress("name_shadowing") val stack = stack.copy() as T val oldCount = stack.count - stack.count = extracted / storageType.energyPerOperation + stack.count = (extracted / storageType.energyPerOperation).whole val diff = oldCount - stack.count val newRequired = storageType.energyPerOperation * stack.count val newExtracted = energy.extractEnergyInner(newRequired, true) @@ -291,7 +291,7 @@ open class PoweredComponent(open val parent: IStorageComponen } if (!simulate) { - val requiredNew = (stack.count - leftover.count) * storageType.energyPerOperation + val requiredNew = storageType.energyPerOperation * (stack.count - leftover.count) energy.extractEnergyInner(requiredNew, false) } @@ -302,9 +302,9 @@ open class PoweredComponent(open val parent: IStorageComponen return stack } - override fun getStack(id: UUID) = parent.getStack(id) + override fun get(id: UUID) = parent[id] - override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T { + override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): T { val required = storageType.energyPerOperation * amount val energy = energyProvider.invoke() val extracted = energy.extractEnergyInner(required, true) @@ -324,7 +324,7 @@ open class PoweredComponent(open val parent: IStorageComponen if (extractedStack.count == amount) { energy.extractEnergyInner(required, false) } else { - energy.extractEnergyInner(extractedStack.count * storageType.energyPerOperation, false) + energy.extractEnergyInner(storageType.energyPerOperation * extractedStack.count, false) } } @@ -332,7 +332,7 @@ open class PoweredComponent(open val parent: IStorageComponen } @Suppress("name_shadowing") - val amount = required / storageType.energyPerOperation + val amount = (required / storageType.energyPerOperation).whole val extractedStack = parent.extractStack(id, amount, simulate) if (extractedStack.isEmpty) { @@ -340,13 +340,13 @@ open class PoweredComponent(open val parent: IStorageComponen } if (!simulate) { - energy.extractEnergyInner(extractedStack.count * storageType.energyPerOperation, false) + energy.extractEnergyInner(storageType.energyPerOperation * extractedStack.count, false) } return extractedStack } - override fun getStacks() = parent.getStacks() + override val stacks get() = parent.stacks } /** @@ -358,8 +358,8 @@ open class PoweredVirtualComponent(override val parent: IVirt constructor(parent: Class, energy: IMatteryEnergyStorage) : this(VirtualComponent(parent), { energy }) constructor(parent: StorageStackType, energy: IMatteryEnergyStorage) : this(VirtualComponent(parent), { energy }) - override fun addStack(stack: T, id: UUID, provider: IStorageView) = parent.addStack(stack, id, provider) - override fun changeStack(stack: T, id: UUID, oldCount: ImpreciseFraction) = parent.changeStack(stack, id, oldCount) + override fun addStack(stack: T, id: UUID, provider: IStorageProvider) = parent.addStack(stack, id, provider) + override fun changeStack(stack: T, id: UUID, oldCount: BigInteger) = parent.changeStack(stack, id, oldCount) override fun removeStack(stack: T, id: UUID) = parent.removeStack(stack, id) override fun add(identity: IStorage) = parent.add(identity)