Iterate storage system design once again
This commit is contained in:
parent
da7be875d5
commit
398105f067
@ -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<ItemStackWrapper> ITEM_STORAGE;
|
||||
private StorageStackType<ItemStackWrapper> ITEM_STORAGE;
|
||||
|
||||
public StorageStackType<ItemStackWrapper> 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) {
|
||||
|
@ -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<Class<? extends IStorageStack>, StorageObjectTuple<? extends IStorageStack>> REGISTRY = new HashMap<>();
|
||||
|
||||
public static <T extends IStorageStack> StorageObjectTuple<T> register(Class<T> identity, T empty, ImpreciseFraction energyPerOperation) {
|
||||
final var tuple = new StorageObjectTuple<>(identity, empty, energyPerOperation);
|
||||
REGISTRY.put(identity, tuple);
|
||||
return tuple;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public static <T extends IStorageStack> StorageObjectTuple<T> get(Class<T> identity) {
|
||||
return (StorageObjectTuple<T>) REGISTRY.get(identity);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static <T extends IStorageStack> StorageObjectTuple<T> getOrError(Class<T> identity) {
|
||||
return Objects.requireNonNull(get(identity), "No storage mapping present for " + identity);
|
||||
}
|
||||
}
|
@ -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<T extends IStorageStack>(@Nonnull Class<T> 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();
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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<T : IStorageStack> @JvmOverloads constructor(
|
||||
override var driveCapacity: ImpreciseFraction,
|
||||
override val uuid: UUID = UUID.randomUUID(),
|
||||
var maxDifferentStacks: Int = 0xFFFF
|
||||
) : IMatteryDrive<T> {
|
||||
protected val storedStacks = Long2ObjectAVLTreeMap<MutableList<IStorageTuple<T>>>()
|
||||
protected val storedByID = Object2ObjectAVLTreeMap<UUID, IStorageTuple<T>>()
|
||||
|
||||
@JvmField
|
||||
protected val storedStacks = HashMap<Any, MutableList<IStorageTuple<T>>>()
|
||||
|
||||
@JvmField
|
||||
protected val storedByID = HashMap<UUID, IStorageTuple<T>>()
|
||||
abstract fun identity(): StorageObjectTuple<T>
|
||||
override var isDirty = false
|
||||
set(value) {
|
||||
if (value != field && value && DrivePool.isLegalAccess()) {
|
||||
@ -42,24 +33,26 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @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<T : IStorageStack> @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<T : IStorageStack> @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<T : IStorageStack> @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<T : IStorageStack> @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<T : IStorageStack> @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<T> {
|
||||
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<IStorageTuple<T>> {
|
||||
@ -221,7 +212,6 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmField
|
||||
protected val listeners = HashSet<IStorageListener<T>>()
|
||||
|
||||
override fun addListener(listener: IStorageListener<T>): Boolean {
|
||||
|
@ -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<ItemStackWrapper>, IItemMatteryDrive {
|
||||
@ -20,16 +20,15 @@ class ItemMatteryDrive : AbstractMatteryDrive<ItemStackWrapper>, 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<ItemStackWrapper> = 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<ItemStackWrapper>): 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<ItemStackWrapper>, IItemMatteryDri
|
||||
}
|
||||
|
||||
override fun findItems(item: Item): List<IStorageTuple<ItemStackWrapper>> {
|
||||
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<IStorageTuple<ItemStackWrapper>> {
|
||||
val list = storedStacks[stack.item] ?: return emptyList()
|
||||
val list = storedStacks[ItemStackWrapper.partitionKey(stack.item)] ?: return emptyList()
|
||||
|
||||
var amount = 0
|
||||
|
||||
|
@ -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<IStorageGraphNode> { this }
|
||||
private var valid = true
|
||||
protected val components = ArrayList<IStorageIdentity<*>>()
|
||||
protected val components = ArrayList<IStorage<*>>()
|
||||
|
||||
private val node = Graph6Node<IStorageGraphNode>(this)
|
||||
|
||||
@ -17,25 +18,14 @@ open class BasicStorageGraphNode : IStorageGraphNode {
|
||||
return node
|
||||
}
|
||||
|
||||
override fun getComponents(): List<IStorageIdentity<*>> {
|
||||
override fun fetchComponents(): List<IStorage<*>> {
|
||||
return Collections.unmodifiableList(components)
|
||||
}
|
||||
|
||||
fun <T : IStorageStack, U : IStorageIdentity<T>> computeIfAbsent(identity: Class<T>, provider: () -> U): U {
|
||||
@Suppress("unchecked_cast")
|
||||
fun <T : IStorageStack, U : IStorage<T>> computeIfAbsent(identity: StorageStackType<T>, provider: (StorageStackType<T>) -> U): U {
|
||||
for (component in components) {
|
||||
if (component.storageIdentity() == identity) {
|
||||
return component as U
|
||||
}
|
||||
}
|
||||
|
||||
val factory = provider()
|
||||
addStorageComponent(factory)
|
||||
return factory
|
||||
}
|
||||
|
||||
fun <T : IStorageStack, U : IStorageIdentity<T>> computeIfAbsent(identity: Class<T>, provider: (Class<T>) -> 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() {
|
||||
|
@ -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<IStorageIdentity<*>>
|
||||
fun fetchComponents(): Collection<IStorage<*>>
|
||||
|
||||
fun getAsStorageNode(): Graph6Node<IStorageGraphNode>
|
||||
fun getStorageGraph(): StorageNetworkGraph? = getAsStorageNode().graph as StorageNetworkGraph?
|
||||
val storageGraph: StorageNetworkGraph? get() = getAsStorageNode().graph as StorageNetworkGraph?
|
||||
}
|
||||
|
@ -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<IStorageGraphNode>() {
|
||||
private val virtualComponents = HashMap<Class<out IStorageStack>, VirtualComponent<out IStorageStack>>()
|
||||
private val virtualComponents = Object2ObjectArrayMap<StorageStackType<*>, VirtualComponent<*>>()
|
||||
|
||||
fun <T : IStorageStack> insertObject(type: Class<T>, obj: T, simulate: Boolean): T {
|
||||
return getVirtualComponent(type).insertStack(obj, simulate)
|
||||
fun <T : IStorageStack> insertStack(obj: T, simulate: Boolean): T {
|
||||
return (getVirtualComponent(StorageRegistry.get(obj::class.java)) as VirtualComponent<T>).insertStack(obj, simulate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [VirtualComponent] representing [type] storage
|
||||
*/
|
||||
fun <T : IStorageStack> getVirtualComponent(type: StorageStackType<T>): VirtualComponent<T> {
|
||||
return virtualComponents.computeIfAbsent(type, Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [VirtualComponent] representing [type] storage
|
||||
*/
|
||||
fun <T : IStorageStack> getVirtualComponent(type: Class<T>): VirtualComponent<T> {
|
||||
return virtualComponents.computeIfAbsent(type) { VirtualComponent(type) } as VirtualComponent<T>
|
||||
return virtualComponents.computeIfAbsent(StorageRegistry.get(type), Object2ObjectFunction { VirtualComponent(type) }) as VirtualComponent<T>
|
||||
}
|
||||
|
||||
fun <T : IStorageStack> add(identity: IStorageIdentity<T>) {
|
||||
getVirtualComponent(identity.storageIdentity()).add(identity)
|
||||
fun <T : IStorageStack> add(storage: IStorage<T>) {
|
||||
getVirtualComponent(storage.storageType).add(storage)
|
||||
}
|
||||
|
||||
fun <T : IStorageStack> remove(identity: IStorageIdentity<T>) {
|
||||
getVirtualComponent(identity.storageIdentity()).remove(identity)
|
||||
fun <T : IStorageStack> remove(storage: IStorage<T>) {
|
||||
getVirtualComponent(storage.storageType).remove(storage)
|
||||
}
|
||||
|
||||
override fun onNodeAdded(node: Graph6Node<IStorageGraphNode>) {
|
||||
for (identity in node.value.getComponents()) {
|
||||
for (identity in node.value.fetchComponents()) {
|
||||
add(identity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) {
|
||||
for (identity in node.value.getComponents()) {
|
||||
for (identity in node.value.fetchComponents()) {
|
||||
remove(identity)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<ItemStackWrapper>).getStacks()) {
|
||||
val tuple = getMatterValue(item.stack.stack, level + 1)
|
||||
|
||||
|
@ -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<ItemStackWrapper>
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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<ItemStackWrapper>) = addObject(stack.stack, id)
|
||||
override fun changeObject(id: UUID, newCount: ImpreciseFraction) = changeObject(id, newCount.toInt())
|
||||
override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageView<ItemStackWrapper>) = addObject(stack.stack, id)
|
||||
override fun changeStack(id: UUID, newCount: ImpreciseFraction) = changeObject(id, newCount.toInt())
|
||||
|
||||
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())
|
||||
|
@ -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<ImpreciseFraction> = 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<T : IStorageStack> {
|
||||
fun storageIdentity(): Class<T>
|
||||
interface IStorage<T : IStorageStack> {
|
||||
/**
|
||||
* @return Identity of this virtual component
|
||||
*/
|
||||
val storageType: StorageStackType<T>
|
||||
}
|
||||
|
||||
interface IStorageTrigger<T : IStorageStack> : IStorageIdentity<T> {
|
||||
interface IStorageTrigger<T : IStorageStack> : IStorage<T> {
|
||||
/**
|
||||
* [listener] is [IStorageListener] which want to subscribe to our events
|
||||
*/
|
||||
@ -66,19 +76,23 @@ interface IStorageTrigger<T : IStorageStack> : IStorageIdentity<T> {
|
||||
fun removeListener(listener: IStorageListener<T>): Boolean
|
||||
}
|
||||
|
||||
interface IStorageConsumer<T : IStorageStack> : IStorageIdentity<T> {
|
||||
interface IStorageConsumer<T : IStorageStack> : IStorage<T> {
|
||||
/**
|
||||
* 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<T : IStorageStack> : IStorageTrigger<T> {
|
||||
/**
|
||||
* @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<T : IStorageStack> : IStorageTrigger<T> {
|
||||
|
||||
/**
|
||||
* 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<T : IStorageStack> : IStorageTrigger<T> {
|
||||
fun addListenerAuto(listener: IStorageListener<T>): 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<T : IStorageStack> : IStorageTrigger<T> {
|
||||
fun removeListenerAuto(listener: IStorageListener<T>): Boolean {
|
||||
if (removeListener(listener)) {
|
||||
for (stack in getStacks()) {
|
||||
listener.removeObject(stack.id())
|
||||
listener.removeStack(stack.id)
|
||||
}
|
||||
|
||||
return true
|
||||
@ -134,38 +148,23 @@ interface IStorageListener<T : IStorageStack> {
|
||||
/**
|
||||
* Fired on whenever an object is added (to listener) we subscribed to
|
||||
*/
|
||||
fun addObject(stack: T, id: UUID, provider: IStorageView<T>)
|
||||
fun addStack(stack: T, id: UUID, provider: IStorageView<T>)
|
||||
|
||||
/**
|
||||
* 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<T : IStorageStack> {
|
||||
val id: UUID
|
||||
get() = id()
|
||||
|
||||
val stack: T
|
||||
get() = stack()
|
||||
|
||||
fun id(): UUID
|
||||
fun stack(): T
|
||||
}
|
||||
|
||||
data class StorageTuple<T : IStorageStack>(override val id: UUID, override val stack: T) : IStorageTuple<T> {
|
||||
override fun id(): UUID {
|
||||
return id
|
||||
}
|
||||
|
||||
override fun stack(): T {
|
||||
return stack
|
||||
}
|
||||
}
|
||||
|
||||
class StorageTuple<T : IStorageStack>(override val id: UUID, override val stack: T) : IStorageTuple<T>
|
||||
interface IStorageComponent<T : IStorageStack> : IStorageView<T>, IStorageConsumer<T>
|
||||
|
@ -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<ImpreciseFraction> {
|
||||
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<Item>?)?.getID(item)?.toLong() ?: System.identityHashCode(item).toLong()
|
||||
}
|
||||
}
|
||||
|
50
src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt
Normal file
50
src/main/kotlin/ru/dbotthepony/mc/otm/storage/Registry.kt
Normal file
@ -0,0 +1,50 @@
|
||||
package ru.dbotthepony.mc.otm.storage
|
||||
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import java.util.IdentityHashMap
|
||||
|
||||
open class StorageStackType<T : IStorageStack>(
|
||||
val identity: Class<T>,
|
||||
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<Class<*>, 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 <T : IStorageStack> register(identity: Class<T>, empty: T, energyPerOperation: ImpreciseFraction): StorageStackType<T> {
|
||||
return register(StorageStackType(identity, empty, energyPerOperation)) as StorageStackType<T>
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <T : IStorageStack> get(identity: Class<T>): StorageStackType<T> {
|
||||
val get = REGISTRY[identity] ?: throw NoSuchElementException("Registry does not contain $identity")
|
||||
return get as StorageStackType<T>
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <T : IStorageStack> getOrNull(identity: Class<T>): StorageStackType<T>? {
|
||||
return REGISTRY[identity] as StorageStackType<T>?
|
||||
}
|
||||
}
|
@ -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<T : IStorageStack>(val obj: T, val remote_id: UUID, val provid
|
||||
}
|
||||
}
|
||||
|
||||
class LocalTuple<T : IStorageStack>(override val stack: T, override val id: UUID, val tuples: ArrayList<RemoteTuple<T>>) : IStorageTuple<T> {
|
||||
override fun id(): UUID {
|
||||
return id
|
||||
}
|
||||
class LocalTuple<T : IStorageStack>(override val stack: T, override val id: UUID, val tuples: ArrayList<RemoteTuple<T>>) : IStorageTuple<T>
|
||||
|
||||
override fun stack(): T {
|
||||
return stack
|
||||
}
|
||||
}
|
||||
open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : IStorageComponent<T>, IStorageListener<T> {
|
||||
constructor(type: Class<T>) : this(StorageRegistry.get(type))
|
||||
|
||||
open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageComponent<T>, IStorageListener<T> {
|
||||
@JvmField
|
||||
protected val identity: StorageObjectTuple<T>
|
||||
final override fun storageIdentity() = identity.identity()
|
||||
|
||||
init {
|
||||
this.identity = StorageObjectRegistry.getOrError(identity)
|
||||
}
|
||||
override val storageType: StorageStackType<T> = type
|
||||
|
||||
// удаленный UUID -> Кортеж
|
||||
@JvmField
|
||||
protected val remoteByUUID = HashMap<UUID, RemoteTuple<T>>()
|
||||
protected val remoteByUUID = Object2ObjectAVLTreeMap<UUID, RemoteTuple<T>>()
|
||||
|
||||
// локальный UUID -> Локальный кортеж
|
||||
@JvmField
|
||||
protected val localByUUID = HashMap<UUID, LocalTuple<T>>()
|
||||
protected val localByUUID = Object2ObjectAVLTreeMap<UUID, LocalTuple<T>>()
|
||||
|
||||
// Хеш ключ -> Список Локальных кортежей
|
||||
@JvmField
|
||||
protected val partitions = HashMap<Any, ArrayList<LocalTuple<T>>>()
|
||||
// ключ -> Список Локальных кортежей
|
||||
protected val partitions = Long2ObjectAVLTreeMap<ArrayList<LocalTuple<T>>>()
|
||||
|
||||
// ArrayList для скорости работы
|
||||
@JvmField
|
||||
protected val listeners = ArrayList<IStorageListener<T>>()
|
||||
|
||||
@JvmField
|
||||
protected val consumers = ArrayList<IStorageConsumer<T>>()
|
||||
|
||||
open fun add(identity: IStorageIdentity<T>) {
|
||||
open fun add(identity: IStorage<T>) {
|
||||
if (identity is IStorageView<T>) {
|
||||
identity.addListenerAuto(this)
|
||||
} else if (identity is IStorageTrigger<T>) {
|
||||
@ -69,11 +53,11 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
||||
}
|
||||
|
||||
if (identity is IStorageConsumer<T> && !consumers.contains(identity)) {
|
||||
consumers.add(identity);
|
||||
consumers.add(identity)
|
||||
}
|
||||
}
|
||||
|
||||
open fun remove(identity: IStorageIdentity<T>) {
|
||||
open fun remove(identity: IStorage<T>) {
|
||||
if (identity is IStorageView<T>) {
|
||||
identity.removeListenerAuto(this)
|
||||
} else if (identity is IStorageTrigger<T>) {
|
||||
@ -99,7 +83,7 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
||||
}
|
||||
|
||||
override fun getStack(id: UUID): T {
|
||||
return localByUUID[id]?.stack ?: identity.empty
|
||||
return localByUUID[id]?.stack ?: this.storageType.empty
|
||||
}
|
||||
|
||||
override fun getStacks(): List<IStorageTuple<T>> {
|
||||
@ -110,9 +94,10 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
||||
return output
|
||||
}
|
||||
|
||||
override fun addObject(stack: T, id: UUID, provider: IStorageView<T>) {
|
||||
@Suppress("unchecked_cast")
|
||||
override fun addStack(stack: T, id: UUID, provider: IStorageView<T>) {
|
||||
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<T>? = null
|
||||
|
||||
for (item in items) {
|
||||
@ -137,16 +122,16 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : 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<T : IStorageStack>(identity: Class<T>) : 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<T : IStorageStack>(identity: Class<T>) : 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<T : IStorageStack>(identity: Class<T>) : 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<T : IStorageStack>(identity: Class<T>) : 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<T>? = 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<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
||||
return copy
|
||||
}
|
||||
|
||||
return identity.empty()
|
||||
return this.storageType.empty
|
||||
}
|
||||
}
|
||||
|
||||
open class PoweredVirtualComponent<T : IStorageStack>(identity: Class<T>, @JvmField val energyProvider: () -> IMatteryEnergyStorage) : VirtualComponent<T>(identity) {
|
||||
constructor(identity: Class<T>, energyStorage: IMatteryEnergyStorage) : this(identity, {energyStorage})
|
||||
constructor(other: VirtualComponent<T>, energyStorage: IMatteryEnergyStorage) : this(other.storageIdentity(), energyStorage) {
|
||||
open class PoweredVirtualComponent<T : IStorageStack>(type: StorageStackType<T>, val energyProvider: () -> IMatteryEnergyStorage) : VirtualComponent<T>(type) {
|
||||
constructor(type: Class<T>, energyStorage: IMatteryEnergyStorage) : this(StorageRegistry.get(type), {energyStorage})
|
||||
constructor(type: StorageStackType<T>, energyStorage: IMatteryEnergyStorage) : this(type, {energyStorage})
|
||||
constructor(other: VirtualComponent<T>, energyStorage: IMatteryEnergyStorage) : this(other.storageType.identity, energyStorage) {
|
||||
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<T : IStorageStack>(identity: Class<T>, @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<T : IStorageStack>(identity: Class<T>, @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<T : IStorageStack>(identity: Class<T>, @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<T : IStorageStack>(identity: Class<T>, @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<T : IStorageStack>(identity: Class<T>, @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
|
||||
|
Loading…
Reference in New Issue
Block a user