diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index da365e8b6..7e559ea10 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -27,8 +27,8 @@ import ru.dbotthepony.mc.otm.matter.MatterRegistryKt; import ru.dbotthepony.mc.otm.network.MatteryNetworking; import ru.dbotthepony.mc.otm.registry.*; import ru.dbotthepony.mc.otm.storage.ItemStackWrapper; -import ru.dbotthepony.mc.otm.storage.StorageObjectRegistry; -import ru.dbotthepony.mc.otm.storage.StorageObjectTuple; +import ru.dbotthepony.mc.otm.storage.StorageRegistry; +import ru.dbotthepony.mc.otm.storage.StorageStackType; import javax.annotation.ParametersAreNonnullByDefault; @@ -43,7 +43,11 @@ public final class OverdriveThatMatters { public static OverdriveThatMatters INSTANCE; public AndroidGui ANDROID_GUI; - public StorageObjectTuple ITEM_STORAGE; + private StorageStackType ITEM_STORAGE; + + public StorageStackType ITEM_STORAGE() { + return ITEM_STORAGE; + } public static ResourceLocation loc(String path) { return new ResourceLocation(MOD_ID, path); @@ -89,9 +93,7 @@ public final class OverdriveThatMatters { private void setup(final FMLCommonSetupEvent event) { MatteryNetworking.register(); - // LOGGER.info("Registered network"); - - ITEM_STORAGE = StorageObjectRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125")); + ITEM_STORAGE = StorageRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125")); } private void setupClient(final FMLClientSetupEvent event) { diff --git a/src/main/java/ru/dbotthepony/mc/otm/storage/StorageObjectRegistry.java b/src/main/java/ru/dbotthepony/mc/otm/storage/StorageObjectRegistry.java deleted file mode 100644 index a7c83e017..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/storage/StorageObjectRegistry.java +++ /dev/null @@ -1,34 +0,0 @@ -package ru.dbotthepony.mc.otm.storage; - -import net.minecraft.MethodsReturnNonnullByDefault; -import ru.dbotthepony.mc.otm.core.Fraction; -import ru.dbotthepony.mc.otm.core.ImpreciseFraction; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; -import java.util.HashMap; -import java.util.Objects; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class StorageObjectRegistry { - private static final HashMap, StorageObjectTuple> REGISTRY = new HashMap<>(); - - public static StorageObjectTuple register(Class identity, T empty, ImpreciseFraction energyPerOperation) { - final var tuple = new StorageObjectTuple<>(identity, empty, energyPerOperation); - REGISTRY.put(identity, tuple); - return tuple; - } - - @SuppressWarnings("unchecked") - @Nullable - public static StorageObjectTuple get(Class identity) { - return (StorageObjectTuple) REGISTRY.get(identity); - } - - @Nonnull - public static StorageObjectTuple getOrError(Class identity) { - return Objects.requireNonNull(get(identity), "No storage mapping present for " + identity); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/storage/StorageObjectTuple.java b/src/main/java/ru/dbotthepony/mc/otm/storage/StorageObjectTuple.java deleted file mode 100644 index 1279153b0..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/storage/StorageObjectTuple.java +++ /dev/null @@ -1,21 +0,0 @@ -package ru.dbotthepony.mc.otm.storage; - -import ru.dbotthepony.mc.otm.core.Fraction; -import ru.dbotthepony.mc.otm.core.ImpreciseFraction; - -import javax.annotation.Nonnull; - -public record StorageObjectTuple(@Nonnull Class identity, @Nonnull T empty, @Nonnull ImpreciseFraction energyPerOperation) { - @Override - public boolean equals(Object obj) { - if (obj instanceof StorageObjectTuple tuple) - return tuple.identity == identity; - - return false; - } - - @Override - public int hashCode() { - return identity.hashCode(); - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt index 68e0392ae..2b231e81f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveRackBlockEntity.kt @@ -36,11 +36,11 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : super.setChanged(slot, new, old) old.getCapability(MatteryCapability.DRIVE).ifPresent { - cell.computeIfAbsent(it.storageIdentity()) {c -> PoweredVirtualComponent(c, energy)}.remove(it) + cell.computeIfAbsent(it.storageType) {PoweredVirtualComponent(it, energy)}.remove(it) } new.getCapability(MatteryCapability.DRIVE).ifPresent { - cell.computeIfAbsent(it.storageIdentity()) {c -> PoweredVirtualComponent(c, energy)}.add(it) + cell.computeIfAbsent(it.storageType) {PoweredVirtualComponent(it, energy)}.add(it) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveViewerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveViewerBlockEntity.kt index e3c18b193..a7af6ffc1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveViewerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/DriveViewerBlockEntity.kt @@ -31,7 +31,7 @@ class DriveViewerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte tickOnceServer { var state = blockState - if (container.getItem(0).getCapability(MatteryCapability.DRIVE).isPresent && energy.batteryLevel >= OverdriveThatMatters.INSTANCE.ITEM_STORAGE.energyPerOperation()) { + if (container.getItem(0).getCapability(MatteryCapability.DRIVE).isPresent && energy.batteryLevel >= OverdriveThatMatters.INSTANCE.ITEM_STORAGE().energyPerOperation) { state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING) } else { state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE) 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 9c99501f8..5de2addf3 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,37 +1,28 @@ package ru.dbotthepony.mc.otm.capability.drive -import ru.dbotthepony.mc.otm.core.Fraction.Companion.deserializeNBT -import ru.dbotthepony.mc.otm.storage.IStorageStack +import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap +import it.unimi.dsi.fastutil.longs.Long2ObjectFunction +import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap import kotlin.jvm.JvmOverloads -import java.util.HashMap -import ru.dbotthepony.mc.otm.storage.IStorageTuple import java.util.UUID -import ru.dbotthepony.mc.otm.storage.StorageObjectTuple -import ru.dbotthepony.mc.otm.storage.IStorageListener -import ru.dbotthepony.mc.otm.storage.StorageTuple import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.nbt.Tag -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.set +import ru.dbotthepony.mc.otm.storage.* import java.util.ArrayList import java.util.HashSet - abstract class AbstractMatteryDrive @JvmOverloads constructor( override var driveCapacity: ImpreciseFraction, override val uuid: UUID = UUID.randomUUID(), var maxDifferentStacks: Int = 0xFFFF ) : IMatteryDrive { + protected val storedStacks = Long2ObjectAVLTreeMap>>() + protected val storedByID = Object2ObjectAVLTreeMap>() - @JvmField - protected val storedStacks = HashMap>>() - - @JvmField - protected val storedByID = HashMap>() - abstract fun identity(): StorageObjectTuple override var isDirty = false set(value) { if (value != field && value && DrivePool.isLegalAccess()) { @@ -42,24 +33,26 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor } var storedDifferentStacks = 0 + protected set override var storedCount = ImpreciseFraction.ZERO protected set + @Suppress("unchecked_cast") override fun insertStack(stack: T, simulate: Boolean): T { val maxInsert = driveCapacity.minus(storedCount).min(stack.count) if (maxInsert <= ImpreciseFraction.ZERO) return stack - val listing = storedStacks.computeIfAbsent(stack.partitionKey()) { ArrayList() } + val listing = storedStacks.computeIfAbsent(stack.partitionKey, Long2ObjectFunction { ArrayList() }) for (state in listing) { - if (state.stack().sameItem(stack)) { + if (state.stack.sameItem(stack)) { if (!simulate) { - state.stack().grow(maxInsert) + state.stack.grow(maxInsert) storedCount += maxInsert for (listener in listeners) { - listener.changeObject(state.id(), state.stack().count) + listener.changeStack(state.id, state.stack.count) } isDirty = true @@ -84,10 +77,10 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor val state = StorageTuple(UUID.randomUUID(), copy) listing.add(state) - storedByID[state.id()] = state + storedByID[state.id] = state for (listener in listeners) { - listener.addObject(state.stack(), state.id(), this) + listener.addStack(state.stack, state.id, this) } isDirty = true @@ -98,33 +91,35 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor return copy } + @Suppress("unchecked_cast") override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T { + @Suppress("NAME_SHADOWING") var amount = amount - val get = storedByID[id] ?: return identity().empty() + val get = storedByID[id] ?: return storageType.empty if (amount <= ImpreciseFraction.ZERO) - amount = get.stack.getMaxStackSize().orElse(get.stack.count) + amount = get.stack.maxStackSize ?: get.stack.count amount = amount.min(get.stack.count) if (amount <= ImpreciseFraction.ZERO) - return identity().empty() + return storageType.empty val copy = get.stack.copy() as T copy.count = amount if (!simulate) { if (amount.compareTo(get.stack.count) == 0) { - val listing = storedStacks[get.stack.partitionKey()]!! + val listing = storedStacks[get.stack.partitionKey]!! listing.remove(get) storedDifferentStacks-- for (listener in listeners) { - listener.removeObject(get.id()) + listener.removeStack(get.id) } if (listing.size == 0) { - storedStacks.remove(get.stack.partitionKey()) + storedStacks.remove(get.stack.partitionKey) } } @@ -133,7 +128,7 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor if (!get.stack.count.isZero) { for (listener in listeners) { - listener.changeObject(get.id(), get.stack.count) + listener.changeStack(get.id, get.stack.count) } } @@ -160,7 +155,7 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor val serialized = serializeStack(stack) if (serialized != null) { - serialized["id"] = longArrayOf(stack.id().mostSignificantBits, stack.id().leastSignificantBits) + serialized["id"] = longArrayOf(stack.id.mostSignificantBits, stack.id.leastSignificantBits) list.add(serialized) } } @@ -191,19 +186,15 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor val id = entry.getLongArray("id") val tuple = StorageTuple(if (id.size == 2) UUID(id[0], id[1]) else UUID.randomUUID(), stack) - storedStacks.computeIfAbsent(stack.partitionKey()) { ArrayList() }.add(tuple) + storedStacks.computeIfAbsent(stack.partitionKey, Long2ObjectFunction { ArrayList() }).add(tuple) storedByID[tuple.id] = tuple } } } } - override fun storageIdentity(): Class { - return identity().identity() - } - override fun getStack(id: UUID): T { - return storedByID[id]?.stack ?: identity().empty() + return storedByID[id]?.stack ?: storageType.empty } override fun getStacks(): List> { @@ -221,7 +212,6 @@ abstract class AbstractMatteryDrive @JvmOverloads constructor return list } - @JvmField protected val listeners = HashSet>() override fun addListener(listener: IStorageListener): Boolean { 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 d46db09de..ad3d8e887 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 @@ -6,12 +6,12 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items import net.minecraftforge.registries.RegistryManager -import ru.dbotthepony.mc.otm.core.Fraction +import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.core.ImpreciseFraction 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.StorageObjectRegistry +import ru.dbotthepony.mc.otm.storage.StorageStackType import java.util.* class ItemMatteryDrive : AbstractMatteryDrive, IItemMatteryDrive { @@ -20,16 +20,15 @@ class ItemMatteryDrive : AbstractMatteryDrive, IItemMatteryDri constructor(capacity: ImpreciseFraction, uuid: UUID) : super(capacity, uuid) constructor(capacity: ImpreciseFraction) : super(capacity) - private val identity = StorageObjectRegistry.getOrError(ItemStackWrapper::class.java) - override fun identity() = identity + override val storageType: StorageStackType = OverdriveThatMatters.INSTANCE.ITEM_STORAGE() - fun insertObject(item: ItemStack, simulate: Boolean): ItemStack { + fun insertStack(item: ItemStack, simulate: Boolean): ItemStack { return insertStack(ItemStackWrapper(item), simulate).stack } override fun serializeStack(item: IStorageTuple): CompoundTag? { val tag = CompoundTag() - val location = item.stack().stack.item.registryName!!.toString() + val location = item.stack.stack.item.registryName!!.toString() tag["item"] = location tag["count"] = item.stack.stack.count @@ -57,12 +56,12 @@ class ItemMatteryDrive : AbstractMatteryDrive, IItemMatteryDri } override fun findItems(item: Item): List> { - val list = storedStacks[item] + val list = storedStacks[ItemStackWrapper.partitionKey(item)] return if (list != null) java.util.List.copyOf(list) else emptyList() } override fun findItems(stack: ItemStack): List> { - val list = storedStacks[stack.item] ?: return emptyList() + val list = storedStacks[ItemStackWrapper.partitionKey(stack.item)] ?: return emptyList() var amount = 0 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt index 652feb7c5..0b7152552 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/BasicStorageGraphNode.kt @@ -2,14 +2,15 @@ package ru.dbotthepony.mc.otm.graph.storage import net.minecraftforge.common.util.LazyOptional import ru.dbotthepony.mc.otm.graph.Graph6Node -import ru.dbotthepony.mc.otm.storage.IStorageIdentity +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 { private var resolver = LazyOptional.of { this } private var valid = true - protected val components = ArrayList>() + protected val components = ArrayList>() private val node = Graph6Node(this) @@ -17,25 +18,14 @@ open class BasicStorageGraphNode : IStorageGraphNode { return node } - override fun getComponents(): List> { + override fun fetchComponents(): List> { return Collections.unmodifiableList(components) } - fun > computeIfAbsent(identity: Class, provider: () -> U): U { + @Suppress("unchecked_cast") + fun > computeIfAbsent(identity: StorageStackType, provider: (StorageStackType) -> U): U { for (component in components) { - if (component.storageIdentity() == identity) { - return component as U - } - } - - val factory = provider() - addStorageComponent(factory) - return factory - } - - fun > computeIfAbsent(identity: Class, provider: (Class) -> U): U { - for (component in components) { - if (component.storageIdentity() == identity) { + if (component.storageType === identity) { return component as U } } @@ -45,25 +35,15 @@ open class BasicStorageGraphNode : IStorageGraphNode { return factory } - fun addStorageComponent(component: IStorageIdentity<*>) { + fun addStorageComponent(component: IStorage<*>) { for (component1 in components) { - if (component === component1 || component1.storageIdentity() == component.storageIdentity()) { + if (component === component1 || component1.storageType === component.storageType) { return } } components.add(component) - getStorageGraph()?.add(component) - } - - fun removeStorageComponent(component: IStorageIdentity<*>) { - for (component1 in components) { - if (component === component1 || component1.storageIdentity() == component.storageIdentity()) { - components.remove(component1) - getStorageGraph()?.remove(component) - return - } - } + storageGraph?.add(component) } fun invalidate() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt index 49f8eefef..5f71e9f11 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/IStorageGraphNode.kt @@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.graph.storage import net.minecraft.MethodsReturnNonnullByDefault import ru.dbotthepony.mc.otm.graph.Graph6Node -import ru.dbotthepony.mc.otm.storage.IStorageIdentity +import ru.dbotthepony.mc.otm.storage.IStorage import javax.annotation.ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault @@ -13,10 +13,10 @@ interface IStorageGraphNode { * * If you don't know what you are going to store, you may return nothing. * - * If something pops up, call [getStorageGraph], and then, call [StorageNetworkGraph.add]. + * If something pops up, call [storageGraph], and then, call [StorageNetworkGraph.add]. */ - fun getComponents(): Collection> + fun fetchComponents(): Collection> fun getAsStorageNode(): Graph6Node - fun getStorageGraph(): StorageNetworkGraph? = getAsStorageNode().graph as StorageNetworkGraph? + val storageGraph: StorageNetworkGraph? get() = getAsStorageNode().graph as StorageNetworkGraph? } 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 021db3c9e..f831c4ef3 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 @@ -1,44 +1,51 @@ package ru.dbotthepony.mc.otm.graph.storage +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap +import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.block.entity.BlockEntity 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.storage.IStorageIdentity -import ru.dbotthepony.mc.otm.storage.IStorageStack -import ru.dbotthepony.mc.otm.storage.VirtualComponent +import ru.dbotthepony.mc.otm.storage.* class StorageNetworkGraph : Abstract6Graph() { - private val virtualComponents = HashMap, VirtualComponent>() + private val virtualComponents = Object2ObjectArrayMap, VirtualComponent<*>>() - fun insertObject(type: Class, obj: T, simulate: Boolean): T { - return getVirtualComponent(type).insertStack(obj, simulate) + fun insertStack(obj: T, simulate: Boolean): T { + return (getVirtualComponent(StorageRegistry.get(obj::class.java)) as VirtualComponent).insertStack(obj, simulate) + } + + /** + * Returns a [VirtualComponent] representing [type] storage + */ + fun getVirtualComponent(type: StorageStackType): VirtualComponent { + return virtualComponents.computeIfAbsent(type, Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent } /** * Returns a [VirtualComponent] representing [type] storage */ fun getVirtualComponent(type: Class): VirtualComponent { - return virtualComponents.computeIfAbsent(type) { VirtualComponent(type) } as VirtualComponent + return virtualComponents.computeIfAbsent(StorageRegistry.get(type), Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent } - fun add(identity: IStorageIdentity) { - getVirtualComponent(identity.storageIdentity()).add(identity) + fun add(storage: IStorage) { + getVirtualComponent(storage.storageType).add(storage) } - fun remove(identity: IStorageIdentity) { - getVirtualComponent(identity.storageIdentity()).remove(identity) + fun remove(storage: IStorage) { + getVirtualComponent(storage.storageType).remove(storage) } override fun onNodeAdded(node: Graph6Node) { - for (identity in node.value.getComponents()) { + for (identity in node.value.fetchComponents()) { add(identity) } } override fun onNodeRemoved(node: Graph6Node) { - for (identity in node.value.getComponents()) { + for (identity in node.value.fetchComponents()) { remove(identity) } } 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 9b595dc18..05651f15e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt @@ -223,7 +223,7 @@ class PortableCondensationDriveItem(capacity: Int) : if (filter.matches(event.item.item)) { val copy = event.item.item.copy() - val remaining = (it as ItemMatteryDrive).insertObject(event.item.item, false) + val remaining = (it as ItemMatteryDrive).insertStack(event.item.item, false) if (remaining.count == event.item.item.count) { return@ifPresent 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 6852137f0..c26cc1a2e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt @@ -16,6 +16,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.PacketDistributor import org.lwjgl.glfw.GLFW +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 @@ -201,7 +202,7 @@ private fun getMatterValue(stack: ItemStack, level: Int): MatterTuple { val drive = stack.getCapability(MatteryCapability.DRIVE).orNull() - if (drive != null && drive.storageIdentity() === ItemStackWrapper.javaClass) { + if (drive != null && drive.storageType === OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) { for (item in (drive as IMatteryDrive).getStacks()) { val tuple = getMatterValue(item.stack.stack, level + 1) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/DriveViewerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/DriveViewerMenu.kt index 5d2dfea7f..33202da11 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/DriveViewerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/DriveViewerMenu.kt @@ -7,6 +7,7 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.minecraftforge.energy.CapabilityEnergy import net.minecraftforge.network.NetworkEvent +import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.block.entity.DriveViewerBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive @@ -70,7 +71,7 @@ class DriveViewerMenu @JvmOverloads constructor( if (!itemStack.isEmpty) { itemStack.getCapability(MatteryCapability.DRIVE).ifPresent { - if (it.storageIdentity() == ItemStackWrapper::class.java) { + if (it.storageType === OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) { lastDrive = it as IMatteryDrive } } @@ -123,7 +124,7 @@ class DriveViewerMenu @JvmOverloads constructor( if (remaining.count.toInt() == item.count) return ItemStack.EMPTY - if (remaining.isEmpty()) { + if (remaining.isEmpty) { val copy = item.copy() slot.set(ItemStack.EMPTY) return copy diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt index 0614b41bf..54a727b09 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.menu import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.block.entity.ItemMonitorBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier @@ -28,7 +29,7 @@ class ItemMonitorMenu @JvmOverloads constructor( init { if (tile != null) { - subscribed = tile.cell.getStorageGraph()!!.getVirtualComponent(ItemStackWrapper::class.java) + subscribed = tile.cell.storageGraph!!.getVirtualComponent(OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) local = PoweredVirtualComponent(subscribed, tile.getCapability(MatteryCapability.ENERGY).resolve().get()) view.setComponent(local) } else { 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 f0b696950..847dde066 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 @@ -77,8 +77,8 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: return state.values.size } - override fun addObject(stack: ItemStackWrapper, id: UUID, provider: IStorageView) = addObject(stack.stack, id) - override fun changeObject(id: UUID, newCount: ImpreciseFraction) = changeObject(id, newCount.toInt()) + override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageView) = addObject(stack.stack, id) + override fun changeStack(id: UUID, newCount: ImpreciseFraction) = changeObject(id, newCount.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 removeObject(id: UUID) { + override fun removeStack(id: UUID) { val get = upstream_state[id] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id!") upstream_state.remove(id) state.remove(get.id) @@ -162,7 +162,7 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: val extracted = provider.extractStack(state.upstreamId!!, amount, true) - if (!extracted.isEmpty()) { + if (!extracted.isEmpty) { val (_, remaining) = menu.quickMoveToInventory(extracted.stack, false) if (remaining.count != extracted.stack.count) { @@ -189,7 +189,7 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: val copy = menu.carried.copy() copy.count = 1 - if (provider.insertStack(ItemStackWrapper(copy), false).isEmpty()) { + if (provider.insertStack(ItemStackWrapper(copy), false).isEmpty) { menu.carried.shrink(1) 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 3456c4b5c..245459f11 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt @@ -2,46 +2,53 @@ package ru.dbotthepony.mc.otm.storage import ru.dbotthepony.mc.otm.core.ImpreciseFraction import java.util.* +import net.minecraftforge.registries.ForgeRegistry interface IStorageStack { fun copy(): IStorageStack var count: ImpreciseFraction - fun isEmpty(): Boolean + val isEmpty: Boolean /** - * @return max stack size for this stack object - * [Optional.empty()] if unlimited (default) + * @return max stack size for this stack object, + * null if unlimited (default) */ - fun getMaxStackSize(): Optional = Optional.empty() + val maxStackSize: ImpreciseFraction? get() = null /** - * Returns Identity utilized to partition view table (if it has any). - * Defaults to no partitioning; meaning performance will degrade much quicker than it should. - * Good object is an object that will influence on [sameItem] return result, making it return true. - * It is strictly considered that if !this.itemIdentity().equals(other.itemIdentity); - * then this.sameItem(other) will never return true. + * This property represent (almost) unique key used to quickly look up for similar stacks. + * Semantic is very similar, but not equal, to [hashCode] of object. This property **must** be equal for two + * entries if [sameItem] returns true. This value should not change. * - * If implemented, and storage is also partitioned properly, then performance will be flat equally to view table's performance. + * A good example of key is [ForgeRegistry.getID]. * - * Example: ItemStack#item + * Collisions are solved as in open hash map, with linear scan for required item. */ - fun partitionKey(): Any { - return Any::class.java - } + val partitionKey: Long /** - * [other] other object to compare; if not the same of this object type just return false - * Returns boolean representing whenever internal state of [this] equals to [other]; - * this include tags, mapping IDs, capabilities, **excluding** amount; - * behavior is pretty much the same as ItemStack.isSameItemSameTags + * [other] is the stack to compare. + * + * If not the same of this object type just return false + * Returns boolean representing whenever internal state of *this* equals to [other]; + * + * This includes (nbt) tags, mapping IDs, capabilities, **excluding** amount; + * + * Example of this behavior is demonstrated by ItemStack.isSameItemSameTags. */ fun sameItem(other: IStorageStack): Boolean + /** + * Increase [count] by [amount] + */ fun grow(amount: ImpreciseFraction) { count += amount } + /** + * Decrease [count] by [amount] + */ fun shrink(amount: ImpreciseFraction) { count -= amount } @@ -50,11 +57,14 @@ interface IStorageStack { /** * Storage system root, along IStorageStack interface */ -interface IStorageIdentity { - fun storageIdentity(): Class +interface IStorage { + /** + * @return Identity of this virtual component + */ + val storageType: StorageStackType } -interface IStorageTrigger : IStorageIdentity { +interface IStorageTrigger : IStorage { /** * [listener] is [IStorageListener] which want to subscribe to our events */ @@ -66,19 +76,23 @@ interface IStorageTrigger : IStorageIdentity { fun removeListener(listener: IStorageListener): Boolean } -interface IStorageConsumer : IStorageIdentity { +interface IStorageConsumer : IStorage { + /** + * Inserts an item into system. + * @return leftover, might equal to [stack] if no items were inserted + */ fun insertStack(stack: T, simulate: Boolean): T } interface IStorageView : IStorageTrigger { /** - * @param id identifier of object + * @param id identifier of stack * @return stored object (not a copy). Do not edit it. */ fun getStack(id: UUID): T /** - * @param id identifier of object to extract + * @param id identifier of stack to extract * @param amount amount of units to extract * @param simulate whenever to simulate the action or not * @return copy of object, with amount of units actually extracted @@ -89,9 +103,9 @@ interface IStorageView : IStorageTrigger { /** * Designed for views, for extraction with less computation overhead caused by - * copying object extracted + * copying stack extracted * - * @param id identifier of object to extract + * @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 @@ -108,7 +122,7 @@ interface IStorageView : IStorageTrigger { fun addListenerAuto(listener: IStorageListener): Boolean { if (addListener(listener)) { for (stack in getStacks()) { - listener.addObject(stack.stack(), stack.id(), this) + listener.addStack(stack.stack, stack.id, this) } return true @@ -120,7 +134,7 @@ interface IStorageView : IStorageTrigger { fun removeListenerAuto(listener: IStorageListener): Boolean { if (removeListener(listener)) { for (stack in getStacks()) { - listener.removeObject(stack.id()) + listener.removeStack(stack.id) } return true @@ -134,38 +148,23 @@ interface IStorageListener { /** * Fired on whenever an object is added (to listener) we subscribed to */ - fun addObject(stack: T, id: UUID, provider: IStorageView) + fun addStack(stack: T, id: UUID, provider: IStorageView) /** * Fired on whenever an object is changes on listener we subscribed to */ - fun changeObject(id: UUID, newCount: ImpreciseFraction) + fun changeStack(id: UUID, newCount: ImpreciseFraction) /** * Fired on whenever an object is removed from listener we subscribed to */ - fun removeObject(id: UUID) + fun removeStack(id: UUID) } interface IStorageTuple { val id: UUID - get() = id() - val stack: T - get() = stack() - - fun id(): UUID - fun stack(): T -} - -data class StorageTuple(override val id: UUID, override val stack: T) : IStorageTuple { - override fun id(): UUID { - return id - } - - override fun stack(): T { - return stack - } } +class StorageTuple(override val id: UUID, override val stack: T) : IStorageTuple interface IStorageComponent : IStorageView, IStorageConsumer 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 2a813dd09..2dcf73036 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt @@ -1,39 +1,37 @@ package ru.dbotthepony.mc.otm.storage +import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack -import ru.dbotthepony.mc.otm.core.Fraction +import net.minecraftforge.registries.ForgeRegistries +import net.minecraftforge.registries.ForgeRegistry import ru.dbotthepony.mc.otm.core.ImpreciseFraction -import java.util.* -@JvmRecord -data class ItemStackWrapper(val stack: ItemStack) : IStorageStack { +class ItemStackWrapper(val stack: ItemStack) : IStorageStack { + operator fun component1() = stack + override fun copy(): IStorageStack { return ItemStackWrapper(stack.copy()) } fun setCount(value: Int) { - stack.count = Math.max(value, 0) + stack.count = value.coerceAtLeast(0) } override var count: ImpreciseFraction get() = ImpreciseFraction(stack.count) set(value) = setCount(value.toInt()) - fun getCountInt() = stack.count + override val maxStackSize get() = ImpreciseFraction(stack.maxStackSize) - override fun getMaxStackSize(): Optional { - return Optional.of(ImpreciseFraction(stack.maxStackSize)) - } - - override fun isEmpty(): Boolean = stack.isEmpty - override fun partitionKey(): Any = stack.item + override val isEmpty: Boolean = stack.isEmpty + override val partitionKey: Long = partitionKey(stack.item) override fun sameItem(other: IStorageStack): Boolean { if (this === other) return true if (other is ItemStackWrapper) - return ItemStack.isSameItemSameTags(stack, other.stack); + return ItemStack.isSameItemSameTags(stack, other.stack) return false } @@ -41,5 +39,7 @@ data class ItemStackWrapper(val stack: ItemStack) : IStorageStack { companion object { @JvmField val EMPTY = ItemStackWrapper(ItemStack.EMPTY) + + fun partitionKey(item: Item) = (ForgeRegistries.ITEMS as ForgeRegistry?)?.getID(item)?.toLong() ?: System.identityHashCode(item).toLong() } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt new file mode 100644 index 000000000..30345ea1e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt @@ -0,0 +1,50 @@ +package ru.dbotthepony.mc.otm.storage + +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import java.util.IdentityHashMap + +open class StorageStackType( + val identity: Class, + open val empty: T, + + /** + * Speculated energy required per operation on stack with size of 1 + */ + open val energyPerOperation: ImpreciseFraction +) { + open fun energyPerOperation(stack: T): ImpreciseFraction { + return stack.count * energyPerOperation + } + + open fun energyPerStorage(stack: T) = energyPerOperation(stack) + open fun energyPerExtraction(stack: T) = energyPerOperation(stack) + open fun energyForUpkeep(stack: T) = ImpreciseFraction.ZERO +} + +@Suppress("unchecked_cast") +object StorageRegistry { + private val REGISTRY = IdentityHashMap, StorageStackType<*>>() + + @JvmStatic + fun register(type: StorageStackType<*>): StorageStackType<*> { + check(!REGISTRY.containsKey(type.identity)) { "Already have storage stack type for ${type.identity}" } + REGISTRY[type.identity] = type + return type + } + + @JvmStatic + fun register(identity: Class, empty: T, energyPerOperation: ImpreciseFraction): StorageStackType { + return register(StorageStackType(identity, empty, energyPerOperation)) as StorageStackType + } + + @JvmStatic + fun get(identity: Class): StorageStackType { + val get = REGISTRY[identity] ?: throw NoSuchElementException("Registry does not contain $identity") + return get as StorageStackType + } + + @JvmStatic + fun getOrNull(identity: Class): StorageStackType? { + return REGISTRY[identity] as StorageStackType? + } +} 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 a3e5ac8ab..db64f2cf4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/VirtualComponent.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/VirtualComponent.kt @@ -1,7 +1,9 @@ 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 ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction import java.util.* @@ -23,45 +25,27 @@ class RemoteTuple(val obj: T, val remote_id: UUID, val provid } } -class LocalTuple(override val stack: T, override val id: UUID, val tuples: ArrayList>) : IStorageTuple { - override fun id(): UUID { - return id - } +class LocalTuple(override val stack: T, override val id: UUID, val tuples: ArrayList>) : IStorageTuple - override fun stack(): T { - return stack - } -} +open class VirtualComponent(type: StorageStackType) : IStorageComponent, IStorageListener { + constructor(type: Class) : this(StorageRegistry.get(type)) -open class VirtualComponent(identity: Class) : IStorageComponent, IStorageListener { - @JvmField - protected val identity: StorageObjectTuple - final override fun storageIdentity() = identity.identity() - - init { - this.identity = StorageObjectRegistry.getOrError(identity) - } + override val storageType: StorageStackType = type // удаленный UUID -> Кортеж - @JvmField - protected val remoteByUUID = HashMap>() + protected val remoteByUUID = Object2ObjectAVLTreeMap>() // локальный UUID -> Локальный кортеж - @JvmField - protected val localByUUID = HashMap>() + protected val localByUUID = Object2ObjectAVLTreeMap>() - // Хеш ключ -> Список Локальных кортежей - @JvmField - protected val partitions = HashMap>>() + // ключ -> Список Локальных кортежей + protected val partitions = Long2ObjectAVLTreeMap>>() // ArrayList для скорости работы - @JvmField protected val listeners = ArrayList>() - - @JvmField protected val consumers = ArrayList>() - open fun add(identity: IStorageIdentity) { + open fun add(identity: IStorage) { if (identity is IStorageView) { identity.addListenerAuto(this) } else if (identity is IStorageTrigger) { @@ -69,11 +53,11 @@ open class VirtualComponent(identity: Class) : IStorageCom } if (identity is IStorageConsumer && !consumers.contains(identity)) { - consumers.add(identity); + consumers.add(identity) } } - open fun remove(identity: IStorageIdentity) { + open fun remove(identity: IStorage) { if (identity is IStorageView) { identity.removeListenerAuto(this) } else if (identity is IStorageTrigger) { @@ -99,7 +83,7 @@ open class VirtualComponent(identity: Class) : IStorageCom } override fun getStack(id: UUID): T { - return localByUUID[id]?.stack ?: identity.empty + return localByUUID[id]?.stack ?: this.storageType.empty } override fun getStacks(): List> { @@ -110,9 +94,10 @@ open class VirtualComponent(identity: Class) : IStorageCom return output } - override fun addObject(stack: T, id: UUID, provider: IStorageView) { + @Suppress("unchecked_cast") + override fun addStack(stack: T, id: UUID, provider: IStorageView) { check(!remoteByUUID.containsKey(id)) { "Already tracking tuple with id $id" } - val items = partitions.computeIfAbsent(stack.partitionKey()) { ArrayList() } + val items = partitions.computeIfAbsent(stack.partitionKey, Long2ObjectFunction { ArrayList() }) var local: LocalTuple? = null for (item in items) { @@ -137,16 +122,16 @@ open class VirtualComponent(identity: Class) : IStorageCom if (added) { for (listener in listeners) { - listener.addObject(local.stack, local.id, this) + listener.addStack(local.stack, local.id, this) } } else { for (listener in listeners) { - listener.changeObject(local.id, local.stack.count) + listener.changeStack(local.id, local.stack.count) } } } - override fun changeObject(id: UUID, newCount: ImpreciseFraction) { + override fun changeStack(id: UUID, newCount: ImpreciseFraction) { assert(newCount > ImpreciseFraction.ZERO) val tuple = remoteByUUID[id] ?: throw IllegalStateException("No such tuple with id $id") @@ -155,13 +140,13 @@ open class VirtualComponent(identity: Class) : IStorageCom tuple.local.stack.grow(diff) for (listener in listeners) { - listener.changeObject(tuple.local.id, tuple.local.stack.count) + listener.changeStack(tuple.local.id, tuple.local.stack.count) } } - override fun removeObject(id: UUID) { + override fun removeStack(id: UUID) { val tuple = remoteByUUID[id] ?: throw IllegalStateException("No such tuple with id $id") - val key = tuple.local.stack.partitionKey() + val key = tuple.local.stack.partitionKey tuple.local.stack.shrink(tuple.obj.count) tuple.local.tuples.remove(tuple) @@ -177,7 +162,7 @@ open class VirtualComponent(identity: Class) : IStorageCom partitions[key]!!.remove(tuple.local) for (listener in listeners) { - listener.removeObject(tuple.local.id) + listener.removeStack(tuple.local.id) } } } @@ -188,7 +173,7 @@ open class VirtualComponent(identity: Class) : IStorageCom for (consumer in consumers) { leftover = consumer.insertStack(leftover, simulate) - if (leftover.isEmpty()) { + if (leftover.isEmpty) { return leftover } } @@ -196,18 +181,20 @@ open class VirtualComponent(identity: Class) : IStorageCom return leftover } + @Suppress("unchecked_cast") override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T { if (amount.isZero) - return identity.empty + return this.storageType.empty + @Suppress("name_shadowing") var amount = amount val tuple: LocalTuple? = localByUUID[id] if (tuple == null || amount.isZero) - return identity.empty + return this.storageType.empty if (amount <= ImpreciseFraction.MINUS_ONE) - amount = tuple.stack.getMaxStackSize().orElse(tuple.stack.count) + amount = tuple.stack.maxStackSize ?: tuple.stack.count val toExtract = tuple.stack.count.min(amount) var extracted = ImpreciseFraction.ZERO @@ -225,19 +212,21 @@ open class VirtualComponent(identity: Class) : IStorageCom return copy } - return identity.empty() + return this.storageType.empty } } -open class PoweredVirtualComponent(identity: Class, @JvmField val energyProvider: () -> IMatteryEnergyStorage) : VirtualComponent(identity) { - constructor(identity: Class, energyStorage: IMatteryEnergyStorage) : this(identity, {energyStorage}) - constructor(other: VirtualComponent, energyStorage: IMatteryEnergyStorage) : this(other.storageIdentity(), energyStorage) { +open class PoweredVirtualComponent(type: StorageStackType, val energyProvider: () -> IMatteryEnergyStorage) : VirtualComponent(type) { + constructor(type: Class, energyStorage: IMatteryEnergyStorage) : this(StorageRegistry.get(type), {energyStorage}) + constructor(type: StorageStackType, energyStorage: IMatteryEnergyStorage) : this(type, {energyStorage}) + constructor(other: VirtualComponent, energyStorage: IMatteryEnergyStorage) : this(other.storageType.identity, energyStorage) { add(other) } + @Suppress("unchecked_cast") override fun insertStack(stack: T, simulate: Boolean): T { - val required = identity.energyPerOperation * stack.count - val energy = energyProvider() + val required = storageType.energyPerOperation * stack.count + val energy = energyProvider.invoke() val extracted = energy.extractEnergyInner(required, true) if (extracted.isZero) { @@ -247,7 +236,7 @@ open class PoweredVirtualComponent(identity: Class, @JvmFi if (extracted == required) { val leftover = super.insertStack(stack, simulate) - if (leftover.isEmpty()) { + if (leftover.isEmpty) { if (!simulate) { energy.extractEnergyInner(required, false) } @@ -256,24 +245,25 @@ open class PoweredVirtualComponent(identity: Class, @JvmFi } if (!simulate) { - val requiredNew = identity.energyPerOperation * stack.count - leftover.count + val requiredNew = storageType.energyPerOperation * stack.count - leftover.count energy.extractEnergyInner(requiredNew, false) } return leftover } + @Suppress("name_shadowing") val stack = stack.copy() as T val oldCount = stack.count - stack.count = extracted / identity.energyPerOperation + stack.count = extracted / storageType.energyPerOperation val diff = oldCount - stack.count - val newRequired = identity.energyPerOperation * stack.count + val newRequired = storageType.energyPerOperation * stack.count val newExtracted = energy.extractEnergyInner(newRequired, true) if (newExtracted == newRequired) { val leftover = super.insertStack(stack, simulate) - if (leftover.isEmpty()) { + if (leftover.isEmpty) { if (!simulate) { energy.extractEnergyInner(newRequired, false) } @@ -283,7 +273,7 @@ open class PoweredVirtualComponent(identity: Class, @JvmFi } if (!simulate) { - val requiredNew = (stack.count - leftover.count) * identity.energyPerOperation + val requiredNew = (stack.count - leftover.count) * storageType.energyPerOperation energy.extractEnergyInner(requiredNew, false) } @@ -295,18 +285,18 @@ open class PoweredVirtualComponent(identity: Class, @JvmFi } override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T { - val required = identity.energyPerOperation * amount - val energy = energyProvider() + val required = storageType.energyPerOperation * amount + val energy = energyProvider.invoke() val extracted = energy.extractEnergyInner(required, true) if (extracted.isZero) { - return identity.empty + return storageType.empty } if (extracted == required) { val extractedStack = super.extractStack(id, amount, simulate) - if (extractedStack.isEmpty()) { + if (extractedStack.isEmpty) { return extractedStack } @@ -314,22 +304,23 @@ open class PoweredVirtualComponent(identity: Class, @JvmFi if (extractedStack.count == amount) { energy.extractEnergyInner(required, false) } else { - energy.extractEnergyInner(extractedStack.count * identity.energyPerOperation, false) + energy.extractEnergyInner(extractedStack.count * storageType.energyPerOperation, false) } } return extractedStack } - val amount = required / identity.energyPerOperation + @Suppress("name_shadowing") + val amount = required / storageType.energyPerOperation val extractedStack = super.extractStack(id, amount, simulate) - if (extractedStack.isEmpty()) { + if (extractedStack.isEmpty) { return extractedStack } if (!simulate) { - energy.extractEnergyInner(extractedStack.count * identity.energyPerOperation, false) + energy.extractEnergyInner(extractedStack.count * storageType.energyPerOperation, false) } return extractedStack