-
Notifications
You must be signed in to change notification settings - Fork 12
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;
}