Skip to content

Commit

Permalink
Extending IItemRepository API plus predicate support
Browse files Browse the repository at this point in the history
  • Loading branch information
jaquadro committed Jul 7, 2017
1 parent 2e820c3 commit e3ee54e
Show file tree
Hide file tree
Showing 10 changed files with 380 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@
import net.minecraft.util.NonNullList;

import javax.annotation.Nonnull;
import java.util.function.Predicate;

/**
* An interface for treating an inventory as a slotless, central repository of items.
*
* For all operations that accept a predicate, if a predicate is supplied, a stored ItemStack must pass the predicate
* in order to be considered for the given operation.
*
* An IItemRepository implementation MAY relax or eliminate its own internal tests when a predicate is supplied. If
* the predicate is derived from DefaultPredicate, then the implementation MUST apply any tests it would have applied
* had no predicate been provided at all, in addition to testing the predicate itself.
*/
public interface IItemRepository
{
/**
* Gets a list of all items in the inventory. The same item may appear multiple times with varying counts.
*
* @return A list of zero or more items in the inventory.
*/
@Nonnull
Expand All @@ -20,24 +31,90 @@ public interface IItemRepository
*
* @param stack ItemStack to insert.
* @param simulate If true, the insertion is only simulated
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The remaining ItemStack that was not inserted. If the entire stack was accepted, returns
* ItemStack.EMPTY instead.
*/
@Nonnull
ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate);
ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate, Predicate<ItemStack> predicate);

@Nonnull
default ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate) {
return insertItem(stack, simulate, null);
}

/**
* Tries to extract the given ItemStack from the inventory. The returned value will be a matching ItemStack
* with a stack size equal to or less than amount, or the empty ItemStack if the item could not be found at all.
* The returned stack size may exceed the itemstack's getMaxStackSize() value.
*
* The returned stack size may exceed the ItemStack's getMaxStackSize() value.
* @param stack The item to extract. The stack size is ignored.
* @param amount Amount to extract (may be greater than the stacks max limit)
* @param simulate If true, the extraction is only simulated
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return ItemStack extracted from the inventory, or ItemStack.EMPTY if nothing could be extracted.
*/
@Nonnull
ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simulate);
ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simulate, Predicate<ItemStack> predicate);

@Nonnull
default ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simulate) {
return extractItem(stack, amount, simulate, null);
}

/**
* Gets the number of items matching the given ItemStack stored by the inventory.
* @param stack ItemStack to query.
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The number of stored matching items. A value of Integer.MAX_VALUE may indicate an infinite item source.
*/
default int getStoredItemCount (@Nonnull ItemStack stack, Predicate<ItemStack> predicate) {
ItemStack amount = extractItem(stack, Integer.MAX_VALUE, true, predicate);
return amount.getCount();
}

default int getStoredItemCount (@Nonnull ItemStack stack) {
return getStoredItemCount(stack, null);
}

/**
* Gets the number items matching the given ItemStack that additionally still be stored by the inventory.
* Remaining capacity may include space that is internally empty or unassigned to any given item.
*
* @param stack ItemStack to query.
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The available remaining space for matching items.
*/
default int getRemainingItemCapacity (@Nonnull ItemStack stack, Predicate<ItemStack> predicate) {
stack = stack.copy();
stack.setCount(Integer.MAX_VALUE);
ItemStack remainder = insertItem(stack, true, predicate);
return Integer.MAX_VALUE - remainder.getCount();
}

default int getRemainingItemCapacity (@Nonnull ItemStack stack) {
return getRemainingItemCapacity(stack, null);
}

/**
* Gets the total inventory capacity for items matching the given ItemStack.
* Total capacity may include space that is internally empty or unassigned to any given item.
*
* @param stack ItemStack to query.
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The total capacity for matching items.
*/
default int getItemCapacity (@Nonnull ItemStack stack, Predicate<ItemStack> predicate) {
long capacity = getStoredItemCount(stack, predicate) + getRemainingItemCapacity(stack, predicate);
if (capacity > Integer.MAX_VALUE)
return Integer.MAX_VALUE;
return (int)capacity;
}

default int getItemCapacity (@Nonnull ItemStack stack) {
return getItemCapacity(stack, null);
}

/**
* An item record representing an item and the amount stored.
Expand All @@ -56,4 +133,11 @@ public ItemRecord (@Nonnull ItemStack itemPrototype, int count) {
this.count = count;
}
}

/**
* A variant of the standard Predicate interface that when passed to IItemRepository functions, will ask the
* internal default predicate to be tested in addition to the custom predicate. An IItemRepository function
* may choose to enforce its own predicate regardless.
*/
interface DefaultPredicate<T> extends Predicate<T> { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.minecraft.item.ItemStack;

import javax.annotation.Nonnull;
import java.util.function.Predicate;

public class Drawers
{
Expand Down Expand Up @@ -44,12 +45,12 @@ public int getRemainingCapacity () {
}

@Override
public boolean canItemBeStored (@Nonnull ItemStack itemPrototype) {
public boolean canItemBeStored (@Nonnull ItemStack itemPrototype, Predicate<ItemStack> matchPredicate) {
return false;
}

@Override
public boolean canItemBeExtracted (@Nonnull ItemStack itemPrototype) {
public boolean canItemBeExtracted (@Nonnull ItemStack itemPrototype, Predicate<ItemStack> matchPredicate) {
return false;
}

Expand Down
35 changes: 23 additions & 12 deletions src/com/jaquadro/minecraft/storagedrawers/api/storage/IDrawer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.minecraft.item.ItemStack;

import javax.annotation.Nonnull;
import java.util.function.Predicate;

public interface IDrawer
{
Expand Down Expand Up @@ -113,26 +114,36 @@ default int getStoredItemStackSize () {
}

/**
* Gets whether or not an item of the given type and data can be stored in this drawer.
* Gets whether or not an item of the given type and data can be stored in this drawer using a custom matching
* predicate. If matchPredicate is null, the drawer's default item matching rules are applied instead.
*
* Stack size and available capacity are not considered. For drawers that are not empty, this
* method can allow ore-dictionary compatible items to be accepted into the drawer, as defined by what
* the drawer considers to be an equivalent item.
* For drawers that are empty, locking status is considered.
* Some attributes, like locking status, are considered regardless of the predicate.
*
* @param itemPrototype An ItemStack representing the type, metadata, and tags of an item.
* @param itemPrototype An ItemStack representing the type, metadata, and tags of an item.
* @param matchPredicate A custom predicate for testing the stored ItemStack for equivalence.
* @return
*/
boolean canItemBeStored (@Nonnull ItemStack itemPrototype);
boolean canItemBeStored (@Nonnull ItemStack itemPrototype, Predicate<ItemStack> matchPredicate);

default boolean canItemBeStored (@Nonnull ItemStack itemPrototype) {
return canItemBeStored(itemPrototype, null);
}

/**
* Gets whether or not an item of the given type and data can be extracted from this drawer.
* Gets whether or not an item of the given type and data can be extracted from this drawer using a custom matching
* predicate. If matchPredicate is null, the drawer's default item matching rules are applied instead.
*
* This is intended to allow outbound ore-dictionary conversions of compatible items, as defined by what
* the drawer considers to be an equivalent item.
* This is intended to allow outbound conversions of compatible items, as defined by what the drawer or predicate
* considers to be an equivalent item.
*
* @param itemPrototype An ItemStack representing the type, metadata, and tags of an item.
* @param itemPrototype An ItemStack representing the type, metadata, and tags of an item.
* @param matchPredicate A custom predicate for testing the stored ItemStack for equivalence.
*/
boolean canItemBeExtracted (@Nonnull ItemStack itemPrototype);
boolean canItemBeExtracted (@Nonnull ItemStack itemPrototype, Predicate<ItemStack> matchPredicate);

default boolean canItemBeExtracted (@Nonnull ItemStack itemPrototype) {
return canItemBeExtracted(itemPrototype, null);
}

/**
* Gets whether or not the drawer has items.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.jaquadro.minecraft.storagedrawers.api.storage.attribute.IProtectable;
import com.jaquadro.minecraft.storagedrawers.api.storage.attribute.LockAttribute;
import com.jaquadro.minecraft.storagedrawers.block.BlockSlave;
import com.jaquadro.minecraft.storagedrawers.capabilities.DrawerGroupItemRepository;
import com.jaquadro.minecraft.storagedrawers.core.ModBlocks;
import com.jaquadro.minecraft.storagedrawers.inventory.DrawerItemHandler;
import com.jaquadro.minecraft.storagedrawers.security.SecurityManager;
Expand All @@ -34,6 +35,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Predicate;

public class TileEntityController extends TileEntity implements IDrawerGroup
{
Expand Down Expand Up @@ -214,7 +216,7 @@ public int interactPutItemsIntoInventory (EntityPlayer player) {
}

protected int insertItems (@Nonnull ItemStack stack, GameProfile profile) {
int remainder = new ProtectedItemRepository(profile).insertItem(stack, false).getCount();
int remainder = new ProtectedItemRepository(this, profile).insertItem(stack, false).getCount();
int added = stack.getCount() - remainder;

stack.setCount(remainder);
Expand Down Expand Up @@ -652,7 +654,7 @@ public IItemRepository getItemRepository () {
static Capability<IDrawerGroup> DRAWER_GROUP_CAPABILITY = null;

private DrawerItemHandler itemHandler = new DrawerItemHandler(this);
private ItemRepository itemRepository = new ItemRepository();
private ItemRepository itemRepository = new ItemRepository(this);

@Override
public boolean hasCapability (@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
Expand All @@ -675,28 +677,15 @@ public <T> T getCapability (@Nonnull Capability<T> capability, @Nullable EnumFac
return super.getCapability(capability, facing);
}

private class ItemRepository implements IItemRepository
private class ItemRepository extends DrawerGroupItemRepository
{
@Nonnull
@Override
public NonNullList<ItemRecord> getAllItems () {
NonNullList<ItemRecord> records = NonNullList.create();

for (int slot : drawerSlots) {
IDrawer drawer = getDrawer(slot);
if (drawer.isEmpty())
continue;

ItemStack stack = drawer.getStoredItemPrototype();
records.add(new ItemRecord(stack, drawer.getStoredItemCount()));
}

return records;
public ItemRepository (IDrawerGroup group) {
super(group);
}

@Nonnull
@Override
public ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate) {
public ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate, Predicate<ItemStack> predicate) {
Collection<SlotRecord> primaryRecords = drawerPrimaryLookup.getEntries(stack.getItem(), stack.getMetadata());
Set<Integer> checkedSlots = (simulate) ? new HashSet<>() : null;

Expand All @@ -708,7 +697,11 @@ public ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate) {
continue;

IDrawer drawer = candidateGroup.getDrawer(record.slot);
if (drawer.isEmpty() || !drawer.canItemBeStored(stack) || !hasAccess(candidateGroup, drawer))
if (drawer.isEmpty())
continue;
if (!testPredicateInsert(drawer, stack, predicate))
continue;
if (!hasAccess(candidateGroup, drawer))
continue;

amount = (simulate)
Expand All @@ -725,7 +718,11 @@ public ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate) {

for (int slot : drawerSlots) {
IDrawer drawer = getDrawer(slot);
if (!drawer.isEnabled() || !drawer.canItemBeStored(stack) || !hasAccess(getGroupForDrawerSlot(slot), drawer))
if (!drawer.isEnabled())
continue;
if (!testPredicateInsert(drawer, stack, predicate))
continue;
if (!hasAccess(getGroupForDrawerSlot(slot), drawer))
continue;
if (simulate && checkedSlots.contains(slot))
continue;
Expand All @@ -746,7 +743,7 @@ public ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate) {

@Nonnull
@Override
public ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simulate) {
public ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simulate, Predicate<ItemStack> predicate) {
Collection<SlotRecord> primaryRecords = drawerPrimaryLookup.getEntries(stack.getItem(), stack.getMetadata());
Set<Integer> checkedSlots = (simulate) ? new HashSet<>() : null;

Expand All @@ -757,7 +754,11 @@ public ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simu
continue;

IDrawer drawer = candidateGroup.getDrawer(record.slot);
if (!drawer.canItemBeExtracted(stack) || !hasAccess(candidateGroup, drawer))
if (!drawer.isEnabled())
continue;
if (!testPredicateExtract(drawer, stack, predicate))
continue;
if (!hasAccess(candidateGroup, drawer))
continue;

remaining = (simulate)
Expand All @@ -773,11 +774,17 @@ public ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simu

for (int slot : drawerSlots) {
IDrawer drawer = getDrawer(slot);
if (!drawer.canItemBeExtracted(stack) || !hasAccess(getGroupForDrawerSlot(slot), drawer))
if (!drawer.isEnabled())
continue;
if (!testPredicateExtract(drawer, stack, predicate))
continue;
if (simulate && checkedSlots.contains(slot))
continue;

remaining = (simulate)
? Math.max(remaining - drawer.getStoredItemCount(), 0)
: drawer.adjustStoredItemCount(-remaining);

if (remaining == 0)
return stackResult(stack, amount);
}
Expand All @@ -790,19 +797,14 @@ public ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simu
protected boolean hasAccess (IDrawerGroup group, IDrawer drawer) {
return true;
}

private ItemStack stackResult (@Nonnull ItemStack stack, int amount) {
ItemStack result = stack.copy();
result.setCount(amount);
return result;
}
}

private class ProtectedItemRepository extends ItemRepository
{
private GameProfile profile;

public ProtectedItemRepository (GameProfile profile) {
public ProtectedItemRepository (IDrawerGroup group, GameProfile profile) {
super(group);
this.profile = profile;
}

Expand Down
Loading

0 comments on commit e3ee54e

Please sign in to comment.