Skip to content

Commit

Permalink
Fixes various crafting related problems (#7928)
Browse files Browse the repository at this point in the history
Fixes #7927
  • Loading branch information
shartte authored Jun 17, 2024
1 parent 2adbf8e commit 86b7d52
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 48 deletions.
2 changes: 0 additions & 2 deletions src/generated/resources/assets/ae2/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 0 additions & 3 deletions src/main/java/appeng/core/localization/GuiText.java
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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"),
Expand Down
80 changes: 52 additions & 28 deletions src/main/java/appeng/crafting/pattern/AECraftingPattern.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public class AECraftingPattern implements IPatternDetails, IMolecularAssemblerSu
private final Input[] inputs;
private final ItemStack output;
private final List<GenericStack> outputsArray;
private final CraftingInput.Positioned positionedPattern;
/**
* We cache results of isValid(...) calls for stacks that don't have NBT.
*/
Expand Down Expand Up @@ -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.");
Expand Down Expand Up @@ -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);

Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -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());
}
}
}

Expand Down Expand Up @@ -622,14 +646,14 @@ public static List<GenericStack> getCraftingInputs(List<ItemStack> 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<ItemStack> makeCraftingInputItems() {
Expand Down
31 changes: 19 additions & 12 deletions src/main/java/appeng/menu/slot/AppEngCraftingSlot.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}
}
Expand Down

0 comments on commit 86b7d52

Please sign in to comment.