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.network.MatteryNetworking;
|
||||||
import ru.dbotthepony.mc.otm.registry.*;
|
import ru.dbotthepony.mc.otm.registry.*;
|
||||||
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper;
|
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper;
|
||||||
import ru.dbotthepony.mc.otm.storage.StorageObjectRegistry;
|
import ru.dbotthepony.mc.otm.storage.StorageRegistry;
|
||||||
import ru.dbotthepony.mc.otm.storage.StorageObjectTuple;
|
import ru.dbotthepony.mc.otm.storage.StorageStackType;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
@ -43,7 +43,11 @@ public final class OverdriveThatMatters {
|
|||||||
|
|
||||||
public static OverdriveThatMatters INSTANCE;
|
public static OverdriveThatMatters INSTANCE;
|
||||||
public AndroidGui ANDROID_GUI;
|
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) {
|
public static ResourceLocation loc(String path) {
|
||||||
return new ResourceLocation(MOD_ID, path);
|
return new ResourceLocation(MOD_ID, path);
|
||||||
@ -89,9 +93,7 @@ public final class OverdriveThatMatters {
|
|||||||
|
|
||||||
private void setup(final FMLCommonSetupEvent event) {
|
private void setup(final FMLCommonSetupEvent event) {
|
||||||
MatteryNetworking.register();
|
MatteryNetworking.register();
|
||||||
// LOGGER.info("Registered network");
|
ITEM_STORAGE = StorageRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125"));
|
||||||
|
|
||||||
ITEM_STORAGE = StorageObjectRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupClient(final FMLClientSetupEvent event) {
|
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)
|
super.setChanged(slot, new, old)
|
||||||
|
|
||||||
old.getCapability(MatteryCapability.DRIVE).ifPresent {
|
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 {
|
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 {
|
tickOnceServer {
|
||||||
var state = blockState
|
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)
|
state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING)
|
||||||
} else {
|
} else {
|
||||||
state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE)
|
state = state.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE)
|
||||||
|
@ -1,37 +1,28 @@
|
|||||||
package ru.dbotthepony.mc.otm.capability.drive
|
package ru.dbotthepony.mc.otm.capability.drive
|
||||||
|
|
||||||
import ru.dbotthepony.mc.otm.core.Fraction.Companion.deserializeNBT
|
import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap
|
||||||
import ru.dbotthepony.mc.otm.storage.IStorageStack
|
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
|
||||||
import kotlin.jvm.JvmOverloads
|
import kotlin.jvm.JvmOverloads
|
||||||
import java.util.HashMap
|
|
||||||
import ru.dbotthepony.mc.otm.storage.IStorageTuple
|
|
||||||
import java.util.UUID
|
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.CompoundTag
|
||||||
import net.minecraft.nbt.ListTag
|
import net.minecraft.nbt.ListTag
|
||||||
import net.minecraft.nbt.Tag
|
import net.minecraft.nbt.Tag
|
||||||
import ru.dbotthepony.mc.otm.core.Fraction
|
|
||||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||||
import ru.dbotthepony.mc.otm.ifHas
|
import ru.dbotthepony.mc.otm.ifHas
|
||||||
import ru.dbotthepony.mc.otm.set
|
import ru.dbotthepony.mc.otm.set
|
||||||
|
import ru.dbotthepony.mc.otm.storage.*
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
|
|
||||||
|
|
||||||
abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor(
|
abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor(
|
||||||
override var driveCapacity: ImpreciseFraction,
|
override var driveCapacity: ImpreciseFraction,
|
||||||
override val uuid: UUID = UUID.randomUUID(),
|
override val uuid: UUID = UUID.randomUUID(),
|
||||||
var maxDifferentStacks: Int = 0xFFFF
|
var maxDifferentStacks: Int = 0xFFFF
|
||||||
) : IMatteryDrive<T> {
|
) : 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
|
override var isDirty = false
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value != field && value && DrivePool.isLegalAccess()) {
|
if (value != field && value && DrivePool.isLegalAccess()) {
|
||||||
@ -42,24 +33,26 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
|
|||||||
}
|
}
|
||||||
|
|
||||||
var storedDifferentStacks = 0
|
var storedDifferentStacks = 0
|
||||||
|
protected set
|
||||||
|
|
||||||
override var storedCount = ImpreciseFraction.ZERO
|
override var storedCount = ImpreciseFraction.ZERO
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
|
@Suppress("unchecked_cast")
|
||||||
override fun insertStack(stack: T, simulate: Boolean): T {
|
override fun insertStack(stack: T, simulate: Boolean): T {
|
||||||
val maxInsert = driveCapacity.minus(storedCount).min(stack.count)
|
val maxInsert = driveCapacity.minus(storedCount).min(stack.count)
|
||||||
if (maxInsert <= ImpreciseFraction.ZERO) return stack
|
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) {
|
for (state in listing) {
|
||||||
if (state.stack().sameItem(stack)) {
|
if (state.stack.sameItem(stack)) {
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
state.stack().grow(maxInsert)
|
state.stack.grow(maxInsert)
|
||||||
storedCount += maxInsert
|
storedCount += maxInsert
|
||||||
|
|
||||||
for (listener in listeners) {
|
for (listener in listeners) {
|
||||||
listener.changeObject(state.id(), state.stack().count)
|
listener.changeStack(state.id, state.stack.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
isDirty = true
|
isDirty = true
|
||||||
@ -84,10 +77,10 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
|
|||||||
|
|
||||||
val state = StorageTuple(UUID.randomUUID(), copy)
|
val state = StorageTuple(UUID.randomUUID(), copy)
|
||||||
listing.add(state)
|
listing.add(state)
|
||||||
storedByID[state.id()] = state
|
storedByID[state.id] = state
|
||||||
|
|
||||||
for (listener in listeners) {
|
for (listener in listeners) {
|
||||||
listener.addObject(state.stack(), state.id(), this)
|
listener.addStack(state.stack, state.id, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
isDirty = true
|
isDirty = true
|
||||||
@ -98,33 +91,35 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
|
|||||||
return copy
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unchecked_cast")
|
||||||
override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T {
|
override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T {
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
var amount = amount
|
var amount = amount
|
||||||
val get = storedByID[id] ?: return identity().empty()
|
val get = storedByID[id] ?: return storageType.empty
|
||||||
|
|
||||||
if (amount <= ImpreciseFraction.ZERO)
|
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)
|
amount = amount.min(get.stack.count)
|
||||||
|
|
||||||
if (amount <= ImpreciseFraction.ZERO)
|
if (amount <= ImpreciseFraction.ZERO)
|
||||||
return identity().empty()
|
return storageType.empty
|
||||||
|
|
||||||
val copy = get.stack.copy() as T
|
val copy = get.stack.copy() as T
|
||||||
copy.count = amount
|
copy.count = amount
|
||||||
|
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
if (amount.compareTo(get.stack.count) == 0) {
|
if (amount.compareTo(get.stack.count) == 0) {
|
||||||
val listing = storedStacks[get.stack.partitionKey()]!!
|
val listing = storedStacks[get.stack.partitionKey]!!
|
||||||
listing.remove(get)
|
listing.remove(get)
|
||||||
storedDifferentStacks--
|
storedDifferentStacks--
|
||||||
|
|
||||||
for (listener in listeners) {
|
for (listener in listeners) {
|
||||||
listener.removeObject(get.id())
|
listener.removeStack(get.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listing.size == 0) {
|
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) {
|
if (!get.stack.count.isZero) {
|
||||||
for (listener in listeners) {
|
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)
|
val serialized = serializeStack(stack)
|
||||||
|
|
||||||
if (serialized != null) {
|
if (serialized != null) {
|
||||||
serialized["id"] = longArrayOf(stack.id().mostSignificantBits, stack.id().leastSignificantBits)
|
serialized["id"] = longArrayOf(stack.id.mostSignificantBits, stack.id.leastSignificantBits)
|
||||||
list.add(serialized)
|
list.add(serialized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,19 +186,15 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
|
|||||||
val id = entry.getLongArray("id")
|
val id = entry.getLongArray("id")
|
||||||
val tuple = StorageTuple(if (id.size == 2) UUID(id[0], id[1]) else UUID.randomUUID(), stack)
|
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
|
storedByID[tuple.id] = tuple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun storageIdentity(): Class<T> {
|
|
||||||
return identity().identity()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStack(id: UUID): T {
|
override fun getStack(id: UUID): T {
|
||||||
return storedByID[id]?.stack ?: identity().empty()
|
return storedByID[id]?.stack ?: storageType.empty
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStacks(): List<IStorageTuple<T>> {
|
override fun getStacks(): List<IStorageTuple<T>> {
|
||||||
@ -221,7 +212,6 @@ abstract class AbstractMatteryDrive<T : IStorageStack> @JvmOverloads constructor
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField
|
|
||||||
protected val listeners = HashSet<IStorageListener<T>>()
|
protected val listeners = HashSet<IStorageListener<T>>()
|
||||||
|
|
||||||
override fun addListener(listener: IStorageListener<T>): Boolean {
|
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.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraftforge.registries.RegistryManager
|
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.core.ImpreciseFraction
|
||||||
import ru.dbotthepony.mc.otm.set
|
import ru.dbotthepony.mc.otm.set
|
||||||
import ru.dbotthepony.mc.otm.storage.IStorageTuple
|
import ru.dbotthepony.mc.otm.storage.IStorageTuple
|
||||||
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
|
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
|
||||||
import ru.dbotthepony.mc.otm.storage.StorageObjectRegistry
|
import ru.dbotthepony.mc.otm.storage.StorageStackType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ItemMatteryDrive : AbstractMatteryDrive<ItemStackWrapper>, IItemMatteryDrive {
|
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, uuid: UUID) : super(capacity, uuid)
|
||||||
constructor(capacity: ImpreciseFraction) : super(capacity)
|
constructor(capacity: ImpreciseFraction) : super(capacity)
|
||||||
|
|
||||||
private val identity = StorageObjectRegistry.getOrError(ItemStackWrapper::class.java)
|
override val storageType: StorageStackType<ItemStackWrapper> = OverdriveThatMatters.INSTANCE.ITEM_STORAGE()
|
||||||
override fun identity() = identity
|
|
||||||
|
|
||||||
fun insertObject(item: ItemStack, simulate: Boolean): ItemStack {
|
fun insertStack(item: ItemStack, simulate: Boolean): ItemStack {
|
||||||
return insertStack(ItemStackWrapper(item), simulate).stack
|
return insertStack(ItemStackWrapper(item), simulate).stack
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serializeStack(item: IStorageTuple<ItemStackWrapper>): CompoundTag? {
|
override fun serializeStack(item: IStorageTuple<ItemStackWrapper>): CompoundTag? {
|
||||||
val tag = CompoundTag()
|
val tag = CompoundTag()
|
||||||
val location = item.stack().stack.item.registryName!!.toString()
|
val location = item.stack.stack.item.registryName!!.toString()
|
||||||
|
|
||||||
tag["item"] = location
|
tag["item"] = location
|
||||||
tag["count"] = item.stack.stack.count
|
tag["count"] = item.stack.stack.count
|
||||||
@ -57,12 +56,12 @@ class ItemMatteryDrive : AbstractMatteryDrive<ItemStackWrapper>, IItemMatteryDri
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun findItems(item: Item): List<IStorageTuple<ItemStackWrapper>> {
|
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()
|
return if (list != null) java.util.List.copyOf(list) else emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findItems(stack: ItemStack): List<IStorageTuple<ItemStackWrapper>> {
|
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
|
var amount = 0
|
||||||
|
|
||||||
|
@ -2,14 +2,15 @@ package ru.dbotthepony.mc.otm.graph.storage
|
|||||||
|
|
||||||
import net.minecraftforge.common.util.LazyOptional
|
import net.minecraftforge.common.util.LazyOptional
|
||||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
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.IStorageStack
|
||||||
|
import ru.dbotthepony.mc.otm.storage.StorageStackType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
open class BasicStorageGraphNode : IStorageGraphNode {
|
open class BasicStorageGraphNode : IStorageGraphNode {
|
||||||
private var resolver = LazyOptional.of<IStorageGraphNode> { this }
|
private var resolver = LazyOptional.of<IStorageGraphNode> { this }
|
||||||
private var valid = true
|
private var valid = true
|
||||||
protected val components = ArrayList<IStorageIdentity<*>>()
|
protected val components = ArrayList<IStorage<*>>()
|
||||||
|
|
||||||
private val node = Graph6Node<IStorageGraphNode>(this)
|
private val node = Graph6Node<IStorageGraphNode>(this)
|
||||||
|
|
||||||
@ -17,25 +18,14 @@ open class BasicStorageGraphNode : IStorageGraphNode {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getComponents(): List<IStorageIdentity<*>> {
|
override fun fetchComponents(): List<IStorage<*>> {
|
||||||
return Collections.unmodifiableList(components)
|
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) {
|
for (component in components) {
|
||||||
if (component.storageIdentity() == identity) {
|
if (component.storageType === 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) {
|
|
||||||
return component as U
|
return component as U
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,25 +35,15 @@ open class BasicStorageGraphNode : IStorageGraphNode {
|
|||||||
return factory
|
return factory
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addStorageComponent(component: IStorageIdentity<*>) {
|
fun addStorageComponent(component: IStorage<*>) {
|
||||||
for (component1 in components) {
|
for (component1 in components) {
|
||||||
if (component === component1 || component1.storageIdentity() == component.storageIdentity()) {
|
if (component === component1 || component1.storageType === component.storageType) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
components.add(component)
|
components.add(component)
|
||||||
getStorageGraph()?.add(component)
|
storageGraph?.add(component)
|
||||||
}
|
|
||||||
|
|
||||||
fun removeStorageComponent(component: IStorageIdentity<*>) {
|
|
||||||
for (component1 in components) {
|
|
||||||
if (component === component1 || component1.storageIdentity() == component.storageIdentity()) {
|
|
||||||
components.remove(component1)
|
|
||||||
getStorageGraph()?.remove(component)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invalidate() {
|
fun invalidate() {
|
||||||
|
@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.graph.storage
|
|||||||
|
|
||||||
import net.minecraft.MethodsReturnNonnullByDefault
|
import net.minecraft.MethodsReturnNonnullByDefault
|
||||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
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
|
import javax.annotation.ParametersAreNonnullByDefault
|
||||||
|
|
||||||
@MethodsReturnNonnullByDefault
|
@MethodsReturnNonnullByDefault
|
||||||
@ -13,10 +13,10 @@ interface IStorageGraphNode {
|
|||||||
*
|
*
|
||||||
* If you don't know what you are going to store, you may return nothing.
|
* 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 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
|
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.server.level.ServerLevel
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.graph.Abstract6Graph
|
import ru.dbotthepony.mc.otm.graph.Abstract6Graph
|
||||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
||||||
import ru.dbotthepony.mc.otm.storage.IStorageIdentity
|
import ru.dbotthepony.mc.otm.storage.*
|
||||||
import ru.dbotthepony.mc.otm.storage.IStorageStack
|
|
||||||
import ru.dbotthepony.mc.otm.storage.VirtualComponent
|
|
||||||
|
|
||||||
class StorageNetworkGraph : Abstract6Graph<IStorageGraphNode>() {
|
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 {
|
fun <T : IStorageStack> insertStack(obj: T, simulate: Boolean): T {
|
||||||
return getVirtualComponent(type).insertStack(obj, simulate)
|
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
|
* Returns a [VirtualComponent] representing [type] storage
|
||||||
*/
|
*/
|
||||||
fun <T : IStorageStack> getVirtualComponent(type: Class<T>): VirtualComponent<T> {
|
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>) {
|
fun <T : IStorageStack> add(storage: IStorage<T>) {
|
||||||
getVirtualComponent(identity.storageIdentity()).add(identity)
|
getVirtualComponent(storage.storageType).add(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : IStorageStack> remove(identity: IStorageIdentity<T>) {
|
fun <T : IStorageStack> remove(storage: IStorage<T>) {
|
||||||
getVirtualComponent(identity.storageIdentity()).remove(identity)
|
getVirtualComponent(storage.storageType).remove(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNodeAdded(node: Graph6Node<IStorageGraphNode>) {
|
override fun onNodeAdded(node: Graph6Node<IStorageGraphNode>) {
|
||||||
for (identity in node.value.getComponents()) {
|
for (identity in node.value.fetchComponents()) {
|
||||||
add(identity)
|
add(identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) {
|
override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) {
|
||||||
for (identity in node.value.getComponents()) {
|
for (identity in node.value.fetchComponents()) {
|
||||||
remove(identity)
|
remove(identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ class PortableCondensationDriveItem(capacity: Int) :
|
|||||||
|
|
||||||
if (filter.matches(event.item.item)) {
|
if (filter.matches(event.item.item)) {
|
||||||
val copy = event.item.item.copy()
|
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) {
|
if (remaining.count == event.item.item.count) {
|
||||||
return@ifPresent
|
return@ifPresent
|
||||||
|
@ -16,6 +16,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent
|
|||||||
import net.minecraftforge.network.NetworkEvent
|
import net.minecraftforge.network.NetworkEvent
|
||||||
import net.minecraftforge.network.PacketDistributor
|
import net.minecraftforge.network.PacketDistributor
|
||||||
import org.lwjgl.glfw.GLFW
|
import org.lwjgl.glfw.GLFW
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive
|
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive
|
||||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
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()
|
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()) {
|
for (item in (drive as IMatteryDrive<ItemStackWrapper>).getStacks()) {
|
||||||
val tuple = getMatterValue(item.stack.stack, level + 1)
|
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.minecraft.world.item.ItemStack
|
||||||
import net.minecraftforge.energy.CapabilityEnergy
|
import net.minecraftforge.energy.CapabilityEnergy
|
||||||
import net.minecraftforge.network.NetworkEvent
|
import net.minecraftforge.network.NetworkEvent
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
import ru.dbotthepony.mc.otm.block.entity.DriveViewerBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.DriveViewerBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive
|
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive
|
||||||
@ -70,7 +71,7 @@ class DriveViewerMenu @JvmOverloads constructor(
|
|||||||
|
|
||||||
if (!itemStack.isEmpty) {
|
if (!itemStack.isEmpty) {
|
||||||
itemStack.getCapability(MatteryCapability.DRIVE).ifPresent {
|
itemStack.getCapability(MatteryCapability.DRIVE).ifPresent {
|
||||||
if (it.storageIdentity() == ItemStackWrapper::class.java) {
|
if (it.storageType === OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) {
|
||||||
lastDrive = it as IMatteryDrive<ItemStackWrapper>
|
lastDrive = it as IMatteryDrive<ItemStackWrapper>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +124,7 @@ class DriveViewerMenu @JvmOverloads constructor(
|
|||||||
if (remaining.count.toInt() == item.count)
|
if (remaining.count.toInt() == item.count)
|
||||||
return ItemStack.EMPTY
|
return ItemStack.EMPTY
|
||||||
|
|
||||||
if (remaining.isEmpty()) {
|
if (remaining.isEmpty) {
|
||||||
val copy = item.copy()
|
val copy = item.copy()
|
||||||
slot.set(ItemStack.EMPTY)
|
slot.set(ItemStack.EMPTY)
|
||||||
return copy
|
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.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.item.ItemStack
|
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.block.entity.ItemMonitorBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier
|
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier
|
||||||
@ -28,7 +29,7 @@ class ItemMonitorMenu @JvmOverloads constructor(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
if (tile != null) {
|
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())
|
local = PoweredVirtualComponent(subscribed, tile.getCapability(MatteryCapability.ENERGY).resolve().get())
|
||||||
view.setComponent(local)
|
view.setComponent(local)
|
||||||
} else {
|
} else {
|
||||||
|
@ -77,8 +77,8 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
|
|||||||
return state.values.size
|
return state.values.size
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addObject(stack: ItemStackWrapper, id: UUID, provider: IStorageView<ItemStackWrapper>) = addObject(stack.stack, id)
|
override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageView<ItemStackWrapper>) = addObject(stack.stack, id)
|
||||||
override fun changeObject(id: UUID, newCount: ImpreciseFraction) = changeObject(id, newCount.toInt())
|
override fun changeStack(id: UUID, newCount: ImpreciseFraction) = changeObject(id, newCount.toInt())
|
||||||
|
|
||||||
protected fun network(fn: () -> Any) {
|
protected fun network(fn: () -> Any) {
|
||||||
if (!remote) {
|
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!")
|
val get = upstream_state[id] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id!")
|
||||||
upstream_state.remove(id)
|
upstream_state.remove(id)
|
||||||
state.remove(get.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)
|
val extracted = provider.extractStack(state.upstreamId!!, amount, true)
|
||||||
|
|
||||||
if (!extracted.isEmpty()) {
|
if (!extracted.isEmpty) {
|
||||||
val (_, remaining) = menu.quickMoveToInventory(extracted.stack, false)
|
val (_, remaining) = menu.quickMoveToInventory(extracted.stack, false)
|
||||||
|
|
||||||
if (remaining.count != extracted.stack.count) {
|
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()
|
val copy = menu.carried.copy()
|
||||||
copy.count = 1
|
copy.count = 1
|
||||||
|
|
||||||
if (provider.insertStack(ItemStackWrapper(copy), false).isEmpty()) {
|
if (provider.insertStack(ItemStackWrapper(copy), false).isEmpty) {
|
||||||
menu.carried.shrink(1)
|
menu.carried.shrink(1)
|
||||||
MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(menu.carried))
|
MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(menu.carried))
|
||||||
menu.setRemoteCarried(menu.carried.copy())
|
menu.setRemoteCarried(menu.carried.copy())
|
||||||
|
@ -2,46 +2,53 @@ package ru.dbotthepony.mc.otm.storage
|
|||||||
|
|
||||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import net.minecraftforge.registries.ForgeRegistry
|
||||||
|
|
||||||
interface IStorageStack {
|
interface IStorageStack {
|
||||||
fun copy(): IStorageStack
|
fun copy(): IStorageStack
|
||||||
|
|
||||||
var count: ImpreciseFraction
|
var count: ImpreciseFraction
|
||||||
fun isEmpty(): Boolean
|
val isEmpty: Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return max stack size for this stack object
|
* @return max stack size for this stack object,
|
||||||
* [Optional.empty()] if unlimited (default)
|
* 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).
|
* This property represent (almost) unique key used to quickly look up for similar stacks.
|
||||||
* Defaults to no partitioning; meaning performance will degrade much quicker than it should.
|
* Semantic is very similar, but not equal, to [hashCode] of object. This property **must** be equal for two
|
||||||
* Good object is an object that will influence on [sameItem] return result, making it return true.
|
* entries if [sameItem] returns true. This value should not change.
|
||||||
* It is strictly considered that if !this.itemIdentity().equals(other.itemIdentity);
|
|
||||||
* then this.sameItem(other) will never return true.
|
|
||||||
*
|
*
|
||||||
* 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 {
|
val partitionKey: Long
|
||||||
return Any::class.java
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [other] other object to compare; if not the same of this object type just return false
|
* [other] is the stack to compare.
|
||||||
* Returns boolean representing whenever internal state of [this] equals to [other];
|
*
|
||||||
* this include tags, mapping IDs, capabilities, **excluding** amount;
|
* If not the same of this object type just return false
|
||||||
* behavior is pretty much the same as ItemStack.isSameItemSameTags
|
* 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
|
fun sameItem(other: IStorageStack): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increase [count] by [amount]
|
||||||
|
*/
|
||||||
fun grow(amount: ImpreciseFraction) {
|
fun grow(amount: ImpreciseFraction) {
|
||||||
count += amount
|
count += amount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrease [count] by [amount]
|
||||||
|
*/
|
||||||
fun shrink(amount: ImpreciseFraction) {
|
fun shrink(amount: ImpreciseFraction) {
|
||||||
count -= amount
|
count -= amount
|
||||||
}
|
}
|
||||||
@ -50,11 +57,14 @@ interface IStorageStack {
|
|||||||
/**
|
/**
|
||||||
* Storage system root, along IStorageStack interface
|
* Storage system root, along IStorageStack interface
|
||||||
*/
|
*/
|
||||||
interface IStorageIdentity<T : IStorageStack> {
|
interface IStorage<T : IStorageStack> {
|
||||||
fun storageIdentity(): Class<T>
|
/**
|
||||||
|
* @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
|
* [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
|
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
|
fun insertStack(stack: T, simulate: Boolean): T
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IStorageView<T : IStorageStack> : IStorageTrigger<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.
|
* @return stored object (not a copy). Do not edit it.
|
||||||
*/
|
*/
|
||||||
fun getStack(id: UUID): T
|
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 amount amount of units to extract
|
||||||
* @param simulate whenever to simulate the action or not
|
* @param simulate whenever to simulate the action or not
|
||||||
* @return copy of object, with amount of units actually extracted
|
* @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
|
* 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 amount desired amount to extract
|
||||||
* @param simulate whenever to simulate the action or not
|
* @param simulate whenever to simulate the action or not
|
||||||
* @return amount extracted
|
* @return amount extracted
|
||||||
@ -108,7 +122,7 @@ interface IStorageView<T : IStorageStack> : IStorageTrigger<T> {
|
|||||||
fun addListenerAuto(listener: IStorageListener<T>): Boolean {
|
fun addListenerAuto(listener: IStorageListener<T>): Boolean {
|
||||||
if (addListener(listener)) {
|
if (addListener(listener)) {
|
||||||
for (stack in getStacks()) {
|
for (stack in getStacks()) {
|
||||||
listener.addObject(stack.stack(), stack.id(), this)
|
listener.addStack(stack.stack, stack.id, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -120,7 +134,7 @@ interface IStorageView<T : IStorageStack> : IStorageTrigger<T> {
|
|||||||
fun removeListenerAuto(listener: IStorageListener<T>): Boolean {
|
fun removeListenerAuto(listener: IStorageListener<T>): Boolean {
|
||||||
if (removeListener(listener)) {
|
if (removeListener(listener)) {
|
||||||
for (stack in getStacks()) {
|
for (stack in getStacks()) {
|
||||||
listener.removeObject(stack.id())
|
listener.removeStack(stack.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -134,38 +148,23 @@ interface IStorageListener<T : IStorageStack> {
|
|||||||
/**
|
/**
|
||||||
* Fired on whenever an object is added (to listener) we subscribed to
|
* 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
|
* 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
|
* Fired on whenever an object is removed from listener we subscribed to
|
||||||
*/
|
*/
|
||||||
fun removeObject(id: UUID)
|
fun removeStack(id: UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IStorageTuple<T : IStorageStack> {
|
interface IStorageTuple<T : IStorageStack> {
|
||||||
val id: UUID
|
val id: UUID
|
||||||
get() = id()
|
|
||||||
|
|
||||||
val stack: T
|
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>
|
interface IStorageComponent<T : IStorageStack> : IStorageView<T>, IStorageConsumer<T>
|
||||||
|
@ -1,39 +1,37 @@
|
|||||||
package ru.dbotthepony.mc.otm.storage
|
package ru.dbotthepony.mc.otm.storage
|
||||||
|
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
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 ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@JvmRecord
|
class ItemStackWrapper(val stack: ItemStack) : IStorageStack {
|
||||||
data class ItemStackWrapper(val stack: ItemStack) : IStorageStack {
|
operator fun component1() = stack
|
||||||
|
|
||||||
override fun copy(): IStorageStack {
|
override fun copy(): IStorageStack {
|
||||||
return ItemStackWrapper(stack.copy())
|
return ItemStackWrapper(stack.copy())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setCount(value: Int) {
|
fun setCount(value: Int) {
|
||||||
stack.count = Math.max(value, 0)
|
stack.count = value.coerceAtLeast(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var count: ImpreciseFraction
|
override var count: ImpreciseFraction
|
||||||
get() = ImpreciseFraction(stack.count)
|
get() = ImpreciseFraction(stack.count)
|
||||||
set(value) = setCount(value.toInt())
|
set(value) = setCount(value.toInt())
|
||||||
|
|
||||||
fun getCountInt() = stack.count
|
override val maxStackSize get() = ImpreciseFraction(stack.maxStackSize)
|
||||||
|
|
||||||
override fun getMaxStackSize(): Optional<ImpreciseFraction> {
|
override val isEmpty: Boolean = stack.isEmpty
|
||||||
return Optional.of(ImpreciseFraction(stack.maxStackSize))
|
override val partitionKey: Long = partitionKey(stack.item)
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean = stack.isEmpty
|
|
||||||
override fun partitionKey(): Any = stack.item
|
|
||||||
|
|
||||||
override fun sameItem(other: IStorageStack): Boolean {
|
override fun sameItem(other: IStorageStack): Boolean {
|
||||||
if (this === other)
|
if (this === other)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
if (other is ItemStackWrapper)
|
if (other is ItemStackWrapper)
|
||||||
return ItemStack.isSameItemSameTags(stack, other.stack);
|
return ItemStack.isSameItemSameTags(stack, other.stack)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -41,5 +39,7 @@ data class ItemStackWrapper(val stack: ItemStack) : IStorageStack {
|
|||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
val EMPTY = ItemStackWrapper(ItemStack.EMPTY)
|
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
|
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.capability.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.core.Fraction
|
|
||||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||||
import java.util.*
|
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> {
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stack(): T {
|
open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : IStorageComponent<T>, IStorageListener<T> {
|
||||||
return stack
|
constructor(type: Class<T>) : this(StorageRegistry.get(type))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageComponent<T>, IStorageListener<T> {
|
override val storageType: StorageStackType<T> = type
|
||||||
@JvmField
|
|
||||||
protected val identity: StorageObjectTuple<T>
|
|
||||||
final override fun storageIdentity() = identity.identity()
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.identity = StorageObjectRegistry.getOrError(identity)
|
|
||||||
}
|
|
||||||
|
|
||||||
// удаленный UUID -> Кортеж
|
// удаленный UUID -> Кортеж
|
||||||
@JvmField
|
protected val remoteByUUID = Object2ObjectAVLTreeMap<UUID, RemoteTuple<T>>()
|
||||||
protected val remoteByUUID = HashMap<UUID, RemoteTuple<T>>()
|
|
||||||
|
|
||||||
// локальный UUID -> Локальный кортеж
|
// локальный UUID -> Локальный кортеж
|
||||||
@JvmField
|
protected val localByUUID = Object2ObjectAVLTreeMap<UUID, LocalTuple<T>>()
|
||||||
protected val localByUUID = HashMap<UUID, LocalTuple<T>>()
|
|
||||||
|
|
||||||
// Хеш ключ -> Список Локальных кортежей
|
// ключ -> Список Локальных кортежей
|
||||||
@JvmField
|
protected val partitions = Long2ObjectAVLTreeMap<ArrayList<LocalTuple<T>>>()
|
||||||
protected val partitions = HashMap<Any, ArrayList<LocalTuple<T>>>()
|
|
||||||
|
|
||||||
// ArrayList для скорости работы
|
// ArrayList для скорости работы
|
||||||
@JvmField
|
|
||||||
protected val listeners = ArrayList<IStorageListener<T>>()
|
protected val listeners = ArrayList<IStorageListener<T>>()
|
||||||
|
|
||||||
@JvmField
|
|
||||||
protected val consumers = ArrayList<IStorageConsumer<T>>()
|
protected val consumers = ArrayList<IStorageConsumer<T>>()
|
||||||
|
|
||||||
open fun add(identity: IStorageIdentity<T>) {
|
open fun add(identity: IStorage<T>) {
|
||||||
if (identity is IStorageView<T>) {
|
if (identity is IStorageView<T>) {
|
||||||
identity.addListenerAuto(this)
|
identity.addListenerAuto(this)
|
||||||
} else if (identity is IStorageTrigger<T>) {
|
} 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)) {
|
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>) {
|
if (identity is IStorageView<T>) {
|
||||||
identity.removeListenerAuto(this)
|
identity.removeListenerAuto(this)
|
||||||
} else if (identity is IStorageTrigger<T>) {
|
} 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 {
|
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>> {
|
override fun getStacks(): List<IStorageTuple<T>> {
|
||||||
@ -110,9 +94,10 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
|||||||
return output
|
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" }
|
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
|
var local: LocalTuple<T>? = null
|
||||||
|
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
@ -137,16 +122,16 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
|||||||
|
|
||||||
if (added) {
|
if (added) {
|
||||||
for (listener in listeners) {
|
for (listener in listeners) {
|
||||||
listener.addObject(local.stack, local.id, this)
|
listener.addStack(local.stack, local.id, this)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (listener in listeners) {
|
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)
|
assert(newCount > ImpreciseFraction.ZERO)
|
||||||
val tuple = remoteByUUID[id] ?: throw IllegalStateException("No such tuple with id $id")
|
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)
|
tuple.local.stack.grow(diff)
|
||||||
|
|
||||||
for (listener in listeners) {
|
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 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.stack.shrink(tuple.obj.count)
|
||||||
tuple.local.tuples.remove(tuple)
|
tuple.local.tuples.remove(tuple)
|
||||||
@ -177,7 +162,7 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
|||||||
partitions[key]!!.remove(tuple.local)
|
partitions[key]!!.remove(tuple.local)
|
||||||
|
|
||||||
for (listener in listeners) {
|
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) {
|
for (consumer in consumers) {
|
||||||
leftover = consumer.insertStack(leftover, simulate)
|
leftover = consumer.insertStack(leftover, simulate)
|
||||||
|
|
||||||
if (leftover.isEmpty()) {
|
if (leftover.isEmpty) {
|
||||||
return leftover
|
return leftover
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,18 +181,20 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
|||||||
return leftover
|
return leftover
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unchecked_cast")
|
||||||
override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T {
|
override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T {
|
||||||
if (amount.isZero)
|
if (amount.isZero)
|
||||||
return identity.empty
|
return this.storageType.empty
|
||||||
|
|
||||||
|
@Suppress("name_shadowing")
|
||||||
var amount = amount
|
var amount = amount
|
||||||
val tuple: LocalTuple<T>? = localByUUID[id]
|
val tuple: LocalTuple<T>? = localByUUID[id]
|
||||||
|
|
||||||
if (tuple == null || amount.isZero)
|
if (tuple == null || amount.isZero)
|
||||||
return identity.empty
|
return this.storageType.empty
|
||||||
|
|
||||||
if (amount <= ImpreciseFraction.MINUS_ONE)
|
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)
|
val toExtract = tuple.stack.count.min(amount)
|
||||||
var extracted = ImpreciseFraction.ZERO
|
var extracted = ImpreciseFraction.ZERO
|
||||||
@ -225,19 +212,21 @@ open class VirtualComponent<T : IStorageStack>(identity: Class<T>) : IStorageCom
|
|||||||
return copy
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
return identity.empty()
|
return this.storageType.empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open class PoweredVirtualComponent<T : IStorageStack>(identity: Class<T>, @JvmField val energyProvider: () -> IMatteryEnergyStorage) : VirtualComponent<T>(identity) {
|
open class PoweredVirtualComponent<T : IStorageStack>(type: StorageStackType<T>, val energyProvider: () -> IMatteryEnergyStorage) : VirtualComponent<T>(type) {
|
||||||
constructor(identity: Class<T>, energyStorage: IMatteryEnergyStorage) : this(identity, {energyStorage})
|
constructor(type: Class<T>, energyStorage: IMatteryEnergyStorage) : this(StorageRegistry.get(type), {energyStorage})
|
||||||
constructor(other: VirtualComponent<T>, energyStorage: IMatteryEnergyStorage) : this(other.storageIdentity(), energyStorage) {
|
constructor(type: StorageStackType<T>, energyStorage: IMatteryEnergyStorage) : this(type, {energyStorage})
|
||||||
|
constructor(other: VirtualComponent<T>, energyStorage: IMatteryEnergyStorage) : this(other.storageType.identity, energyStorage) {
|
||||||
add(other)
|
add(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unchecked_cast")
|
||||||
override fun insertStack(stack: T, simulate: Boolean): T {
|
override fun insertStack(stack: T, simulate: Boolean): T {
|
||||||
val required = identity.energyPerOperation * stack.count
|
val required = storageType.energyPerOperation * stack.count
|
||||||
val energy = energyProvider()
|
val energy = energyProvider.invoke()
|
||||||
val extracted = energy.extractEnergyInner(required, true)
|
val extracted = energy.extractEnergyInner(required, true)
|
||||||
|
|
||||||
if (extracted.isZero) {
|
if (extracted.isZero) {
|
||||||
@ -247,7 +236,7 @@ open class PoweredVirtualComponent<T : IStorageStack>(identity: Class<T>, @JvmFi
|
|||||||
if (extracted == required) {
|
if (extracted == required) {
|
||||||
val leftover = super.insertStack(stack, simulate)
|
val leftover = super.insertStack(stack, simulate)
|
||||||
|
|
||||||
if (leftover.isEmpty()) {
|
if (leftover.isEmpty) {
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
energy.extractEnergyInner(required, false)
|
energy.extractEnergyInner(required, false)
|
||||||
}
|
}
|
||||||
@ -256,24 +245,25 @@ open class PoweredVirtualComponent<T : IStorageStack>(identity: Class<T>, @JvmFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
val requiredNew = identity.energyPerOperation * stack.count - leftover.count
|
val requiredNew = storageType.energyPerOperation * stack.count - leftover.count
|
||||||
energy.extractEnergyInner(requiredNew, false)
|
energy.extractEnergyInner(requiredNew, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return leftover
|
return leftover
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("name_shadowing")
|
||||||
val stack = stack.copy() as T
|
val stack = stack.copy() as T
|
||||||
val oldCount = stack.count
|
val oldCount = stack.count
|
||||||
stack.count = extracted / identity.energyPerOperation
|
stack.count = extracted / storageType.energyPerOperation
|
||||||
val diff = oldCount - stack.count
|
val diff = oldCount - stack.count
|
||||||
val newRequired = identity.energyPerOperation * stack.count
|
val newRequired = storageType.energyPerOperation * stack.count
|
||||||
val newExtracted = energy.extractEnergyInner(newRequired, true)
|
val newExtracted = energy.extractEnergyInner(newRequired, true)
|
||||||
|
|
||||||
if (newExtracted == newRequired) {
|
if (newExtracted == newRequired) {
|
||||||
val leftover = super.insertStack(stack, simulate)
|
val leftover = super.insertStack(stack, simulate)
|
||||||
|
|
||||||
if (leftover.isEmpty()) {
|
if (leftover.isEmpty) {
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
energy.extractEnergyInner(newRequired, false)
|
energy.extractEnergyInner(newRequired, false)
|
||||||
}
|
}
|
||||||
@ -283,7 +273,7 @@ open class PoweredVirtualComponent<T : IStorageStack>(identity: Class<T>, @JvmFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
val requiredNew = (stack.count - leftover.count) * identity.energyPerOperation
|
val requiredNew = (stack.count - leftover.count) * storageType.energyPerOperation
|
||||||
energy.extractEnergyInner(requiredNew, false)
|
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 {
|
override fun extractStack(id: UUID, amount: ImpreciseFraction, simulate: Boolean): T {
|
||||||
val required = identity.energyPerOperation * amount
|
val required = storageType.energyPerOperation * amount
|
||||||
val energy = energyProvider()
|
val energy = energyProvider.invoke()
|
||||||
val extracted = energy.extractEnergyInner(required, true)
|
val extracted = energy.extractEnergyInner(required, true)
|
||||||
|
|
||||||
if (extracted.isZero) {
|
if (extracted.isZero) {
|
||||||
return identity.empty
|
return storageType.empty
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extracted == required) {
|
if (extracted == required) {
|
||||||
val extractedStack = super.extractStack(id, amount, simulate)
|
val extractedStack = super.extractStack(id, amount, simulate)
|
||||||
|
|
||||||
if (extractedStack.isEmpty()) {
|
if (extractedStack.isEmpty) {
|
||||||
return extractedStack
|
return extractedStack
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,22 +304,23 @@ open class PoweredVirtualComponent<T : IStorageStack>(identity: Class<T>, @JvmFi
|
|||||||
if (extractedStack.count == amount) {
|
if (extractedStack.count == amount) {
|
||||||
energy.extractEnergyInner(required, false)
|
energy.extractEnergyInner(required, false)
|
||||||
} else {
|
} else {
|
||||||
energy.extractEnergyInner(extractedStack.count * identity.energyPerOperation, false)
|
energy.extractEnergyInner(extractedStack.count * storageType.energyPerOperation, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractedStack
|
return extractedStack
|
||||||
}
|
}
|
||||||
|
|
||||||
val amount = required / identity.energyPerOperation
|
@Suppress("name_shadowing")
|
||||||
|
val amount = required / storageType.energyPerOperation
|
||||||
val extractedStack = super.extractStack(id, amount, simulate)
|
val extractedStack = super.extractStack(id, amount, simulate)
|
||||||
|
|
||||||
if (extractedStack.isEmpty()) {
|
if (extractedStack.isEmpty) {
|
||||||
return extractedStack
|
return extractedStack
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!simulate) {
|
if (!simulate) {
|
||||||
energy.extractEnergyInner(extractedStack.count * identity.energyPerOperation, false)
|
energy.extractEnergyInner(extractedStack.count * storageType.energyPerOperation, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractedStack
|
return extractedStack
|
||||||
|
Loading…
Reference in New Issue
Block a user