1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-05 21:33:54 +00:00

Create a new CraftingInput for each craft

It's not actually safe to reuse this, as we need to recompute the
internal StackedContents each time the inventory changes, otherwise
ShapelessRecipe.matches will continue to return true, even if the actual
inventory doesn't include the required items.

Fixes #2094
This commit is contained in:
Jonathan Coates 2025-02-07 09:45:14 +00:00
parent 9bb62b047a
commit 74f707aaea
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
3 changed files with 176 additions and 9 deletions

View File

@ -39,7 +39,7 @@ public final class TurtleInventoryCrafting {
} }
} }
var input = CraftingInput.ofPositioned(WIDTH, HEIGHT, new AbstractList<>() { List<ItemStack> items = new AbstractList<>() {
@Override @Override
public ItemStack get(int index) { public ItemStack get(int index) {
var x = xStart + index % WIDTH; var x = xStart + index % WIDTH;
@ -53,9 +53,10 @@ public final class TurtleInventoryCrafting {
public int size() { public int size() {
return WIDTH * HEIGHT; return WIDTH * HEIGHT;
} }
}); };
var recipe = level.getRecipeManager().getRecipeFor(RecipeType.CRAFTING, input.input(), level).orElse(null); var input = CraftingInput.of(WIDTH, HEIGHT, items);
return recipe == null ? null : new FoundRecipe(recipe.value(), input.input(), input.left() + xStart, input.top() + yStart); var recipe = level.getRecipeManager().getRecipeFor(RecipeType.CRAFTING, input, level).orElse(null);
return recipe == null ? null : new FoundRecipe(recipe.value(), items, xStart, yStart);
} }
@Nullable @Nullable
@ -76,18 +77,24 @@ public final class TurtleInventoryCrafting {
if (maxCount == 0) return List.of(); if (maxCount == 0) return List.of();
var recipe = candidate.recipe(); var recipe = candidate.recipe();
var input = candidate.input(); var items = candidate.items();
var xStart = candidate.xStart();
var yStart = candidate.yStart();
var results = new ArrayList<ItemStack>(); var results = new ArrayList<ItemStack>();
for (var i = 0; i < maxCount && recipe.matches(input, level); i++) { for (var i = 0; i < maxCount; i++) {
var offsetInput = CraftingInput.ofPositioned(WIDTH, HEIGHT, items);
var input = offsetInput.input();
if (!recipe.matches(input, level)) break;
var result = recipe.assemble(input, level.registryAccess()); var result = recipe.assemble(input, level.registryAccess());
if (result.isEmpty()) break; if (result.isEmpty()) break;
results.add(result); results.add(result);
result.onCraftedBySystem(level); result.onCraftedBySystem(level);
// Remove items from the inventory, and add back the remainders.
var xStart = candidate.xStart() + offsetInput.left();
var yStart = candidate.yStart() + offsetInput.top();
var remainders = recipe.getRemainingItems(input); var remainders = recipe.getRemainingItems(input);
for (var y = 0; y < input.height(); y++) { for (var y = 0; y < input.height(); y++) {
for (var x = 0; x < input.width(); x++) { for (var x = 0; x < input.width(); x++) {
@ -118,6 +125,6 @@ public final class TurtleInventoryCrafting {
return Collections.unmodifiableList(results); return Collections.unmodifiableList(results);
} }
private record FoundRecipe(Recipe<CraftingInput> recipe, CraftingInput input, int xStart, int yStart) { private record FoundRecipe(Recipe<CraftingInput> recipe, List<ItemStack> items, int xStart, int yStart) {
} }
} }

View File

@ -835,6 +835,29 @@ class Turtle_Test {
} }
} }
/**
* `turtle.craft` works on shapeless recipes
*
* @see [#2094](https://github.com/cc-tweaked/CC-Tweaked/issues/2094)
*/
@GameTest
fun Craft_shapeless(helper: GameTestHelper) = helper.sequence {
thenExecute {
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get())
assertTrue(TurtleCraftCommand(64).execute(turtle.access).isSuccess, "Crafting succeeded")
helper.assertContainerExactly(
BlockPos(2, 2, 2),
listOf(
ItemStack(Items.ENDER_EYE, 1), ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY,
ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY,
ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY,
ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY,
),
)
}
}
/** /**
* `turtle.craft` leaves a remainder * `turtle.craft` leaves a remainder
* *

View File

@ -0,0 +1,137 @@
{
DataVersion: 3465,
size: [5, 5, 5],
data: [
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
{pos: [0, 1, 0], state: "minecraft:air"},
{pos: [0, 1, 1], state: "minecraft:air"},
{pos: [0, 1, 2], state: "minecraft:air"},
{pos: [0, 1, 3], state: "minecraft:air"},
{pos: [0, 1, 4], state: "minecraft:air"},
{pos: [1, 1, 0], state: "minecraft:air"},
{pos: [1, 1, 1], state: "minecraft:air"},
{pos: [1, 1, 2], state: "minecraft:air"},
{pos: [1, 1, 3], state: "minecraft:air"},
{pos: [1, 1, 4], state: "minecraft:air"},
{pos: [2, 1, 0], state: "minecraft:air"},
{pos: [2, 1, 1], state: "minecraft:air"},
{pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:north,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "minecraft:ender_pearl"}, {Count: 1b, Slot: 1b, id: "minecraft:blaze_powder"}], Label: "turtle_test.craft_shapeless", LeftUpgrade: "minecraft:crafting_table", LeftUpgradeNbt: {}, On: 1b, Slot: 0, id: "computercraft:turtle_normal"}},
{pos: [2, 1, 3], state: "minecraft:air"},
{pos: [2, 1, 4], state: "minecraft:air"},
{pos: [3, 1, 0], state: "minecraft:air"},
{pos: [3, 1, 1], state: "minecraft:air"},
{pos: [3, 1, 2], state: "minecraft:air"},
{pos: [3, 1, 3], state: "minecraft:air"},
{pos: [3, 1, 4], state: "minecraft:air"},
{pos: [4, 1, 0], state: "minecraft:air"},
{pos: [4, 1, 1], state: "minecraft:air"},
{pos: [4, 1, 2], state: "minecraft:air"},
{pos: [4, 1, 3], state: "minecraft:air"},
{pos: [4, 1, 4], state: "minecraft:air"},
{pos: [0, 2, 0], state: "minecraft:air"},
{pos: [0, 2, 1], state: "minecraft:air"},
{pos: [0, 2, 2], state: "minecraft:air"},
{pos: [0, 2, 3], state: "minecraft:air"},
{pos: [0, 2, 4], state: "minecraft:air"},
{pos: [1, 2, 0], state: "minecraft:air"},
{pos: [1, 2, 1], state: "minecraft:air"},
{pos: [1, 2, 2], state: "minecraft:air"},
{pos: [1, 2, 3], state: "minecraft:air"},
{pos: [1, 2, 4], state: "minecraft:air"},
{pos: [2, 2, 0], state: "minecraft:air"},
{pos: [2, 2, 1], state: "minecraft:air"},
{pos: [2, 2, 2], state: "minecraft:air"},
{pos: [2, 2, 3], state: "minecraft:air"},
{pos: [2, 2, 4], state: "minecraft:air"},
{pos: [3, 2, 0], state: "minecraft:air"},
{pos: [3, 2, 1], state: "minecraft:air"},
{pos: [3, 2, 2], state: "minecraft:air"},
{pos: [3, 2, 3], state: "minecraft:air"},
{pos: [3, 2, 4], state: "minecraft:air"},
{pos: [4, 2, 0], state: "minecraft:air"},
{pos: [4, 2, 1], state: "minecraft:air"},
{pos: [4, 2, 2], state: "minecraft:air"},
{pos: [4, 2, 3], state: "minecraft:air"},
{pos: [4, 2, 4], state: "minecraft:air"},
{pos: [0, 3, 0], state: "minecraft:air"},
{pos: [0, 3, 1], state: "minecraft:air"},
{pos: [0, 3, 2], state: "minecraft:air"},
{pos: [0, 3, 3], state: "minecraft:air"},
{pos: [0, 3, 4], state: "minecraft:air"},
{pos: [1, 3, 0], state: "minecraft:air"},
{pos: [1, 3, 1], state: "minecraft:air"},
{pos: [1, 3, 2], state: "minecraft:air"},
{pos: [1, 3, 3], state: "minecraft:air"},
{pos: [1, 3, 4], state: "minecraft:air"},
{pos: [2, 3, 0], state: "minecraft:air"},
{pos: [2, 3, 1], state: "minecraft:air"},
{pos: [2, 3, 2], state: "minecraft:air"},
{pos: [2, 3, 3], state: "minecraft:air"},
{pos: [2, 3, 4], state: "minecraft:air"},
{pos: [3, 3, 0], state: "minecraft:air"},
{pos: [3, 3, 1], state: "minecraft:air"},
{pos: [3, 3, 2], state: "minecraft:air"},
{pos: [3, 3, 3], state: "minecraft:air"},
{pos: [3, 3, 4], state: "minecraft:air"},
{pos: [4, 3, 0], state: "minecraft:air"},
{pos: [4, 3, 1], state: "minecraft:air"},
{pos: [4, 3, 2], state: "minecraft:air"},
{pos: [4, 3, 3], state: "minecraft:air"},
{pos: [4, 3, 4], state: "minecraft:air"},
{pos: [0, 4, 0], state: "minecraft:air"},
{pos: [0, 4, 1], state: "minecraft:air"},
{pos: [0, 4, 2], state: "minecraft:air"},
{pos: [0, 4, 3], state: "minecraft:air"},
{pos: [0, 4, 4], state: "minecraft:air"},
{pos: [1, 4, 0], state: "minecraft:air"},
{pos: [1, 4, 1], state: "minecraft:air"},
{pos: [1, 4, 2], state: "minecraft:air"},
{pos: [1, 4, 3], state: "minecraft:air"},
{pos: [1, 4, 4], state: "minecraft:air"},
{pos: [2, 4, 0], state: "minecraft:air"},
{pos: [2, 4, 1], state: "minecraft:air"},
{pos: [2, 4, 2], state: "minecraft:air"},
{pos: [2, 4, 3], state: "minecraft:air"},
{pos: [2, 4, 4], state: "minecraft:air"},
{pos: [3, 4, 0], state: "minecraft:air"},
{pos: [3, 4, 1], state: "minecraft:air"},
{pos: [3, 4, 2], state: "minecraft:air"},
{pos: [3, 4, 3], state: "minecraft:air"},
{pos: [3, 4, 4], state: "minecraft:air"},
{pos: [4, 4, 0], state: "minecraft:air"},
{pos: [4, 4, 1], state: "minecraft:air"},
{pos: [4, 4, 2], state: "minecraft:air"},
{pos: [4, 4, 3], state: "minecraft:air"},
{pos: [4, 4, 4], state: "minecraft:air"}
],
entities: [],
palette: [
"minecraft:polished_andesite",
"minecraft:air",
"computercraft:turtle_normal{facing:north,waterlogged:false}"
]
}