Skip to content

ItemStack Attributes

AlexIIL edited this page Jan 18, 2020 · 4 revisions

A small example, for storing an int-based value called "fmc".

interface FmcStorage {
    int getStoredFmc();

    /** @return The amount extracted */
    int extractFmc(int max);

    // I'm leaving off insert for simplicities sake
}
public static final Attribute<FmcStorage> ATTRIBUTE = Attributes.create(FmcStorage.class);
class FmcItemBasedStorage implements FmcStorage {
    final Reference<ItemStack> stackRef;
    final LimitedConsumer<ItemStack> excess;

    @Override
    int getStoredFmc() {
        ItemStack stack = stackRef.get();
        if (stack.isEmpty() || stack.getItem() != TheContainingItem.this) {
            return 0;
        }
        CompoundTag tag = stack.getTag();
        if (tag != null) {
            return tag.getInt("FmcValue"):
        }
        return 0;
    }

    @Override
    int extractFmc(int max) {
        ItemStack stack = stackRef.get();
        if (stack.isEmpty() || stack.getItem() != TheContainingItem.this) {
            return 0;
        }
        CompoundTag tag = stack.getTag();
        if (tag != null) {
            int current = tag.getInt("FmcValue"):
            int toExtract = Math.min(max, current);
            if (toExtract <= 0) {
                return 0;
            }
            int leftover = current - toExtract;
            ItemStack oldStack = stack.copy();
            ItemStack newStack = stack.split(1);
            newStack.getTag().putInt("FmcValue", leftover);
            if (setStacks(Simulation.ACTION, oldStack, newStack)) {
                return toExtract;
            }
        }
        return 0;
    }

    // NOTE: This will be a util method in LBA 0.6.4 (unreleased)
    // You'll get this for free by extending AbstractItemBasedAttribute
    // (Which also doesn't exist yet, but will in 0.6.4)
    /** Attempts to place the stacks in the reference and excess.
     * 
     * @param oldStack A copied stack from {@link #stackRef}, but decreased by 1.
     * @param newStack The modified stack that was split off from {@link #stackRef}. */
    protected boolean setStacks(Simulation simulation, ItemStack oldStack, ItemStack newStack) {
        if (oldStack.isEmpty() && stackRef.set(newStack, simulation)) {
            return true;
        } else if (stackRef.isValid(oldStack) && excessStacks.offer(newStack, simulation)) {
            boolean did = stackRef.set(oldStack, simulation);
            if (!did) {
                throw new IllegalStateException(
                    "Failed to set the stack! (Even though we just checked this up above...)" //
                        + "\n\tstackRef = " + stackRef + "\n\tstack = " + oldStack
                );
            }
            return true;
        } else {
            return false;
        }
    }
}

You could then call this in a method like Item.onUse with something like this:

@Override
ActionResult onUse(PlayerEntity player, Hand hand) {
    Reference<ItemStack> ref = ItemInvUtil.referenceHand(player, hand);
    LimitedConsumer<ItemStack> excess = LimitedConsumer.fromConsumer(ItemInvUtil.createPlayerInsertable(player));
    FmcStorage storage = ATTRIBUTE.get(ref, excess);
    if (storage != null) {
        // A real item would probably have a "simulated" extract before the real extraction
        int extracted = storage.extract(1);
        if (extracted > 0) {
            doSomethingMagical();
            return ActionResult.SUCCESS;
        }
    }
    return ActionResult.PASS;
}

Clone this wiki locally