Skip to content

Commit

Permalink
Port large and indexed inventory to common
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensworks committed Oct 6, 2024
1 parent 394e3be commit e3219e9
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.cyclops.cyclopscore.datastructure;

import it.unimi.dsi.fastutil.ints.IntIterator;

import java.util.PrimitiveIterator;

/**
* @author rubensworks
*/
public class WrappedIntIterator implements PrimitiveIterator.OfInt {

private final IntIterator it;

public WrappedIntIterator(IntIterator it) {
this.it = it;
}

@Override
public int nextInt() {
return it.nextInt();
}

@Override
public boolean hasNext() {
return it.hasNext();
}

@Override
public Integer next() {
return it.next();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package org.cyclops.cyclopscore.inventory;

import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.cyclops.cyclopscore.datastructure.WrappedIntIterator;

import java.util.Map;
import java.util.PrimitiveIterator;

/**
* An inventory that adds an index from item to slot on a regular inventory.
* @author rubensworks
*
*/
public class IndexedInventoryCommon extends LargeInventoryCommon {

private final Map<Item, Int2ObjectMap<ItemStack>> index = Maps.newIdentityHashMap();
private IntSet emptySlots;
private IntSet nonEmptySlots;

/**
* Default constructor for NBT persistence, don't call this yourself.
*/
public IndexedInventoryCommon() {
this(0, 0);
}

/**
* Make a new instance.
* @param size The amount of slots in the inventory.
* @param stackLimit The stack limit for each slot.
*/
public IndexedInventoryCommon(int size, int stackLimit) {
super(size, stackLimit);
this.emptySlots = new IntAVLTreeSet();
this.nonEmptySlots = new IntAVLTreeSet();
createIndex();
}

protected void createIndex() {
this.index.clear();
this.nonEmptySlots.clear();
this.emptySlots.clear();
for (int i = 0; i < getContainerSize(); i++) {
ItemStack itemStack = getItem(i);
if (!itemStack.isEmpty()) {
Int2ObjectMap<ItemStack> stacks = index.get(itemStack.getItem());
if (stacks == null) {
stacks = new Int2ObjectOpenHashMap<>();
index.put(itemStack.getItem(), stacks);
}
stacks.put(i, itemStack);
this.nonEmptySlots.add(i);
} else {
this.emptySlots.add(i);
}
}
}

@Override
public void readFromNBT(HolderLookup.Provider provider, CompoundTag data, String tag) {
super.readFromNBT(provider, data, tag);
createIndex();
}

@Override
public void setItem(int slotId, ItemStack itemStack) {
// Update index
ItemStack oldStack = getItem(slotId);
boolean wasEmpty = oldStack.isEmpty();
boolean isEmpty = itemStack.isEmpty();
if (!oldStack.isEmpty()) {
Int2ObjectMap<ItemStack> stacks = index.get(oldStack.getItem());
if (stacks != null) {
stacks.remove(slotId);
}
if (stacks.isEmpty()) {
index.remove(oldStack.getItem());
}
}
if (!itemStack.isEmpty()) {
Int2ObjectMap<ItemStack> stacks = index.get(itemStack.getItem());
if (stacks == null) {
stacks = new Int2ObjectOpenHashMap<>();
index.put(itemStack.getItem(), stacks);
}
stacks.put(slotId, itemStack);
}

// Call super
super.setItem(slotId, itemStack);

// Update first and last values
if (wasEmpty && !isEmpty) {
this.emptySlots.remove(slotId);
this.nonEmptySlots.add(slotId);
}
if (!wasEmpty && isEmpty) {
this.emptySlots.add(slotId);
this.nonEmptySlots.remove(slotId);
}

// This is unit-tested, so this *should not* be able to happen.
// If it happens, trigger a crash!
if (this.nonEmptySlots.size() + this.emptySlots.size() != getContainerSize()) throw new IllegalStateException(String.format(
"Indexed inventory at inconsistent state %s %s %s (slot: %s).", this.nonEmptySlots, this.emptySlots, this.getContainerSize(), slotId));
}

@Override
public void clearContent() {
super.clearContent();
index.clear();
}

public int getInventoryReferenceStackLimit() {
return getMaxStackSize();
}

public Map<Item, Int2ObjectMap<ItemStack>> getIndex() {
return index;
}

public PrimitiveIterator.OfInt getEmptySlots() {
return new WrappedIntIterator(this.emptySlots.iterator());
}

public PrimitiveIterator.OfInt getNonEmptySlots() {
return new WrappedIntIterator(this.nonEmptySlots.iterator());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.cyclops.cyclopscore.inventory;

import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.item.ItemStack;

/**
* A large inventory implementation.
* @author rubensworks
*
*/
public class LargeInventoryCommon extends SimpleInventoryCommon {

/**
* Default constructor for NBT persistence, don't call this yourself.
*/
public LargeInventoryCommon() {
this(0, 0);
}

/**
* Make a new instance.
* @param size The amount of slots in the inventory.
* @param stackLimit The stack limit for each slot.
*/
public LargeInventoryCommon(int size, int stackLimit) {
super(size, stackLimit);
}

public void readFromNBT(HolderLookup.Provider provider, CompoundTag data, String tag) {
ListTag nbttaglist = data.getList(tag, Tag.TAG_COMPOUND);

for (int j = 0; j < getContainerSize(); ++j)
contents[j] = ItemStack.EMPTY;

for (int j = 0; j < nbttaglist.size(); ++j) {
CompoundTag slot = nbttaglist.getCompound(j);
int index;
if (slot.contains("index")) {
index = slot.getInt("index");
} else {
index = slot.getInt("Slot");
}
if (index >= 0 && index < getContainerSize()) {
contents[index] = ItemStack.parseOptional(provider, slot);
}
}
}

public void writeToNBT(HolderLookup.Provider provider, CompoundTag data, String tag) {
ListTag slots = new ListTag();
for (int index = 0; index < getContainerSize(); ++index) {
ItemStack itemStack = getItem(index);
if (!itemStack.isEmpty() && itemStack.getCount() > 0) {
CompoundTag slot = new CompoundTag();
slot.putInt("Slot", index);
slots.add(itemStack.save(provider, slot));
}
}
data.put(tag, slots);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* @author rubensworks
*
*/
@Deprecated // TODO: rm in next major, after porting IndexedSlotlessItemHandlerWrapper.IInventoryIndexReference
public class IndexedInventory extends LargeInventory implements IndexedSlotlessItemHandlerWrapper.IInventoryIndexReference {

private final Map<Item, Int2ObjectMap<ItemStack>> index = Maps.newIdentityHashMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* @author rubensworks
*
*/
@Deprecated // TODO: rm in next major
public class LargeInventory extends SimpleInventory {

/**
Expand Down

0 comments on commit e3219e9

Please sign in to comment.