diff --git a/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java b/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java index 4fd5d66d2..0ef6766dc 100644 --- a/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java +++ b/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java @@ -50,7 +50,7 @@ public NonNullList getItems() { private final InventorySource inputSource; private @Nullable RecipeHolder recipe = null; - private CraftingInput craftingInput = CraftingInput.EMPTY; + private CraftingInput.Positioned posCraftingInput = CraftingInput.Positioned.EMPTY; private CraftingResult result = CraftingResult.EMPTY; public CraftingHelper(InventorySource inputSource) { @@ -61,7 +61,7 @@ public CraftingHelper(InventorySource inputSource) { public void clear() { recipe = null; craftingInventory.clearContent(); - craftingInput = CraftingInput.EMPTY; + posCraftingInput = CraftingInput.Positioned.EMPTY; } public void onInventoryChanged() { @@ -87,14 +87,14 @@ public void loadInputs() { for (int i = 0; i < 9; i++) { craftingInventory.setItem(i, craftingMatrix.getItem(i).copy()); } - craftingInput = craftingInventory.asCraftInput(); + posCraftingInput = craftingInventory.asPositionedCraftInput(); } public void loadRecipe() { recipe = inputSource.getWorld().getRecipeManager() - .getRecipeFor(RecipeType.CRAFTING, craftingInput, inputSource.getWorld()).orElse(null); + .getRecipeFor(RecipeType.CRAFTING, posCraftingInput.input(), inputSource.getWorld()).orElse(null); - craftResultInventory.setItem(0, recipe == null ? ItemStack.EMPTY : recipe.value().assemble(craftingInput, inputSource.getWorld().registryAccess())); + craftResultInventory.setItem(0, recipe == null ? ItemStack.EMPTY : recipe.value().assemble(posCraftingInput.input(), inputSource.getWorld().registryAccess())); } public void loadOutput() { @@ -133,19 +133,20 @@ public boolean onCraftedByPlayer(Player player, boolean leaveRemainingInGrid) { // Re-obtain remaining items in case "setCraftingPlayer" changes remaining items CommonHooks.setCraftingPlayer(player); - NonNullList remainingStacks = recipe.value().getRemainingItems(craftingInput); // Skip re-searching for recipe, should be ok + NonNullList remainingStacks = recipe.value().getRemainingItems(posCraftingInput.input()); // Skip re-searching for recipe, should be ok CommonHooks.setCraftingPlayer(null); Container craftingGird = inputSource.getCraftingMatrix(); Container storage = inputSource.getStorage(); - for (int i = 0; i < 9; i++) { + for (int i = 0; i < remainingStacks.size(); i++) { ItemStack remaining = remainingStacks.get(i); if (remaining.isEmpty()) continue; // If allowed, leave remaining in crafting grid just like Vanilla crafting bench if (leaveRemainingInGrid && craftingGird.getItem(i).isEmpty()) { - craftingGird.setItem(i, remaining.split(remaining.getCount())); + int ccSlot = craftingInputSlotToContainer(craftingInventory, posCraftingInput, i); + craftingGird.setItem(ccSlot, remaining.split(remaining.getCount())); continue; } @@ -187,9 +188,9 @@ private CraftingResult craftFromStorage(boolean simulate) { private CraftingResult craftFromSource(Container source, boolean simulate) { if (recipe == null) return CraftingResult.EMPTY; - if (!recipe.value().matches(craftingInput, inputSource.getWorld())) return CraftingResult.EMPTY; + if (!recipe.value().matches(posCraftingInput.input(), inputSource.getWorld())) return CraftingResult.EMPTY; - ItemStack result = recipe.value().assemble(craftingInput, inputSource.getWorld().registryAccess()); + ItemStack result = recipe.value().assemble(posCraftingInput.input(), inputSource.getWorld().registryAccess()); if (result.isEmpty()) return CraftingResult.EMPTY; if (simulate) { @@ -227,7 +228,7 @@ private CraftingResult craftFromSource(Container source, boolean simulate) { return CraftingResult.missingIngredients(missingIngredientMask); } - return new CraftingResult(result, recipe.value().getRemainingItems(craftingInput), 0, simulate ? source : copyInventory(source)); + return new CraftingResult(result, recipe.value().getRemainingItems(posCraftingInput.input()), 0, simulate ? source : copyInventory(source)); } private boolean consumeIngredient(Container storage, int startIndex, Predicate matchFunc) { @@ -317,4 +318,27 @@ default boolean canConsumeFromCraftingMatrix() { Level getWorld(); // Required for recipe lookup } + + /** + * Maps the slot index from within a CraftingInput (which is a sub-square within a crafting container) + * into a slot index of this outer crafting container. + *

+ * For example, if the matrix is 3x3, and the crafting input is 2x2 in bottom left, then + * slot 0 in the 2x2 input corresponds with slot 4 in the 3x3 matrix. + * + * @param matrix The CraftingContainer that the CraftingInput is in + * @param pCraftInput A CraftingInput positioned somewhere inside matrix + * @param pSlot A slot index inside pCraftInput + * @return The corresponding slot index in matrix + */ + private static int craftingInputSlotToContainer(CraftingContainer matrix, CraftingInput.Positioned pCraftInput, int pSlot) { + // xy within the crafting input + int ix = pSlot % pCraftInput.input().width(); + int iy = pSlot / pCraftInput.input().width(); + // xy within outer grid + int x = pCraftInput.left() + ix; + int y = pCraftInput.top() + iy; + // Outer index + return y * matrix.getWidth() + x; + } } diff --git a/expansion/src/main/java/mrtjp/projectred/expansion/item/RecipePlanComponent.java b/expansion/src/main/java/mrtjp/projectred/expansion/item/RecipePlanComponent.java index 8e4d6e8bf..73c8807da 100644 --- a/expansion/src/main/java/mrtjp/projectred/expansion/item/RecipePlanComponent.java +++ b/expansion/src/main/java/mrtjp/projectred/expansion/item/RecipePlanComponent.java @@ -7,12 +7,10 @@ import net.minecraft.ChatFormatting; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; -import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.Container; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.component.TooltipProvider; @@ -121,13 +119,13 @@ public void addToTooltip(Item.TooltipContext context, Consumer toolti //region Codecs // Codecs public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Codec.list(ItemStack.CODEC).fieldOf("inputs").forGetter(c -> c.inputs), - ItemStack.CODEC.fieldOf("output").forGetter(c -> c.output) + Codec.list(ItemStack.OPTIONAL_CODEC).fieldOf("inputs").forGetter(c -> c.inputs), + ItemStack.OPTIONAL_CODEC.fieldOf("output").forGetter(c -> c.output) ).apply(instance, RecipePlanComponent::new)); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - ItemStack.STREAM_CODEC.apply(ByteBufCodecs.list()), c -> c.inputs, - ItemStack.STREAM_CODEC, c -> c.output, + ItemStack.OPTIONAL_LIST_STREAM_CODEC, c -> c.inputs, + ItemStack.OPTIONAL_STREAM_CODEC, c -> c.output, RecipePlanComponent::new ); //endregion