From 86b7d527e6e14e83698e6493252ce0b88e1c9355 Mon Sep 17 00:00:00 2001 From: shartte Date: Tue, 18 Jun 2024 01:21:55 +0200 Subject: [PATCH] Fixes various crafting related problems (#7928) Fixes #7927 --- .../resources/assets/ae2/lang/en_us.json | 2 - .../client/gui/me/common/MEStorageScreen.java | 4 +- .../appeng/core/localization/GuiText.java | 3 - .../crafting/pattern/AECraftingPattern.java | 80 ++++++++++++------- .../appeng/menu/slot/AppEngCraftingSlot.java | 31 ++++--- 5 files changed, 72 insertions(+), 48 deletions(-) diff --git a/src/generated/resources/assets/ae2/lang/en_us.json b/src/generated/resources/assets/ae2/lang/en_us.json index fc7807be3d1..8cb3652bc5c 100644 --- a/src/generated/resources/assets/ae2/lang/en_us.json +++ b/src/generated/resources/assets/ae2/lang/en_us.json @@ -377,7 +377,6 @@ "gui.ae2.InvalidPattern": "Invalid Pattern", "gui.ae2.InvalidSingularity": "Invalid Singularity", "gui.ae2.Items": "Items", - "gui.ae2.LargeFontCraft": "+", "gui.ae2.LevelEmitter": "ME Level Emitter", "gui.ae2.LightBlue": "Light Blue", "gui.ae2.LightGray": "Light Gray", @@ -474,7 +473,6 @@ "gui.ae2.Set": "Set", "gui.ae2.ShowingOf": "Showing %d of %d", "gui.ae2.SkyChest": "Sky Stone Chest", - "gui.ae2.SmallFontCraft": "Craft", "gui.ae2.SmithingTablePattern": "Smithing Table Patterns", "gui.ae2.SpatialAnchor": "Spatial Anchor", "gui.ae2.SpatialAnchorAll": "Spanning: %d chunks in %d worlds", diff --git a/src/main/java/appeng/client/gui/me/common/MEStorageScreen.java b/src/main/java/appeng/client/gui/me/common/MEStorageScreen.java index 5bcaa93c86b..2edba94e66f 100644 --- a/src/main/java/appeng/client/gui/me/common/MEStorageScreen.java +++ b/src/main/java/appeng/client/gui/me/common/MEStorageScreen.java @@ -632,9 +632,7 @@ public void renderSlot(GuiGraphics guiGraphics, Slot s) { boolean craftable = entry.isCraftable(); var useLargeFonts = config.isUseLargeFonts(); if (craftable && (isViewOnlyCraftable() || storedAmount <= 0)) { - var craftLabelText = useLargeFonts ? GuiText.LargeFontCraft.getLocal() - : GuiText.SmallFontCraft.getLocal(); - StackSizeRenderer.renderSizeLabel(guiGraphics, this.font, s.x, s.y, craftLabelText); + StackSizeRenderer.renderSizeLabel(guiGraphics, this.font, s.x, s.y, "+"); } else { AmountFormat format = useLargeFonts ? AmountFormat.SLOT_LARGE_FONT : AmountFormat.SLOT; diff --git a/src/main/java/appeng/core/localization/GuiText.java b/src/main/java/appeng/core/localization/GuiText.java index dffa1fc1669..81ad45d8415 100644 --- a/src/main/java/appeng/core/localization/GuiText.java +++ b/src/main/java/appeng/core/localization/GuiText.java @@ -126,8 +126,6 @@ public enum GuiText implements LocalizationEnum { InvalidPattern("Invalid Pattern"), InvalidSingularity("Invalid Singularity"), Items("Items"), - // Used in a terminal to indicate that an item is craftable - LargeFontCraft("+"), LevelEmitter("ME Level Emitter"), LightBlue("Light Blue"), LightGray("Light Gray"), @@ -201,7 +199,6 @@ public enum GuiText implements LocalizationEnum { ShowingOf("Showing %d of %d"), SkyChest("Sky Stone Chest"), // Used in a terminal to indicate that an item is craftable - SmallFontCraft("Craft"), SmithingTablePattern("Smithing Table Patterns"), SpatialAnchor("Spatial Anchor"), SpatialAnchorAll("Spanning: %d chunks in %d worlds"), diff --git a/src/main/java/appeng/crafting/pattern/AECraftingPattern.java b/src/main/java/appeng/crafting/pattern/AECraftingPattern.java index c39bacce96d..f1e57cb6409 100644 --- a/src/main/java/appeng/crafting/pattern/AECraftingPattern.java +++ b/src/main/java/appeng/crafting/pattern/AECraftingPattern.java @@ -73,6 +73,7 @@ public class AECraftingPattern implements IPatternDetails, IMolecularAssemblerSu private final Input[] inputs; private final ItemStack output; private final List outputsArray; + private final CraftingInput.Positioned positionedPattern; /** * We cache results of isValid(...) calls for stacks that don't have NBT. */ @@ -100,12 +101,12 @@ public AECraftingPattern(AEItemKey definition, Level level) { this.recipe = (CraftingRecipe) recipeHolder.value(); // Build frame and find output - var craftingInput = makeCraftingInput(); - if (!this.recipe.matches(craftingInput, level)) { + this.positionedPattern = makeCraftingInput(); + if (!this.recipe.matches(positionedPattern.input(), level)) { throw new IllegalStateException("The recipe " + recipe + " no longer matches the encoded input."); } - this.output = this.recipe.assemble(craftingInput, level.registryAccess()); + this.output = this.recipe.assemble(positionedPattern.input(), level.registryAccess()); if (this.output.isEmpty()) { throw new IllegalStateException( "The recipe " + encodedPattern.recipeId() + " produced an empty item stack result."); @@ -264,8 +265,8 @@ public boolean isItemValid(int slot, AEItemKey key, Level level) { // Fill frame and check result var testCraftingInput = makeCraftingInputWithReplacedSlot(slot, key); - var newResult = recipe.matches(testCraftingInput, level) - && ItemStack.matches(output, recipe.assemble(testCraftingInput, level.registryAccess())); + var newResult = recipe.matches(testCraftingInput.input(), level) + && ItemStack.matches(output, recipe.assemble(testCraftingInput.input(), level.registryAccess())); setTestResult(slot, key, newResult); @@ -282,11 +283,18 @@ private ItemStack getRecipeRemainder(int slot, AEItemKey key) { // Consider making this more efficient in the future? (e.g. cache the produced remainders) // Fill frame - var testInput = makeCraftingInputWithReplacedSlot(slot, key); + var positioned = makeCraftingInputWithReplacedSlot(slot, key); // Get remainder - var remainder = recipe.getRemainingItems(testInput).get(slot); + var remainingItems = recipe.getRemainingItems(positioned.input()); - return remainder; + var x = (slot % CRAFTING_GRID_DIMENSION - positioned.left()); + var y = slot / CRAFTING_GRID_DIMENSION - positioned.top(); + var remainderIdx = y * positioned.input().width() + x; + if (remainderIdx >= 0 && remainderIdx < remainingItems.size()) { + return remainingItems.get(remainderIdx); + } + + return ItemStack.EMPTY; } /** @@ -372,6 +380,11 @@ public void fillCraftingGrid(KeyCounter[] table, CraftingGridAccessor gridAccess @Override public ItemStack assemble(CraftingInput container, Level level) { + if (positionedPattern.input().width() != container.width() + || positionedPattern.input().height() != container.height()) { + return ItemStack.EMPTY; + } + if (canSubstitute && recipe.isSpecial()) { // For special recipes, we need to test the recipe with assemble, unfortunately, since the output might // depend on the inputs in a way that can't be detected by changing one input at the time. @@ -396,20 +409,24 @@ public ItemStack assemble(CraftingInput container, Level level) { return recipe.assemble(testInput, level.registryAccess()); } - for (int x = 0; x < container.size(); x++) { - ItemStack item = container.getItem(x); - var stack = GenericStack.unwrapItemStack(item); - if (stack != null) { - // If we receive a pure fluid stack, we'll convert it to the appropriate container item - // If it matches the allowable input - var validFluid = getValidFluid(x); - if (validFluid != null && validFluid.equals(stack)) { - continue; + for (int i = 0; i < sparseInputs.size(); i++) { + var x = (i % CRAFTING_GRID_DIMENSION) - positionedPattern.left(); + var y = i / CRAFTING_GRID_DIMENSION - positionedPattern.top(); + if (x >= 0 && x < container.width() && y >= 0 && y < container.height()) { + ItemStack item = container.getItem(x, y); + var stack = GenericStack.unwrapItemStack(item); + if (stack != null) { + // If we receive a pure fluid stack, we'll convert it to the appropriate container item + // If it matches the allowable input + var validFluid = getValidFluid(i); + if (validFluid != null && validFluid.equals(stack)) { + continue; + } } - } - if (!isItemValid(x, AEItemKey.of(item), level)) { - return ItemStack.EMPTY; + if (!isItemValid(i, AEItemKey.of(item), level)) { + return ItemStack.EMPTY; + } } } return output; @@ -479,10 +496,17 @@ private GenericStack getItemOrFluidInput(int slot, GenericStack item) { // Note: the following call might do a performed extraction with mods that have native fluid container // support (such as immersive engineering "fluid aware" recipes). This is only safe because we restrict this // code path to buckets. - var remainingItems = recipe.getRemainingItems(makeCraftingInput()); - var slotRemainder = remainingItems.get(slot); - if (slotRemainder.getCount() == 1 && slotRemainder.is(Items.BUCKET)) { - return new GenericStack(containedFluid.what(), containedFluid.amount()); + var positioned = makeCraftingInput(); + + var remainingItems = recipe.getRemainingItems(positioned.input()); + var x = (slot % 3 - positioned.left()); + var y = slot / 3 - positioned.top(); + var remainderIdx = y * positioned.input().width() + x; + if (remainderIdx >= 0 && remainderIdx < remainingItems.size()) { + var slotRemainder = remainingItems.get(remainderIdx); + if (slotRemainder.getCount() == 1 && slotRemainder.is(Items.BUCKET)) { + return new GenericStack(containedFluid.what(), containedFluid.amount()); + } } } @@ -622,14 +646,14 @@ public static List getCraftingInputs(List stacks) { return Arrays.asList(result); } - private CraftingInput makeCraftingInput() { - return CraftingInput.of(CRAFTING_GRID_DIMENSION, CRAFTING_GRID_DIMENSION, makeCraftingInputItems()); + private CraftingInput.Positioned makeCraftingInput() { + return CraftingInput.ofPositioned(CRAFTING_GRID_DIMENSION, CRAFTING_GRID_DIMENSION, makeCraftingInputItems()); } - private CraftingInput makeCraftingInputWithReplacedSlot(int slot, AEItemKey replacement) { + private CraftingInput.Positioned makeCraftingInputWithReplacedSlot(int slot, AEItemKey replacement) { var items = makeCraftingInputItems(); items.set(slot, replacement.toStack()); - return CraftingInput.of(CRAFTING_GRID_DIMENSION, CRAFTING_GRID_DIMENSION, items); + return CraftingInput.ofPositioned(CRAFTING_GRID_DIMENSION, CRAFTING_GRID_DIMENSION, items); } private List makeCraftingInputItems() { diff --git a/src/main/java/appeng/menu/slot/AppEngCraftingSlot.java b/src/main/java/appeng/menu/slot/AppEngCraftingSlot.java index 946f71e682c..ab7b6694fa0 100644 --- a/src/main/java/appeng/menu/slot/AppEngCraftingSlot.java +++ b/src/main/java/appeng/menu/slot/AppEngCraftingSlot.java @@ -104,22 +104,29 @@ public void onTake(Player player, ItemStack stack) { for (int i = 0; i < this.craftingGrid.size(); i++) { items.set(i, this.craftingGrid.getStackInSlot(i)); } - var input = CraftingInput.of(3, 3, items); + var positioned = CraftingInput.ofPositioned(3, 3, items); CommonHooks.setCraftingPlayer(player); - var remainingItems = this.getRemainingItems(input, player.level()); + var remainingItems = this.getRemainingItems(positioned.input(), player.level()); CommonHooks.setCraftingPlayer(null); - for (int i = 0; i < this.craftingGrid.size(); ++i) { - // Consumes the item from the grid - this.craftingGrid.extractItem(i, 1, false); - - var remainingInSlot = remainingItems.get(i); - if (!remainingInSlot.isEmpty()) { - if (this.craftingGrid.getStackInSlot(i).isEmpty()) { - this.craftingGrid.setItemDirect(i, remainingInSlot); - } else if (!this.player.getInventory().add(remainingInSlot)) { - this.player.drop(remainingInSlot, false); + for (var y = 0; y < 3; y++) { + for (var x = 0; x < 3; x++) { + var slotIdx = y * 3 + x; + var remainderIdx = (y - positioned.top()) * 3 + (x - positioned.left()); + + // Consumes the item from the grid + this.craftingGrid.extractItem(slotIdx, 1, false); + + if (remainderIdx >= 0 && remainderIdx < remainingItems.size()) { + var remainingInSlot = remainingItems.get(remainderIdx); + if (!remainingInSlot.isEmpty()) { + if (this.craftingGrid.getStackInSlot(slotIdx).isEmpty()) { + this.craftingGrid.setItemDirect(slotIdx, remainingInSlot); + } else if (!this.player.getInventory().add(remainingInSlot)) { + this.player.drop(remainingInSlot, false); + } + } } } }