mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Correctly obey stack limits in OffsetStorage.extract/insert
Many thanks to Lem for managing to reproduce it. It was actually an easy bug bug to spot on second look, but having a reliable way to verify was super helpful. Fixes #1338
This commit is contained in:
		| @@ -42,7 +42,7 @@ jqwik = "1.7.2" | ||||
| junit = "5.9.2" | ||||
|  | ||||
| # Build tools | ||||
| cctJavadoc = "1.6.0" | ||||
| cctJavadoc = "1.6.1" | ||||
| checkstyle = "10.3.4" | ||||
| curseForgeGradle = "1.0.11" | ||||
| errorProne-core = "2.18.0" | ||||
|   | ||||
| @@ -22,7 +22,7 @@ public class InventoryUtilTest { | ||||
| 
 | ||||
|         var remainder = InventoryUtil.storeItemsFromOffset(container, new ItemStack(Items.COBBLESTONE, 32), 4); | ||||
|         assertThat("Remainder is empty", remainder, isStack(ItemStack.EMPTY)); | ||||
|         assertThat("Was inserted into slot", container.getItem(4), isStack(new ItemStack(Items.COBBLESTONE, 32))); | ||||
|         assertThat("Was inserted into slot", container.getItem(4), isStack(Items.COBBLESTONE, 32)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
| @@ -33,6 +33,6 @@ public class InventoryUtilTest { | ||||
| 
 | ||||
|         var remainder = InventoryUtil.storeItemsFromOffset(container, new ItemStack(Items.COBBLESTONE, 32), 4); | ||||
|         assertThat("Remainder is empty", remainder, isStack(ItemStack.EMPTY)); | ||||
|         assertThat("Was inserted into slot", container.getItem(1), isStack(new ItemStack(Items.COBBLESTONE, 32))); | ||||
|         assertThat("Was inserted into slot", container.getItem(1), isStack(Items.COBBLESTONE, 32)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  */ | ||||
| package dan200.computercraft.test.shared; | ||||
| 
 | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import org.hamcrest.Description; | ||||
| import org.hamcrest.Matcher; | ||||
| @@ -30,4 +31,8 @@ public class ItemStackMatcher extends TypeSafeMatcher<ItemStack> { | ||||
|     public static Matcher<ItemStack> isStack(ItemStack stack) { | ||||
|         return new ItemStackMatcher(stack); | ||||
|     } | ||||
| 
 | ||||
|     public static Matcher<ItemStack> isStack(Item item, int size) { | ||||
|         return new ItemStackMatcher(new ItemStack(item, size)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,8 @@ import net.minecraft.world.SimpleContainer; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.item.Items; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.params.ParameterizedTest; | ||||
| import org.junit.jupiter.params.provider.ValueSource; | ||||
| 
 | ||||
| import java.util.Collections; | ||||
| import java.util.IdentityHashMap; | ||||
| @@ -34,7 +36,7 @@ public interface ContainerTransferContract { | ||||
|         var move = wrap(inv).singleSlot(0).moveTo(wrap(inv).singleSlot(0), 64); | ||||
|         assertEquals(ContainerTransfer.NO_SPACE, move); | ||||
| 
 | ||||
|         assertThat(inv.getItem(0), isStack(new ItemStack(Items.DIRT, 64))); | ||||
|         assertThat(inv.getItem(0), isStack(Items.DIRT, 64)); | ||||
| 
 | ||||
|         assertNoOverlap(inv); | ||||
|     } | ||||
| @@ -48,7 +50,7 @@ public interface ContainerTransferContract { | ||||
|         assertEquals(64, move); | ||||
| 
 | ||||
|         assertThat(inv.getItem(0), isStack(ItemStack.EMPTY)); | ||||
|         assertThat(inv.getItem(1), isStack(new ItemStack(Items.DIRT, 64))); | ||||
|         assertThat(inv.getItem(1), isStack(Items.DIRT, 64)); | ||||
| 
 | ||||
|         assertNoOverlap(inv); | ||||
|     } | ||||
| @@ -64,7 +66,7 @@ public interface ContainerTransferContract { | ||||
|         assertEquals(64, move); | ||||
| 
 | ||||
|         assertThat(source.getItem(0), isStack(ItemStack.EMPTY)); | ||||
|         assertThat(destination.getItem(0), isStack(new ItemStack(Items.DIRT, 64))); | ||||
|         assertThat(destination.getItem(0), isStack(Items.DIRT, 64)); | ||||
| 
 | ||||
|         assertNoOverlap(source, destination); | ||||
|     } | ||||
| @@ -85,12 +87,40 @@ public interface ContainerTransferContract { | ||||
| 
 | ||||
|         assertThat(source.getItem(0), isStack(ItemStack.EMPTY)); | ||||
|         for (var i = 0; i < 4; i++) { | ||||
|             assertThat("Stack in slot " + i, destination.getItem(i), isStack(new ItemStack(Items.DIRT, 64))); | ||||
|             assertThat("Stack in slot " + i, destination.getItem(i), isStack(Items.DIRT, 64)); | ||||
|         } | ||||
| 
 | ||||
|         assertNoOverlap(source, destination); | ||||
|     } | ||||
| 
 | ||||
|     @ParameterizedTest(name = "offset = {0}") | ||||
|     @ValueSource(ints = { 0, 1, 2 }) | ||||
|     default void testMoveDistributeWithLimit(int offset) { | ||||
|         // We create a specific setup here such that each slot has room for strictly less than the limit(=17). | ||||
|         // There was a bug (https://github.com/cc-tweaked/CC-Tweaked/issues/1338) where this would insert items beyond | ||||
|         // the limit as it did not account for the number of items already transferred. | ||||
|         var destination = new SimpleContainer(4); | ||||
|         destination.setItem(offset, new ItemStack(Items.DIRT, 48)); | ||||
|         destination.setItem((offset + 1) % 4, new ItemStack(Items.DIRT, 48)); | ||||
| 
 | ||||
|         var source = new SimpleContainer(4); | ||||
|         source.setItem(0, new ItemStack(Items.DIRT, 64)); | ||||
|         source.setItem(1, new ItemStack(Items.DIRT, 64)); | ||||
| 
 | ||||
|         var move = wrap(source).moveTo(wrap(destination).rotate(offset), 17); | ||||
|         assertEquals(17, move); | ||||
| 
 | ||||
|         assertThat("Source stack in slot 0", source.getItem(0), isStack(Items.DIRT, 47)); | ||||
|         assertThat("Source stack in slot 1", source.getItem(1), isStack(Items.DIRT, 64)); | ||||
| 
 | ||||
|         assertThat("Dest stack in slot 0", destination.getItem(offset), isStack(Items.DIRT, 64)); | ||||
|         assertThat("Dest stack in slot 2", destination.getItem((offset + 1) % 4), isStack(Items.DIRT, 49)); | ||||
|         assertThat("Dest stack in slot 3", destination.getItem((offset + 2) % 4), isStack(ItemStack.EMPTY)); | ||||
|         assertThat("Dest stack in slot 3", destination.getItem((offset + 3) % 4), isStack(ItemStack.EMPTY)); | ||||
| 
 | ||||
|         assertNoOverlap(source, destination); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     default void testMoveSkipFullSlot() { | ||||
|         var destination = new SimpleContainer(4); | ||||
| @@ -103,8 +133,8 @@ public interface ContainerTransferContract { | ||||
|         assertEquals(64, move); | ||||
| 
 | ||||
|         assertThat(source.getItem(1), isStack(ItemStack.EMPTY)); | ||||
|         assertThat(destination.getItem(0), isStack(new ItemStack(Items.DIRT, 64))); | ||||
|         assertThat(destination.getItem(1), isStack(new ItemStack(Items.DIRT, 64))); | ||||
|         assertThat(destination.getItem(0), isStack(Items.DIRT, 64)); | ||||
|         assertThat(destination.getItem(1), isStack(Items.DIRT, 64)); | ||||
| 
 | ||||
|         assertNoOverlap(source, destination); | ||||
|     } | ||||
| @@ -124,7 +154,7 @@ public interface ContainerTransferContract { | ||||
|         var move = wrap(source).moveTo(wrap(destination), 64); | ||||
|         assertEquals(ContainerTransfer.NO_SPACE, move); | ||||
| 
 | ||||
|         assertThat(source.getItem(0), isStack(new ItemStack(Items.DIRT, 64))); | ||||
|         assertThat(source.getItem(0), isStack(Items.DIRT, 64)); | ||||
|         assertThat(destination.getItem(0), isStack(ItemStack.EMPTY)); | ||||
| 
 | ||||
|         assertNoOverlap(source, destination); | ||||
| @@ -143,7 +173,7 @@ public interface ContainerTransferContract { | ||||
|         assertEquals(32, move); | ||||
| 
 | ||||
|         assertThat("Source is empty", source.getItem(0), isStack(ItemStack.EMPTY)); | ||||
|         assertThat("Was inserted into slot", destination.getItem(1), isStack(new ItemStack(Items.COBBLESTONE, 32))); | ||||
|         assertThat("Was inserted into slot", destination.getItem(1), isStack(Items.COBBLESTONE, 32)); | ||||
|     } | ||||
| 
 | ||||
|     static void assertNoOverlap(Container... containers) { | ||||
|   | ||||
| @@ -111,7 +111,7 @@ public class FabricContainerTransfer implements ContainerTransfer { | ||||
| 
 | ||||
|             long transferred = 0; | ||||
|             for (var i = 0; i < size; i++) { | ||||
|                 transferred += slots.get(wrap(i, size)).insert(resource, maxAmount, transaction); | ||||
|                 transferred += slots.get(wrap(i, size)).insert(resource, maxAmount - transferred, transaction); | ||||
|                 if (transferred >= maxAmount) break; | ||||
|             } | ||||
| 
 | ||||
| @@ -125,7 +125,7 @@ public class FabricContainerTransfer implements ContainerTransfer { | ||||
| 
 | ||||
|             long transferred = 0; | ||||
|             for (var i = 0; i < size; i++) { | ||||
|                 transferred += slots.get(wrap(i, size)).extract(resource, maxAmount, transaction); | ||||
|                 transferred += slots.get(wrap(i, size)).extract(resource, maxAmount - transferred, transaction); | ||||
|                 if (transferred >= maxAmount) break; | ||||
|             } | ||||
| 
 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates