mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-22 23:58:02 -05:00
Work around vanilla capturing ItemStack references (#1700)
This commit is contained in:
parent
ffb6d41e97
commit
86bae2c0e9
3 changed files with 52 additions and 1 deletions
|
@ -115,6 +115,7 @@ public abstract class SingleStackStorage extends SnapshotParticipant<ItemStack>
|
|||
|
||||
if (insertedAmount > 0) {
|
||||
updateSnapshots(transaction);
|
||||
currentStack = getStack();
|
||||
|
||||
if (currentStack.isEmpty()) {
|
||||
currentStack = insertedVariant.toStack(insertedAmount);
|
||||
|
@ -142,6 +143,7 @@ public abstract class SingleStackStorage extends SnapshotParticipant<ItemStack>
|
|||
|
||||
if (extracted > 0) {
|
||||
this.updateSnapshots(transaction);
|
||||
currentStack = getStack();
|
||||
currentStack.decrement(extracted);
|
||||
setStack(currentStack);
|
||||
}
|
||||
|
@ -154,7 +156,9 @@ public abstract class SingleStackStorage extends SnapshotParticipant<ItemStack>
|
|||
|
||||
@Override
|
||||
protected final ItemStack createSnapshot() {
|
||||
return getStack().copy();
|
||||
ItemStack original = getStack();
|
||||
setStack(original.copy());
|
||||
return original;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -34,6 +34,7 @@ class InventorySlotWrapper extends SingleStackStorage {
|
|||
*/
|
||||
private final InventoryStorageImpl storage;
|
||||
final int slot;
|
||||
private ItemStack lastReleasedSnapshot = null;
|
||||
|
||||
InventorySlotWrapper(InventoryStorageImpl storage, int slot) {
|
||||
this.storage = storage;
|
||||
|
@ -66,4 +67,25 @@ class InventorySlotWrapper extends SingleStackStorage {
|
|||
storage.markDirtyParticipant.updateSnapshots(transaction);
|
||||
super.updateSnapshots(transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseSnapshot(ItemStack snapshot) {
|
||||
lastReleasedSnapshot = snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinalCommit() {
|
||||
// Try to apply the change to the original stack
|
||||
ItemStack original = lastReleasedSnapshot;
|
||||
ItemStack currentStack = getStack();
|
||||
|
||||
if (!original.isEmpty() && !currentStack.isEmpty() && ItemStack.canCombine(original, currentStack)) {
|
||||
// None is empty and the contents match: just update the amount and reuse the original stack.
|
||||
original.setCount(currentStack.getCount());
|
||||
setStack(original);
|
||||
} else {
|
||||
// Otherwise assume everything was taken from original so empty it.
|
||||
original.setCount(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,11 +40,36 @@ import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
|||
*/
|
||||
class ItemTests {
|
||||
public static void run() {
|
||||
testStackReference();
|
||||
testInventoryWrappers();
|
||||
testLimitedStackCountInventory();
|
||||
testLimitedStackCountItem();
|
||||
}
|
||||
|
||||
private static void testStackReference() {
|
||||
// Ensure that Inventory wrappers will try to mutate the backing stack as much as possible.
|
||||
// In many cases, MC code captures a reference to the ItemStack so we want to edit that stack directly
|
||||
// and not a copy whenever we can. Obviously this can't be perfect, but we try to cover as many cases as possible.
|
||||
SimpleInventory inv = new SimpleInventory(new ItemStack(Items.DIAMOND, 2));
|
||||
InventoryStorage invWrapper = InventoryStorage.of(inv, null);
|
||||
ItemStack stack = inv.getStack(0);
|
||||
|
||||
// Simulate should correctly reset the stack.
|
||||
try (Transaction tx = Transaction.openOuter()) {
|
||||
invWrapper.extract(ItemVariant.of(Items.DIAMOND), 2, tx);
|
||||
}
|
||||
|
||||
if (stack != inv.getStack(0)) throw new AssertionError("Stack should have stayed the same.");
|
||||
|
||||
// Commit should try to edit the original stack when it is feasible to do so.
|
||||
try (Transaction tx = Transaction.openOuter()) {
|
||||
invWrapper.extract(ItemVariant.of(Items.DIAMOND), 1, tx);
|
||||
tx.commit();
|
||||
}
|
||||
|
||||
if (stack != inv.getStack(0)) throw new AssertionError("Stack should have stayed the same.");
|
||||
}
|
||||
|
||||
private static void testInventoryWrappers() {
|
||||
ItemVariant emptyBucket = ItemVariant.of(Items.BUCKET);
|
||||
TestSidedInventory testInventory = new TestSidedInventory();
|
||||
|
|
Loading…
Reference in a new issue