mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-27 01:55:41 -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) {
|
if (insertedAmount > 0) {
|
||||||
updateSnapshots(transaction);
|
updateSnapshots(transaction);
|
||||||
|
currentStack = getStack();
|
||||||
|
|
||||||
if (currentStack.isEmpty()) {
|
if (currentStack.isEmpty()) {
|
||||||
currentStack = insertedVariant.toStack(insertedAmount);
|
currentStack = insertedVariant.toStack(insertedAmount);
|
||||||
|
@ -142,6 +143,7 @@ public abstract class SingleStackStorage extends SnapshotParticipant<ItemStack>
|
||||||
|
|
||||||
if (extracted > 0) {
|
if (extracted > 0) {
|
||||||
this.updateSnapshots(transaction);
|
this.updateSnapshots(transaction);
|
||||||
|
currentStack = getStack();
|
||||||
currentStack.decrement(extracted);
|
currentStack.decrement(extracted);
|
||||||
setStack(currentStack);
|
setStack(currentStack);
|
||||||
}
|
}
|
||||||
|
@ -154,7 +156,9 @@ public abstract class SingleStackStorage extends SnapshotParticipant<ItemStack>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final ItemStack createSnapshot() {
|
protected final ItemStack createSnapshot() {
|
||||||
return getStack().copy();
|
ItemStack original = getStack();
|
||||||
|
setStack(original.copy());
|
||||||
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -34,6 +34,7 @@ class InventorySlotWrapper extends SingleStackStorage {
|
||||||
*/
|
*/
|
||||||
private final InventoryStorageImpl storage;
|
private final InventoryStorageImpl storage;
|
||||||
final int slot;
|
final int slot;
|
||||||
|
private ItemStack lastReleasedSnapshot = null;
|
||||||
|
|
||||||
InventorySlotWrapper(InventoryStorageImpl storage, int slot) {
|
InventorySlotWrapper(InventoryStorageImpl storage, int slot) {
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
|
@ -66,4 +67,25 @@ class InventorySlotWrapper extends SingleStackStorage {
|
||||||
storage.markDirtyParticipant.updateSnapshots(transaction);
|
storage.markDirtyParticipant.updateSnapshots(transaction);
|
||||||
super.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 {
|
class ItemTests {
|
||||||
public static void run() {
|
public static void run() {
|
||||||
|
testStackReference();
|
||||||
testInventoryWrappers();
|
testInventoryWrappers();
|
||||||
testLimitedStackCountInventory();
|
testLimitedStackCountInventory();
|
||||||
testLimitedStackCountItem();
|
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() {
|
private static void testInventoryWrappers() {
|
||||||
ItemVariant emptyBucket = ItemVariant.of(Items.BUCKET);
|
ItemVariant emptyBucket = ItemVariant.of(Items.BUCKET);
|
||||||
TestSidedInventory testInventory = new TestSidedInventory();
|
TestSidedInventory testInventory = new TestSidedInventory();
|
||||||
|
|
Loading…
Reference in a new issue