diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java index b843b3d4d..b4809edf2 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -29,6 +29,7 @@ import lombok.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.Registries; @@ -38,6 +39,10 @@ import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; import java.util.HashMap; @@ -77,6 +82,20 @@ public class GeyserItemStack { return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponents()); } + public static @NonNull GeyserItemStack from(@NonNull SlotDisplay slotDisplay) { + if (slotDisplay instanceof EmptySlotDisplay) { + return GeyserItemStack.EMPTY; + } + if (slotDisplay instanceof ItemSlotDisplay itemSlotDisplay) { + return GeyserItemStack.of(itemSlotDisplay.item(), 1); + } + if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlotDisplay) { + return GeyserItemStack.from(itemStackSlotDisplay.itemStack()); + } + GeyserImpl.getInstance().getLogger().warning("Unsure how to convert to ItemStack: " + slotDisplay); + return GeyserItemStack.EMPTY; + } + public int getJavaId() { return isEmpty() ? 0 : javaId; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java index 3037b725e..d9cae943f 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.inventory.recipe; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; /** * A more compact version of {link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}. @@ -38,5 +38,5 @@ public interface GeyserRecipe { boolean isShaped(); @Nullable - ItemStack result(); + SlotDisplay result(); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java index 413041ba7..70b71cf4d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java @@ -26,14 +26,16 @@ package org.geysermc.geyser.inventory.recipe; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapedCraftingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; -public record GeyserShapedRecipe(int width, int height, Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { +import java.util.List; -// public GeyserShapedRecipe(ShapedRecipeData data) { -// this(data.getWidth(), data.getHeight(), data.getIngredients(), data.getResult()); -// } +public record GeyserShapedRecipe(int width, int height, List ingredients, @Nullable SlotDisplay result) implements GeyserRecipe { + + public GeyserShapedRecipe(ShapedCraftingRecipeDisplay data) { + this(data.width(), data.height(), data.ingredients(), data.result()); + } @Override public boolean isShaped() { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java index 6b9e36956..90eeb01c9 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java @@ -26,14 +26,16 @@ package org.geysermc.geyser.inventory.recipe; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapelessCraftingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; -public record GeyserShapelessRecipe(Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { +import java.util.List; -// public GeyserShapelessRecipe(ShapelessRecipeData data) { -// this(data.getIngredients(), data.getResult()); -// } +public record GeyserShapelessRecipe(List ingredients, @Nullable SlotDisplay result) implements GeyserRecipe { + + public GeyserShapelessRecipe(ShapelessCraftingRecipeDisplay data) { + this(data.ingredients(), data.result()); + } @Override public boolean isShaped() { diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java index f061ed070..4cbd2ea47 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java @@ -31,8 +31,6 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; -import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; -import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -92,7 +90,7 @@ public abstract class RecipeRegistryLoader implements RegistryLoader> javaToBedrockRecipeIds; - @Setter - private Int2ObjectMap craftingRecipes; + private final Int2ObjectMap craftingRecipes; private final AtomicInteger lastRecipeNetId; /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index f051885d4..15c19c542 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -25,21 +25,40 @@ package org.geysermc.geyser.translator.inventory; -import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.IntSortedSet; import lombok.AllArgsConstructor; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; -import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.*; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.AutoCraftRecipeAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ConsumeAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftResultsDeprecatedAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.DropAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.SwapAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.TransferItemStackRequestAction; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseContainer; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseSlot; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseStatus; import org.cloudburstmc.protocol.bedrock.packet.ItemStackResponsePacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.*; +import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.CartographyContainer; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.inventory.PlayerInventory; +import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.inventory.click.ClickPlan; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; @@ -56,12 +75,17 @@ import org.geysermc.geyser.translator.inventory.furnace.SmokerInventoryTranslato import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.ItemUtils; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @AllArgsConstructor public abstract class InventoryTranslator { @@ -642,8 +666,8 @@ public abstract class InventoryTranslator { } int gridDimensions = gridSize == 4 ? 2 : 3; - Ingredient[] ingredients = new Ingredient[0]; - ItemStack output = null; + List ingredients = Collections.emptyList(); + SlotDisplay output = null; int recipeWidth = 0; int ingRemaining = 0; int ingredientIndex = -1; @@ -697,7 +721,7 @@ public abstract class InventoryTranslator { ingredients = shapelessRecipe.ingredients(); recipeWidth = gridDimensions; output = shapelessRecipe.result(); - if (ingredients.length > gridSize) { + if (ingredients.size() > gridSize) { return rejectRequest(request); } } @@ -728,11 +752,11 @@ public abstract class InventoryTranslator { craftState = CraftState.INGREDIENTS; if (ingRemaining == 0) { - while (++ingredientIndex < ingredients.length) { -// if (ingredients[ingredientIndex].getOptions().length != 0) { -// ingRemaining = timesCrafted; -// break; -// } + while (++ingredientIndex < ingredients.size()) { + if (!(ingredients.get(ingredientIndex) instanceof EmptySlotDisplay)) { // TODO I guess can technically other options be empty? + ingRemaining = timesCrafted; + break; + } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java similarity index 93% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java index 1a32c1a97..6cbefde0d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java @@ -42,7 +42,7 @@ import java.util.UUID; import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; @Translator(packet = ClientboundFinishConfigurationPacket.class) -public class JavaFinishConfigurationPacketTranslator extends PacketTranslator { +public class JavaFinishConfigurationTranslator extends PacketTranslator { /** * Required to use the specified cartography table recipes */ @@ -72,6 +72,9 @@ public class JavaFinishConfigurationPacketTranslator extends PacketTranslator> javaToBedrockRecipeIds = session.getJavaToBedrockRecipeIds(); + Int2ObjectMap geyserRecipes = session.getCraftingRecipes(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); @@ -101,14 +105,17 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator bedrockRecipeIds = new ArrayList<>(); ItemData output = bedrockRecipes.right(); List> left = bedrockRecipes.left(); + GeyserRecipe geyserRecipe = new GeyserShapedRecipe(shapedRecipe); for (int i = 0; i < left.size(); i++) { List inputs = left.get(i); String recipeId = contents.id() + "_" + i; + int recipeNetworkId = netId++; craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, shapedRecipe.width(), shapedRecipe.height(), inputs, - Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); + Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, recipeNetworkId, false, RecipeUnlockingRequirement.INVALID)); recipesPacket.getUnlockedRecipes().add(recipeId); bedrockRecipeIds.add(recipeId); + geyserRecipes.put(recipeNetworkId, geyserRecipe); } javaToBedrockRecipeIds.put(contents.id(), List.copyOf(bedrockRecipeIds)); } @@ -121,13 +128,16 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator bedrockRecipeIds = new ArrayList<>(); ItemData output = bedrockRecipes.right(); List> left = bedrockRecipes.left(); + GeyserRecipe geyserRecipe = new GeyserShapelessRecipe(shapelessRecipe); for (int i = 0; i < left.size(); i++) { List inputs = left.get(i); String recipeId = contents.id() + "_" + i; + int recipeNetworkId = netId++; craftingDataPacket.getCraftingData().add(ShapelessRecipeData.shapeless(recipeId, - inputs, Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, RecipeUnlockingRequirement.INVALID)); + inputs, Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, recipeNetworkId, RecipeUnlockingRequirement.INVALID)); recipesPacket.getUnlockedRecipes().add(recipeId); bedrockRecipeIds.add(recipeId); + geyserRecipes.put(recipeNetworkId, geyserRecipe); } javaToBedrockRecipeIds.put(contents.id(), List.copyOf(bedrockRecipeIds)); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java index 743c07a31..c98ab1ff6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java @@ -44,12 +44,15 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -104,9 +107,6 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator javaIngredients = new ArrayList<>(height * width); int index = 0; for (int row = firstRow; row < height + firstRow; row++) { for (int col = firstCol; col < width + firstCol; col++) { GeyserItemStack geyserItemStack = inventory.getItem(col + (row * gridDimensions) + 1); ingredients[index] = geyserItemStack.getItemData(session); - int[] items = new int[] {geyserItemStack.isEmpty() ? 0 : geyserItemStack.getJavaId()}; - javaIngredients[index] = new Ingredient(new HolderSet(items)); + javaIngredients.add(geyserItemStack.isEmpty() ? new EmptySlotDisplay() : new ItemStackSlotDisplay(geyserItemStack.getItemStack())); InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.UI); @@ -185,7 +184,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator acceptsAsInput(session, aSlotDisplay, itemStack)); + } + if (slotDisplay instanceof ItemSlotDisplay itemSlotDisplay) { + return itemStack.getJavaId() == itemSlotDisplay.item(); + } + if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlotDisplay) { + ItemStack other = itemStackSlotDisplay.itemStack(); + // Amount check might be flimsy? + return itemStack.getJavaId() == other.getId() && itemStack.getAmount() >= other.getAmount() + && Objects.equals(itemStack.getComponents(), other.getDataComponents()); + } + if (slotDisplay instanceof TagSlotDisplay tagSlotDisplay) { + return session.getTagCache().is(new Tag<>(JavaRegistries.ITEM, tagSlotDisplay.tag()), itemStack.asItem()); + } + session.getGeyser().getLogger().warning("Unknown slot display type: " + slotDisplay); + return false; + } + /** * Test all known recipes to find a valid match * @@ -462,91 +499,70 @@ public class InventoryUtils { for (GeyserRecipe recipe : session.getCraftingRecipes().values()) { if (recipe.isShaped()) { GeyserShapedRecipe shapedRecipe = (GeyserShapedRecipe) recipe; - if (output != null && !shapedRecipe.result().equals(output)) { + if (output != null && !acceptsAsInput(session, shapedRecipe.result(), GeyserItemStack.from(output))) { continue; } - Ingredient[] ingredients = shapedRecipe.ingredients(); - if (shapedRecipe.width() != width || shapedRecipe.height() != height || width * height != ingredients.length) { + List ingredients = shapedRecipe.ingredients(); + if (shapedRecipe.width() != width || shapedRecipe.height() != height || width * height != ingredients.size()) { continue; } - if (!testShapedRecipe(ingredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { - Ingredient[] mirroredIngredients = new Ingredient[ingredients.length]; + if (!testShapedRecipe(session, ingredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { + List mirroredIngredients = new ArrayList<>(ingredients.size()); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { - mirroredIngredients[col + (row * width)] = ingredients[(width - 1 - col) + (row * width)]; + mirroredIngredients.add(ingredients.get((width - 1 - col) + (row * width))); } } - if (Arrays.equals(ingredients, mirroredIngredients) || - !testShapedRecipe(mirroredIngredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { + if (!ingredients.equals(mirroredIngredients) || + !testShapedRecipe(session, mirroredIngredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { continue; } } } else { GeyserShapelessRecipe data = (GeyserShapelessRecipe) recipe; - if (output != null && !data.result().equals(output)) { + if (output != null && !acceptsAsInput(session, data.result(), GeyserItemStack.from(output))) { continue; } - if (nonAirCount != data.ingredients().length) { + if (nonAirCount != data.ingredients().size()) { // There is an amount of items on the crafting table that is not the same as the ingredient count so this is invalid continue; } - for (int i = 0; i < data.ingredients().length; i++) { - Ingredient ingredient = data.ingredients()[i]; - for (int item : ingredient.getValues().getHolders()) { // FIXME - boolean inventoryHasItem = false; - // Iterate only over the crafting table to find this item - crafting: - for (int row = firstRow; row < height + firstRow; row++) { - for (int col = firstCol; col < width + firstCol; col++) { - GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); - if (geyserItemStack.isEmpty()) { - inventoryHasItem = item == 0; - if (inventoryHasItem) { - break crafting; - } - } else if (item == geyserItemStack.getJavaId()) { - inventoryHasItem = true; - break crafting; - } + for (int i = 0; i < data.ingredients().size(); i++) { + SlotDisplay slotDisplay = data.ingredients().get(i); + boolean inventoryHasItem = false; + // Iterate only over the crafting table to find this item + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); + if (acceptsAsInput(session, slotDisplay, geyserItemStack)) { + inventoryHasItem = true; + break; } } - if (!inventoryHasItem) { - continue recipes; - } + } + if (!inventoryHasItem) { + continue recipes; } } } + System.out.println("Found existing match for item: " + recipe); return recipe; } return null; } @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean testShapedRecipe(final Ingredient[] ingredients, final IntFunction inventoryGetter, + private static boolean testShapedRecipe(final GeyserSession session, final List ingredients, final IntFunction inventoryGetter, final int gridDimensions, final int firstRow, final int height, final int firstCol, final int width) { int ingredientIndex = 0; for (int row = firstRow; row < height + firstRow; row++) { for (int col = firstCol; col < width + firstCol; col++) { GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); - Ingredient ingredient = ingredients[ingredientIndex++]; - int[] items = ingredient.getValues().getHolders(); // FIXME - if (items.length == 0) { - if (!geyserItemStack.isEmpty()) { - return false; - } - } else { - boolean inventoryHasItem = false; - for (int item : items) { - if (geyserItemStack.getJavaId() == item) { - inventoryHasItem = true; - break; - } - } - if (!inventoryHasItem) { - return false; - } + SlotDisplay slotDisplay = ingredients.get(ingredientIndex++); + if (!acceptsAsInput(session, slotDisplay, geyserItemStack)) { + return false; } } }