Initial port of storage system to graph

This commit is contained in:
DBotThePony 2021-12-31 20:55:46 +07:00
parent 215ecd1f21
commit 4b5a77b92e
Signed by: DBot
GPG Key ID: DCC23B5715498507
25 changed files with 618 additions and 777 deletions

View File

@ -9,15 +9,10 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.capability.IStorageGridCell;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.storage.StorageGrid;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import java.security.Provider;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;

View File

@ -1,118 +0,0 @@
package ru.dbotthepony.mc.otm.capability;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.storage.IStorageIdentity;
import ru.dbotthepony.mc.otm.storage.IStorageStack;
import ru.dbotthepony.mc.otm.storage.StorageGrid;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class AbstractStorageGridCell implements IStorageGridCell {
private LazyOptional<IStorageGridCell> resolver = LazyOptional.of(() -> this);
private boolean valid = true;
protected final ArrayList<IStorageIdentity<?>> components = new ArrayList<>();
@Override
public List<? extends IStorageIdentity<?>> getComponents() {
return Collections.unmodifiableList(components);
}
@SuppressWarnings("unchecked")
public <T extends IStorageStack, U extends IStorageIdentity<T>> U computeIfAbsent(Class<T> identity, Supplier<U> provider) {
for (var component : components) {
if (component.storageIdentity() == identity) {
return (U) component;
}
}
var factory = provider.get();
addStorageComponent(factory);
return factory;
}
@SuppressWarnings("unchecked")
public <T extends IStorageStack, U extends IStorageIdentity<T>> U computeIfAbsent(Class<T> identity, Function<Class<T>, U> provider) {
for (var component : components) {
if (component.storageIdentity() == identity) {
return (U) component;
}
}
var factory = provider.apply(identity);
addStorageComponent(factory);
return factory;
}
public void addStorageComponent(IStorageIdentity<?> component) {
for (var component1 : components) {
if (component == component1 || component1.storageIdentity() == component.storageIdentity()) {
return;
}
}
detachStorage();
components.add(component);
attachStorage();
}
public void removeStorageComponent(IStorageIdentity<?> component) {
for (var component1 : components) {
if (component == component1 || component1.storageIdentity() == component.storageIdentity()) {
detachStorage();
components.remove(component1);
attachStorage();
return;
}
}
}
public void invalidate() {
if (!valid)
return;
valid = false;
resolver.invalidate();
// detachStorage();
}
public void revive() {
if (valid)
return;
valid = true;
resolver = LazyOptional.of(() -> this);
// attachStorage();
}
public LazyOptional<IStorageGridCell> get() {
return valid ? resolver : LazyOptional.empty();
}
protected StorageGrid storage_grid;
@Nullable
@Override
public StorageGrid getStorageGrid() {
return storage_grid;
}
@Override
public void setStorageGrid(@Nullable StorageGrid grid) {
storage_grid = grid;
}
@Override
public boolean isValidStorageCell() {
return valid;
}
}

View File

@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.capability.matter.IMatterTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage; import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.core.Fraction;
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode; import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode;
import ru.dbotthepony.mc.otm.graph.storage.IStorageGraphNode;
import java.math.MathContext; import java.math.MathContext;
import java.math.RoundingMode; import java.math.RoundingMode;
@ -21,7 +22,7 @@ public class MatteryCapability {
public static final Capability<IPatternStorage> PATTERN = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<IPatternStorage> PATTERN = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<IMatterTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IMatteryDrive> DRIVE = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<IMatteryDrive> DRIVE = CapabilityManager.get(new CapabilityToken<>() {});
public static final Capability<IStorageGridCell> STORAGE_CELL = CapabilityManager.get(new CapabilityToken<>() {}); public static final Capability<IStorageGraphNode> STORAGE_CELL = CapabilityManager.get(new CapabilityToken<>() {});
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static void register(final RegisterCapabilitiesEvent event) { public static void register(final RegisterCapabilitiesEvent event) {
@ -31,7 +32,7 @@ public class MatteryCapability {
event.register(IPatternStorage.class); event.register(IPatternStorage.class);
event.register(IMatterTaskProvider.class); event.register(IMatterTaskProvider.class);
event.register(IMatteryDrive.class); event.register(IMatteryDrive.class);
event.register(IStorageGridCell.class); event.register(IStorageGraphNode.class);
event.register(IMatterGraphNode.class); event.register(IMatterGraphNode.class);
} }

View File

@ -1,46 +1,35 @@
package ru.dbotthepony.mc.otm.menu; package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.SimpleContainer; import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveRack
import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveRack;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
public class DriveRackMenu extends PoweredMatteryMenu { class DriveRackMenu @JvmOverloads constructor(
public DriveRackMenu(int p_38852_, Inventory inventory) { p_38852_: Int,
this(p_38852_, inventory, null); inventory: Inventory,
} tile: BlockEntityDriveRack? = null
) : PoweredMatteryMenu(Registry.Menus.DRIVE_RACK, p_38852_, inventory, tile) {
val drives = arrayOfNulls<MatterySlot>(4)
public final MatterySlot[] drives = new MatterySlot[4]; init {
val container = tile?.drives ?: SimpleContainer(4)
public DriveRackMenu(int p_38852_, Inventory inventory, BlockEntityDriveRack tile) { for (i in 0 until container.containerSize) {
super(Registry.Menus.DRIVE_RACK, p_38852_, inventory, tile); val slot = DriveSlot(container, i)
drives[i] = slot
var container = tile != null ? tile.drives : new SimpleContainer(4); addSlot(slot)
for (int i = 0; i < container.getContainerSize(); i++) {
drives[i] = new MatterySlot(container, i) {
@Override
public boolean mayPlace(ItemStack p_40231_) {
return p_40231_.getCapability(MatteryCapability.DRIVE).isPresent();
}
};
addSlot(drives[i]);
} }
addBatterySlot(); addBatterySlot()
addInventorySlots(); addInventorySlots()
} }
@Override override fun getWorkingSlotStart(): Int {
protected int getWorkingSlotStart() { return 0
return 0;
} }
@Override override fun getWorkingSlotEnd(): Int {
protected int getWorkingSlotEnd() { return 5
return 5;
} }
} }

View File

@ -1,54 +1,43 @@
package ru.dbotthepony.mc.otm.menu; package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.entity.BlockEntityItemMonitor; import ru.dbotthepony.mc.otm.block.entity.BlockEntityItemMonitor
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier; import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView; import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper; import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import javax.annotation.Nonnull; class ItemMonitorMenu @JvmOverloads constructor(
p_38852_: Int,
inventory: Inventory,
tile: BlockEntityItemMonitor? = null
) : PoweredMatteryMenu(Registry.Menus.ITEM_MONITOR, p_38852_, inventory, tile), INetworkedItemViewSupplier {
@JvmField
val view = NetworkedItemView(inventory.player, this, tile == null)
public class ItemMonitorMenu extends PoweredMatteryMenu implements INetworkedItemViewSupplier { override fun getNetworkedItemView(): NetworkedItemView {
public final NetworkedItemView view; return view
@Nonnull
@Override
public NetworkedItemView getNetworkedItemView() {
return view;
} }
public ItemMonitorMenu(int p_38852_, Inventory inventory) { init {
this(p_38852_, inventory, null);
}
public ItemMonitorMenu(int p_38852_, Inventory inventory, BlockEntityItemMonitor tile) {
super(Registry.Menus.ITEM_MONITOR, p_38852_, inventory, tile);
view = new NetworkedItemView(inventory.player, this, tile == null);
if (tile != null) { if (tile != null) {
view.setComponent(tile.cell.getStorageGrid().getVirtualComponent(ItemStackWrapper.class)); view.setComponent(tile.cell.storageGrid!!.getVirtualComponent(ItemStackWrapper::class.java))
} }
addBatterySlot(); addBatterySlot()
addInventorySlots(); addInventorySlots()
} }
@Override override fun broadcastChanges() {
public void broadcastChanges() { super.broadcastChanges()
super.broadcastChanges(); view.network()
view.network();
} }
@Override override fun getWorkingSlotStart(): Int {
protected int getWorkingSlotStart() { return 0
return 0;
} }
@Override override fun getWorkingSlotEnd(): Int {
protected int getWorkingSlotEnd() { return 1
return 1;
} }
} }

View File

@ -1,11 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import net.minecraft.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageComponent<T extends IStorageStack> extends IStorageView<T>, IStorageConsumer<T> {
}

View File

@ -1,11 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import net.minecraft.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageConsumer<T extends IStorageStack> extends IStorageIdentity<T> {
T insertStack(T stack, boolean simulate);
}

View File

@ -1,11 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import net.minecraft.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageIdentity<T extends IStorageStack> {
Class<T> storageIdentity();
}

View File

@ -1,16 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import net.minecraft.MethodsReturnNonnullByDefault;
import ru.dbotthepony.mc.otm.core.Fraction;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import java.util.UUID;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageListener<T extends IStorageStack> {
void addObject(T stack, UUID id, IStorageView<T> provider);
void changeObject(UUID id, Fraction new_count);
void removeObject(UUID id);
}

View File

@ -1,65 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import net.minecraft.MethodsReturnNonnullByDefault;
import ru.dbotthepony.mc.otm.core.Fraction;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import java.util.Optional;
/**
* Interface implements all methods required for storage system functioning and interaction
* with your kind of items/objects/whatever.
*
* You can either implement this interface directly (hard dependency, discouraged, unless you do an addon to this storage system)
* or create a record class (preferred), which encapsulate your storage object.
*/
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageStack {
IStorageStack copy();
void setCount(Fraction value);
Fraction getCount();
boolean isEmpty();
/**
* @return max stack size for this stack object
* Optional.empty() if unlimited (default)
*/
default Optional<Fraction> getMaxStackSize() {
return Optional.empty();
}
/**
* @return 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.
*
* If implemented, and storage is also partitioned properly, then performance will be flat equally to view table's performance.
*
* Example: ItemStack#getItem()
*/
default Object partitionKey() {
return Object.class;
};
/**
* @param other other object to compare; if not the same of this object type just return false
* @return 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
*/
boolean sameItem(IStorageStack other);
default void grow(Fraction amount) {
setCount(getCount().plus(amount));
}
default void shrink(Fraction amount) {
setCount(getCount().minus(amount));
}
}

View File

@ -1,12 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import net.minecraft.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageTrigger<T extends IStorageStack> extends IStorageIdentity<T> {
boolean addListener(IStorageListener<T> listener);
boolean removeListener(IStorageListener<T> listener);
}

View File

@ -1,8 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import java.util.UUID;
public interface IStorageTuple<T extends IStorageStack> {
UUID id();
T stack();
}

View File

@ -1,83 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraftforge.common.util.LazyOptional;
import ru.dbotthepony.mc.otm.AbstractGrid;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.IStorageGridCell;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.*;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class StorageGrid extends AbstractGrid<IStorageGridCell> {
private final HashMap<Class<? extends IStorageStack>, VirtualComponent<? extends IStorageStack>> virtual_components = new HashMap<>();
public StorageGrid() {
super(MatteryCapability.STORAGE_CELL);
}
public <T extends IStorageStack> T insertObject(Class<T> type, T object, boolean simulate) {
return getVirtualComponent(type).insertStack(object, simulate);
}
/**
* @param type Class, representing identity of stored object
* @param <T> The identity itself
* @return a virtual IStorageComponent<T>, or null if storage grid contain no view for provided type
*/
@SuppressWarnings("unchecked")
public <T extends IStorageStack> VirtualComponent<T> getVirtualComponent(final Class<T> type) {
return (VirtualComponent<T>) virtual_components.computeIfAbsent(type, (k) -> new VirtualComponent<>(type));
}
public <T extends IStorageStack> void add(IStorageIdentity<T> identity) {
getVirtualComponent(identity.storageIdentity()).add(identity);
}
public <T extends IStorageStack> void remove(IStorageIdentity<T> identity) {
getVirtualComponent(identity.storageIdentity()).remove(identity);
}
@Override
protected void onAdded(IStorageGridCell cell) {
cell.setStorageGrid(this);
for (var identity : cell.getComponents()) {
add(identity);
}
}
@Override
protected void onRemoved(IStorageGridCell cell) {
cell.setStorageGrid(null);
for (var identity : cell.getComponents()) {
remove(identity);
}
}
public void detach(IStorageGridCell cell) {
if (cells.contains(cell)) {
for (var identity : cell.getComponents()) {
remove(identity);
}
}
}
public void attach(IStorageGridCell cell) {
if (cells.contains(cell)) {
for (var identity : cell.getComponents()) {
add(identity);
}
}
}
public static void scheduleDiscoverNeighbours(IStorageGridCell cell, Level level, BlockPos pos) {
OverdriveThatMatters.tickUntil(level, () -> !cell.isValidStorageCell() || cell.connectOrCreateStorageGrid(level, pos, true));
}
}

View File

@ -27,6 +27,6 @@ public class StorageObjectRegistry {
@Nonnull @Nonnull
public static <T extends IStorageStack> StorageObjectTuple<T> getOrError(Class<T> identity) { public static <T extends IStorageStack> StorageObjectTuple<T> getOrError(Class<T> identity) {
return Objects.requireNonNull(get(identity), "No storage mapping present for " + identity.toString()); return Objects.requireNonNull(get(identity), "No storage mapping present for " + identity);
} }
} }

View File

@ -1,6 +0,0 @@
package ru.dbotthepony.mc.otm.storage;
import java.util.UUID;
public record StorageTuple<T extends IStorageStack>(UUID id, T stack) implements IStorageTuple<T> {
}

View File

@ -1,111 +1,100 @@
package ru.dbotthepony.mc.otm.block.entity; package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos
import net.minecraft.core.BlockPos; import net.minecraft.core.Direction
import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
import ru.dbotthepony.mc.otm.capability.AbstractStorageGridCell; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage; import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainer; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.menu.DriveRackMenu; import ru.dbotthepony.mc.otm.menu.DriveRackMenu
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper; import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.storage.VirtualComponent; import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.storage.VirtualComponent
import javax.annotation.Nonnull; class BlockEntityDriveRack(p_155229_: BlockPos, p_155230_: BlockState) :
import javax.annotation.Nullable; BlockEntityMatteryPowered(Registry.BlockEntities.DRIVE_RACK, p_155229_, p_155230_) {
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
@MethodsReturnNonnullByDefault @JvmField
@ParametersAreNonnullByDefault val drives: MatteryContainer = object : MatteryContainer(this::setChanged, 4) {
public class BlockEntityDriveRack extends BlockEntityMatteryPowered { override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) {
public BlockEntityDriveRack(BlockPos p_155229_, BlockState p_155230_) { super.setChanged(slot, new_state, old_state)
super(Registry.BlockEntities.DRIVE_RACK, p_155229_, p_155230_);
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new Fraction(80_000));
}
public final MatteryContainer drives = new MatteryContainer(this::setChanged, 4) { old_state.getCapability(MatteryCapability.DRIVE).ifPresent {
@Override cell.computeIfAbsent(it.storageIdentity()) {c -> VirtualComponent(c)}.remove(it)
public void setChanged(int slot, ItemStack new_state, ItemStack old_state) { }
super.setChanged(slot, new_state, old_state);
old_state.getCapability(MatteryCapability.DRIVE).ifPresent((drive) -> { new_state.getCapability(MatteryCapability.DRIVE).ifPresent {
cell.computeIfAbsent(drive.storageIdentity(), VirtualComponent::new).remove(drive); cell.computeIfAbsent(it.storageIdentity()) {c -> VirtualComponent(c)}.add(it)
}); }
new_state.getCapability(MatteryCapability.DRIVE).ifPresent((drive) -> {
cell.computeIfAbsent(drive.storageIdentity(), VirtualComponent::new).add(drive);
});
} }
};
public final AbstractStorageGridCell cell = new AbstractStorageGridCell();
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
drives.deserializeNBT(nbt.getCompound("drives"));
} }
@Override val cell = BasicStorageGraphNode()
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("drives", drives.serializeNBT());
}
@Override override fun load(nbt: CompoundTag) {
public void setLevel(Level p_155231_) { super.load(nbt)
super.setLevel(p_155231_);
cell.scheduleDiscoverNeighbours(p_155231_, getBlockPos()); nbt.ifHas("drives", CompoundTag::class.java) {
} drives.deserializeNBT(it)
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.drive_rack");
@Override
protected Component getDefaultDisplayName() {
return NAME;
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new DriveRackMenu(containerID, inventory, this);
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (cap == MatteryCapability.STORAGE_CELL) {
return cell.get().cast();
} }
return super.getCapability(cap, side);
} }
@Override override fun saveAdditional(nbt: CompoundTag) {
public void invalidateCaps() { super.saveAdditional(nbt)
super.invalidateCaps(); nbt["drives"] = drives.serializeNBT()
cell.invalidate();
} }
@Override override fun setLevel(p_155231_: Level) {
public void reviveCaps() { super.setLevel(p_155231_)
super.reviveCaps();
cell.revive(); if (p_155231_ is ServerLevel)
StorageNetworkGraph.discoverFull(this, cell.getAsStorageNode())
}
init {
energy = MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, Fraction(80000))
}
override fun getDefaultDisplayName(): Component {
return NAME
}
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
return DriveRackMenu(containerID, inventory, this)
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
return if (cap === MatteryCapability.STORAGE_CELL) {
cell.get().cast()
} else super.getCapability(cap, side)
}
override fun invalidateCaps() {
super.invalidateCaps()
cell.invalidate()
}
override fun reviveCaps() {
super.reviveCaps()
cell.revive()
}
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.drive_rack")
} }
} }

View File

@ -1,79 +1,67 @@
package ru.dbotthepony.mc.otm.block.entity; package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos
import net.minecraft.core.BlockPos; import net.minecraft.core.Direction
import net.minecraft.core.Direction; import net.minecraft.network.chat.Component
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.common.util.LazyOptional; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
import ru.dbotthepony.mc.otm.capability.AbstractStorageGridCell; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu
import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu; import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
import javax.annotation.Nonnull; class BlockEntityItemMonitor(p_155229_: BlockPos, p_155230_: BlockState) :
import javax.annotation.Nullable; BlockEntityMatteryPowered(Registry.BlockEntities.ITEM_MONITOR, p_155229_, p_155230_) {
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
@MethodsReturnNonnullByDefault @JvmField
@ParametersAreNonnullByDefault val cell = BasicStorageGraphNode()
public class BlockEntityItemMonitor extends BlockEntityMatteryPowered {
public BlockEntityItemMonitor(BlockPos p_155229_, BlockState p_155230_) { init {
super(Registry.BlockEntities.ITEM_MONITOR, p_155229_, p_155230_); energy = MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, Fraction(80000))
energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new Fraction(80_000));
} }
public final AbstractStorageGridCell cell = new AbstractStorageGridCell(); override fun getDefaultDisplayName(): Component {
return NAME
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.item_storage_viewer");
@Override
protected Component getDefaultDisplayName() {
return NAME;
} }
@Nullable override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
@Override return ItemMonitorMenu(containerID, inventory, this)
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new ItemMonitorMenu(containerID, inventory, this);
} }
@Override override fun setLevel(p_155231_: Level) {
public void setLevel(Level p_155231_) { super.setLevel(p_155231_)
super.setLevel(p_155231_);
cell.scheduleDiscoverNeighbours(p_155231_, getBlockPos()); if (p_155231_ is ServerLevel)
StorageNetworkGraph.discoverFull(this, cell.getAsStorageNode())
} }
@Nonnull override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
@Override return if (cap === MatteryCapability.STORAGE_CELL) {
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { cell.get().cast()
if (cap == MatteryCapability.STORAGE_CELL) { } else super.getCapability(cap, side)
return cell.get().cast();
}
return super.getCapability(cap, side);
} }
@Override override fun invalidateCaps() {
public void invalidateCaps() { super.invalidateCaps()
super.invalidateCaps(); cell.invalidate()
cell.invalidate();
} }
@Override override fun reviveCaps() {
public void reviveCaps() { super.reviveCaps()
super.reviveCaps(); cell.revive()
cell.revive(); }
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.item_storage_viewer")
} }
} }

View File

@ -5,14 +5,23 @@ import ru.dbotthepony.mc.otm.menu.DriveRackMenu
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
class DriveRackScreen(menu: DriveRackMenu, inventory: Inventory?, title: Component?) : class DriveRackScreen(menu: DriveRackMenu, inventory: Inventory, title: Component) :
MatteryScreen<DriveRackMenu>(menu, inventory, title) { MatteryScreen<DriveRackMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel { override fun makeMainFrame(): FramePanel {
val frame = super.makeMainFrame()!! val frame = super.makeMainFrame()!!
PowerGaugePanel(this, frame, menu.battery_widget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
SlotPanel(this, frame, menu.battery_slot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
SlotPanel(this, frame, menu.drives[0], 71f, 32f)
SlotPanel(this, frame, menu.drives[1], 71f + 18f, 32f)
SlotPanel(this, frame, menu.drives[2], 71f, 32f + 18f)
SlotPanel(this, frame, menu.drives[3], 71f + 18f, 32f + 18f)
return frame return frame
} }

View File

@ -0,0 +1,90 @@
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.IStorageStack
import java.util.*
open class BasicStorageGraphNode : IStorageGraphNode {
private var resolver = LazyOptional.of<IStorageGraphNode> { this }
private var valid = true
protected val components = ArrayList<IStorageIdentity<*>>()
private val node = Graph6Node<IStorageGraphNode>(this)
override fun getAsStorageNode(): Graph6Node<IStorageGraphNode> {
return node
}
override fun getComponents(): List<IStorageIdentity<*>> {
return Collections.unmodifiableList(components)
}
fun <T : IStorageStack, U : IStorageIdentity<T>> computeIfAbsent(identity: Class<T>, provider: () -> 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) {
return component as U
}
}
val factory = provider(identity)
addStorageComponent(factory)
return factory
}
fun addStorageComponent(component: IStorageIdentity<*>) {
for (component1 in components) {
if (component === component1 || component1.storageIdentity() == component.storageIdentity()) {
return
}
}
detachStorage()
components.add(component)
attachStorage()
}
fun removeStorageComponent(component: IStorageIdentity<*>) {
for (component1 in components) {
if (component === component1 || component1.storageIdentity() == component.storageIdentity()) {
detachStorage()
components.remove(component1)
attachStorage()
return
}
}
}
fun invalidate() {
if (!valid) return
valid = false
resolver.invalidate()
// detachStorage();
}
fun revive() {
if (valid) return
valid = true
resolver = LazyOptional.of { this }
// attachStorage();
}
fun get(): LazyOptional<IStorageGraphNode> {
return if (valid) resolver else LazyOptional.empty()
}
override var storageGrid: StorageNetworkGraph? = null
}

View File

@ -1,26 +1,13 @@
package ru.dbotthepony.mc.otm.capability; package ru.dbotthepony.mc.otm.graph.storage
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.MethodsReturnNonnullByDefault
import net.minecraft.core.BlockPos; import ru.dbotthepony.mc.otm.graph.Graph6Node
import net.minecraft.core.Direction; import ru.dbotthepony.mc.otm.storage.IStorageIdentity
import net.minecraft.core.SectionPos; import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.storage.IStorageIdentity;
import ru.dbotthepony.mc.otm.storage.StorageGrid;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
import static ru.dbotthepony.mc.otm.AbstractGrid.createOrConnectGrid;
@MethodsReturnNonnullByDefault @MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public interface IStorageGridCell { interface IStorageGraphNode {
/** /**
* Return all providers that this cell can store. Or nothing, if it is not a storage. * Return all providers that this cell can store. Or nothing, if it is not a storage.
* *
@ -34,64 +21,13 @@ public interface IStorageGridCell {
* *
* @return a list of all providers, inheriting IStorageIdentity, or an empty list * @return a list of all providers, inheriting IStorageIdentity, or an empty list
*/ */
List<? extends IStorageIdentity<?>> getComponents(); fun getComponents(): Collection<IStorageIdentity<*>>
fun getComponentsForView(): Collection<IStorageIdentity<*>> = getComponents()
fun getComponentsForInterfaces(): Collection<IStorageIdentity<*>> = getComponents()
fun getComponentsForExporters(): Collection<IStorageIdentity<*>> = getComponents()
fun detachStorage() = storageGrid?.detach(getAsStorageNode())
fun attachStorage() = storageGrid?.attach(getAsStorageNode())
var storageGrid: StorageNetworkGraph?
default List<? extends IStorageIdentity<?>> getComponentsForView() { fun getAsStorageNode(): Graph6Node<IStorageGraphNode>
return getComponents();
}
default List<? extends IStorageIdentity<?>> getComponentsForInterfaces() {
return getComponents();
}
default List<? extends IStorageIdentity<?>> getComponentsForExporters() {
return getComponents();
}
default void detachStorage() {
var grid = getStorageGrid();
if (grid != null) {
grid.detach(this);
}
}
default void attachStorage() {
var grid = getStorageGrid();
if (grid != null) {
grid.attach(this);
}
}
@Nullable
StorageGrid getStorageGrid();
void setStorageGrid(@Nullable StorageGrid grid);
boolean isValidStorageCell();
default void scheduleDiscoverNeighbours(Level level, BlockPos pos) {
if (level instanceof ServerLevel)
StorageGrid.scheduleDiscoverNeighbours(this, level, pos);
}
default boolean connectOrCreateStorageGrid(Level level, BlockPos pos) {
return connectOrCreateStorageGrid(level, pos, false);
}
default void onNeighbourStorageCell(Level level, BlockPos pos, Direction direction, IStorageGridCell cell, BlockEntity entity) {
}
default boolean connectOrCreateStorageGrid(Level level, BlockPos pos, boolean force) {
return createOrConnectGrid(
this,
MatteryCapability.STORAGE_CELL,
level,
pos,
force,
StorageGrid::new,
IStorageGridCell::getStorageGrid,
this::onNeighbourStorageCell
);
}
} }

View File

@ -0,0 +1,117 @@
package ru.dbotthepony.mc.otm.graph.storage
import net.minecraft.MethodsReturnNonnullByDefault
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 javax.annotation.ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
class StorageNetworkGraph : Abstract6Graph<IStorageGraphNode>() {
private val virtualComponents = HashMap<Class<out IStorageStack>, VirtualComponent<out IStorageStack>>()
fun <T : IStorageStack> insertObject(type: Class<T>, obj: T, simulate: Boolean): T {
return getVirtualComponent(type).insertStack(obj, simulate)
}
/**
* @param type Class, representing identity of stored object
* @param <T> The identity itself
* @return a virtual IStorageComponent<T>
*/
fun <T : IStorageStack> getVirtualComponent(type: Class<T>): VirtualComponent<T> {
return virtualComponents.computeIfAbsent(type) { VirtualComponent(type) } as VirtualComponent<T>
}
fun <T : IStorageStack> add(identity: IStorageIdentity<T>) {
getVirtualComponent(identity.storageIdentity()).add(identity)
}
fun <T : IStorageStack> remove(identity: IStorageIdentity<T>) {
getVirtualComponent(identity.storageIdentity()).remove(identity)
}
override fun onNodeRemoved(node: Graph6Node<IStorageGraphNode>) {
node.value.storageGrid = null
for (identity in node.value.getComponents()) {
remove(identity)
}
}
override fun onNodeAdded(node: Graph6Node<IStorageGraphNode>) {
node.value.storageGrid = this
for (identity in node.value.getComponents()) {
add(identity)
}
}
fun detach(node: Graph6Node<IStorageGraphNode>) {
if (_nodes.contains(node)) {
for (identity in node.value.getComponents()) {
remove(identity)
}
}
}
fun attach(node: Graph6Node<IStorageGraphNode>) {
if (_nodes.contains(node)) {
for (identity in node.value.getComponents()) {
add(identity)
}
}
}
companion object {
@JvmStatic
fun discoverFull(tile: BlockEntity, node: Graph6Node<IStorageGraphNode>) {
if (tile.level !is ServerLevel)
return
return discoverFull(
tile.level!! as ServerLevel,
tile.blockPos,
node,
fun(_tile): Graph6Node<IStorageGraphNode>? {
val resolve = _tile.getCapability(MatteryCapability.STORAGE_CELL)
return if (resolve.isPresent) {
resolve.resolve().get().getAsStorageNode()
} else {
null
}
},
::StorageNetworkGraph
)
}
@JvmStatic
fun discover(tile: BlockEntity, node: Graph6Node<IStorageGraphNode>): Boolean {
if (tile.level !is ServerLevel)
return false
return discover(
tile.level!! as ServerLevel,
tile.blockPos,
node,
fun(_tile): Graph6Node<IStorageGraphNode>? {
val resolve = _tile.getCapability(MatteryCapability.STORAGE_CELL)
return if (resolve.isPresent) {
resolve.resolve().get().getAsStorageNode()
} else {
null
}
},
::StorageNetworkGraph
)
}
}
}

View File

@ -42,3 +42,9 @@ open class PatternSlot(p_40223_: Container, index: Int, x: Int = 0, y: Int = 0)
return p_40231_.getCapability(MatteryCapability.PATTERN).isPresent return p_40231_.getCapability(MatteryCapability.PATTERN).isPresent
} }
} }
open class DriveSlot(p_40223_: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(p_40223_, index, x, y) {
override fun mayPlace(p_40231_: ItemStack): Boolean {
return p_40231_.getCapability(MatteryCapability.DRIVE).isPresent
}
}

View File

@ -0,0 +1,156 @@
package ru.dbotthepony.mc.otm.storage
import ru.dbotthepony.mc.otm.core.Fraction
import java.util.*
interface IStorageStack {
fun copy(): IStorageStack
var count: Fraction
fun isEmpty(): Boolean
/**
* @return max stack size for this stack object
* [Optional.empty()] if unlimited (default)
*/
fun getMaxStackSize(): Optional<Fraction> = Optional.empty()
/**
* 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.
*
* If implemented, and storage is also partitioned properly, then performance will be flat equally to view table's performance.
*
* Example: ItemStack#item
*/
fun partitionKey(): Any {
return Any::class.java
}
/**
* [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
*/
fun sameItem(other: IStorageStack): Boolean
fun grow(amount: Fraction) {
count += amount
}
fun shrink(amount: Fraction) {
count -= amount
}
}
/**
* Storage system root, along IStorageStack interface
*/
interface IStorageIdentity<T : IStorageStack> {
fun storageIdentity(): Class<T>
}
interface IStorageTrigger<T : IStorageStack> : IStorageIdentity<T> {
/**
* [listener] is [IStorageListener] which want to subscribe to our events
*/
fun addListener(listener: IStorageListener<T>): Boolean
/**
* [listener] is [IStorageListener] which want to unsubscribe from our events
*/
fun removeListener(listener: IStorageListener<T>): Boolean
}
interface IStorageConsumer<T : IStorageStack> : IStorageIdentity<T> {
fun insertStack(stack: T, simulate: Boolean): T
}
interface IStorageView<T : IStorageStack> : IStorageTrigger<T> {
/**
* @param id identifier of object
* @return stored object (not a copy). Do not edit it.
*/
fun getStack(id: UUID): T
/**
* @param id identifier of object 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
*/
fun extractStack(id: UUID, amount: Fraction, simulate: Boolean): T
/**
* Designed for views, for extraction with less computation overhead caused by
* copying object extracted
*
* @param id identifier of object to extract
* @param amount desired amount to extract
* @param simulate whenever to simulate the action or not
* @return amount extracted
*/
fun extractStackCount(id: UUID, amount: Fraction, simulate: Boolean): Fraction? {
return extractStack(id, amount, simulate).count
}
fun getStacks(): Collection<IStorageTuple<T>>
fun addListenerAuto(listener: IStorageListener<T>): Boolean {
if (addListener(listener)) {
for (stack in getStacks()) {
listener.addObject(stack.stack(), stack.id(), this)
}
return true
}
return false
}
fun removeListenerAuto(listener: IStorageListener<T>): Boolean {
if (removeListener(listener)) {
for (stack in getStacks()) {
listener.removeObject(stack.id())
}
return true
}
return false
}
}
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>)
/**
* Fired on whenever an object is changes on listener we subscribed to
*/
fun changeObject(id: UUID, new_count: Fraction)
/**
* Fired on whenever an object is removed from listener we subscribed to
*/
fun removeObject(id: UUID)
}
interface IStorageTuple<T : IStorageStack> {
fun id(): UUID
fun stack(): T
}
@JvmRecord
data class StorageTuple<T : IStorageStack>(private val id: UUID, private val stack: T) : IStorageTuple<T> {
override fun id(): UUID = id
override fun stack(): T = stack
}
interface IStorageComponent<T : IStorageStack> : IStorageView<T>, IStorageConsumer<T>

View File

@ -1,67 +1,4 @@
package ru.dbotthepony.mc.otm.storage; package ru.dbotthepony.mc.otm.storage
import ru.dbotthepony.mc.otm.core.Fraction
import net.minecraft.MethodsReturnNonnullByDefault; import java.util.*
import ru.dbotthepony.mc.otm.core.Fraction;
import javax.annotation.ParametersAreNonnullByDefault;
import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public interface IStorageView<T extends IStorageStack> extends IStorageTrigger<T> {
/**
* @param id identifier of object
* @return stored object (not a copy). Do not edit it.
*/
T getStack(UUID id);
/**
* @param id identifier of object 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
*/
T extractStack(UUID id, Fraction amount, boolean simulate);
/**
* Designed for views, for extraction with less computation overhead caused by
* copying object extracted
*
* @param id identifier of object to extract
* @param amount desired amount to extract
* @param simulate whenever to simulate the action or not
* @return amount extracted
*/
default Fraction extractStackCount(UUID id, Fraction amount, boolean simulate) {
return extractStack(id, amount, simulate).getCount();
}
List<IStorageTuple<T>> getStacks();
default boolean addListenerAuto(IStorageListener<T> listener) {
if (addListener(listener)) {
for (var stack : getStacks()) {
listener.addObject(stack.stack(), stack.id(), this);
}
return true;
}
return false;
}
default boolean removeListenerAuto(IStorageListener<T> listener) {
if (removeListener(listener)) {
for (var stack : getStacks()) {
listener.removeObject(stack.id());
}
return true;
}
return false;
}
}

View File

@ -1,64 +1,44 @@
package ru.dbotthepony.mc.otm.storage; package ru.dbotthepony.mc.otm.storage
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.ItemStack; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.Fraction; import java.util.*
import javax.annotation.ParametersAreNonnullByDefault; @JvmRecord
import java.math.BigDecimal; data class ItemStackWrapper(val stack: ItemStack) : IStorageStack {
import java.util.Optional; override fun copy(): IStorageStack {
return ItemStackWrapper(stack.copy())
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public record ItemStackWrapper(ItemStack stack) implements IStorageStack {
public static final ItemStackWrapper EMPTY = new ItemStackWrapper(ItemStack.EMPTY);
@Override
public IStorageStack copy() {
return new ItemStackWrapper(stack.copy());
} }
@Override fun setCount(value: Int) {
public void setCount(Fraction value) { stack.count = Math.max(value, 0)
setCount(value.toInt());
} }
public void setCount(int value) { override var count: Fraction
stack.setCount(Math.max(value, 0)); get() = Fraction(stack.getCount())
set(value) = setCount(value.toInt())
fun getCountInt() = stack.count
override fun getMaxStackSize(): Optional<Fraction> {
return Optional.of(Fraction(stack.maxStackSize))
} }
@Override override fun isEmpty(): Boolean = stack.isEmpty
public Fraction getCount() { override fun partitionKey(): Any = stack.item
return new Fraction(stack.getCount());
override fun sameItem(other: IStorageStack): Boolean {
if (this === other)
return true
if (other is ItemStackWrapper)
return ItemStack.isSameItemSameTags(stack, other.stack);
return false
} }
public int getCountInt() { companion object {
return stack.getCount(); @JvmField
} val EMPTY = ItemStackWrapper(ItemStack.EMPTY)
@Override
public Optional<Fraction> getMaxStackSize() {
return Optional.of(new Fraction(stack.getMaxStackSize()));
}
@Override
public boolean isEmpty() {
return stack.isEmpty();
}
@Override
public Object partitionKey() {
return stack.getItem();
}
@Override
public boolean sameItem(IStorageStack other) {
if (other == this)
return true;
if (other instanceof ItemStackWrapper obj)
return ItemStack.isSameItemSameTags(stack, obj.stack);
return false;
} }
} }