diff --git a/CHANGELOG.md b/CHANGELOG.md index ce9471ccf..ec914cb0b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,14 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- Available items indicator in JEI now updates while JEI is open + ### Fixed - Fixed chained crafters not taking over the name of the root crafter. +- Fixed lag when opening JEI in large system ## [v1.11.1] - 2022-10-30 diff --git a/src/main/java/com/refinedmods/refinedstorage/container/GridContainerMenu.java b/src/main/java/com/refinedmods/refinedstorage/container/GridContainerMenu.java index a112d504b..e414a285d 100644 --- a/src/main/java/com/refinedmods/refinedstorage/container/GridContainerMenu.java +++ b/src/main/java/com/refinedmods/refinedstorage/container/GridContainerMenu.java @@ -9,6 +9,9 @@ import com.refinedmods.refinedstorage.api.network.grid.handler.IItemGridHandler; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCache; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCacheListener; import com.refinedmods.refinedstorage.apiimpl.network.node.GridNetworkNode; +import com.refinedmods.refinedstorage.blockentity.BaseBlockEntity; +import com.refinedmods.refinedstorage.blockentity.config.IType; +import com.refinedmods.refinedstorage.blockentity.grid.portable.IPortableGrid; import com.refinedmods.refinedstorage.container.slot.filter.FilterSlot; import com.refinedmods.refinedstorage.container.slot.filter.FluidFilterSlot; import com.refinedmods.refinedstorage.container.slot.grid.CraftingGridSlot; @@ -17,9 +20,6 @@ import com.refinedmods.refinedstorage.container.slot.legacy.LegacyBaseSlot; import com.refinedmods.refinedstorage.container.slot.legacy.LegacyDisabledSlot; import com.refinedmods.refinedstorage.container.slot.legacy.LegacyFilterSlot; import com.refinedmods.refinedstorage.screen.IScreenInfoProvider; -import com.refinedmods.refinedstorage.blockentity.BaseBlockEntity; -import com.refinedmods.refinedstorage.blockentity.config.IType; -import com.refinedmods.refinedstorage.blockentity.grid.portable.IPortableGrid; import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; diff --git a/src/main/java/com/refinedmods/refinedstorage/integration/jei/GridRecipeTransferHandler.java b/src/main/java/com/refinedmods/refinedstorage/integration/jei/GridRecipeTransferHandler.java index 793fc3d54..c85ae911a 100644 --- a/src/main/java/com/refinedmods/refinedstorage/integration/jei/GridRecipeTransferHandler.java +++ b/src/main/java/com/refinedmods/refinedstorage/integration/jei/GridRecipeTransferHandler.java @@ -8,8 +8,6 @@ import com.refinedmods.refinedstorage.network.grid.GridCraftingPreviewRequestMes import com.refinedmods.refinedstorage.network.grid.GridProcessingTransferMessage; import com.refinedmods.refinedstorage.network.grid.GridTransferMessage; import com.refinedmods.refinedstorage.screen.grid.GridScreen; -import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; -import com.refinedmods.refinedstorage.screen.grid.stack.ItemGridStack; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.forge.ForgeTypes; import mezz.jei.api.gui.ingredient.IRecipeSlotView; @@ -20,14 +18,16 @@ import mezz.jei.api.recipe.transfer.IRecipeTransferError; import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; import net.minecraft.client.gui.screens.Screen; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; public class GridRecipeTransferHandler implements IRecipeTransferHandler { @@ -58,26 +58,38 @@ public class GridRecipeTransferHandler implements IRecipeTransferHandler firstStack = slotView.getIngredients(VanillaTypes.ITEM_STACK).findAny(); + ingredientList.add(new Ingredient(slotView, firstStack.map(ItemStack::getCount).orElse(0))); + } + + IngredientTracker tracker = IngredientTracker.getTracker(container); + tracker.updateAvailability(ingredientList, container, player); + GridType type = container.getGrid().getGridType(); if (type == GridType.CRAFTING) { - return transferRecipeForCraftingGrid(container, recipe, recipeSlots, player, doTransfer); + return transferRecipeForCraftingGrid(container, recipe, recipeSlots, player, doTransfer, ingredientList); } else if (type == GridType.PATTERN) { - return transferRecipeForPatternGrid(container, recipe, recipeSlots, player, doTransfer); + return transferRecipeForPatternGrid(container, recipe, recipeSlots, player, doTransfer, ingredientList); } return null; } - private RecipeTransferCraftingGridError transferRecipeForCraftingGrid(GridContainerMenu container, Object recipe, IRecipeSlotsView recipeLayout, Player player, boolean doTransfer) { - IngredientTracker tracker = createTracker(container, recipeLayout, player, doTransfer); + private RecipeTransferCraftingGridError transferRecipeForCraftingGrid(GridContainerMenu container, Object recipe, IRecipeSlotsView recipeLayout, Player player, boolean doTransfer, Ingredient.IngredientList ingredientList) { if (doTransfer) { - if (tracker.hasMissingButAutocraftingAvailable() && Screen.hasControlDown()) { - tracker.createCraftingRequests().forEach((id, count) -> RS.NETWORK_HANDLER.sendToServer( + if (ingredientList.hasMissingButAutocraftingAvailable() && Screen.hasControlDown()) { + ingredientList.createCraftingRequests().forEach((id, count) -> RS.NETWORK_HANDLER.sendToServer( new GridCraftingPreviewRequestMessage( id, count, @@ -86,79 +98,38 @@ public class GridRecipeTransferHandler implements IRecipeTransferHandler gridStacks = ((GridScreen) container.getScreenInfoProvider()).getView().getAllStacks(); - - // Check grid - if (container.getGrid().isGridActive()) { - for (IGridStack gridStack : gridStacks) { - if (gridStack instanceof ItemGridStack) { - tracker.addAvailableStack(((ItemGridStack) gridStack).getStack(), gridStack); - } - } - } - - // Check inventory - for (int inventorySlot = 0; inventorySlot < player.getInventory().getContainerSize(); inventorySlot++) { - if (!player.getInventory().getItem(inventorySlot).isEmpty()) { - tracker.addAvailableStack(player.getInventory().getItem(inventorySlot), null); - } - } - - // Check grid crafting slots - if (container.getGrid().getGridType().equals(GridType.CRAFTING)) { - CraftingContainer craftingMatrix = container.getGrid().getCraftingMatrix(); - if (craftingMatrix != null) { - for (int matrixSlot = 0; matrixSlot < craftingMatrix.getContainerSize(); matrixSlot++) { - if (!craftingMatrix.getItem(matrixSlot).isEmpty()) { - tracker.addAvailableStack(craftingMatrix.getItem(matrixSlot), null); - } - } - } - } - - return tracker; - } - public boolean hasTransferredRecently() { return System.currentTimeMillis() - lastTransferTimeMs <= TRANSFER_SCROLLBAR_DELAY_MS; } - private void moveItems(GridContainerMenu gridContainer, Object recipe, IRecipeSlotsView recipeLayout, IngredientTracker tracker) { + private void moveItems(GridContainerMenu gridContainer, Object recipe, IRecipeSlotsView recipeLayout, Player player) { this.lastTransferTimeMs = System.currentTimeMillis(); if (gridContainer.getGrid().getGridType() == GridType.PATTERN && !(recipe instanceof CraftingRecipe)) { - moveForProcessing(recipeLayout, tracker); + moveForProcessing(recipeLayout, gridContainer, player); } else { move(recipeLayout); } @@ -185,7 +156,7 @@ public class GridRecipeTransferHandler implements IRecipeTransferHandler inputs = new LinkedList<>(); List outputs = new LinkedList<>(); @@ -194,13 +165,13 @@ public class GridRecipeTransferHandler implements IRecipeTransferHandler inputSlots = recipeLayout.getSlotViews(RecipeIngredientRole.INPUT); for (IRecipeSlotView view : inputSlots) { - handleItemIngredient(inputs, view, tracker); + handleItemIngredient(inputs, view, gridContainer, player); handleFluidIngredient(fluidInputs, view); } List outputSlots = recipeLayout.getSlotViews(RecipeIngredientRole.OUTPUT); for (IRecipeSlotView view : outputSlots) { - handleItemIngredient(outputs, view, tracker); + handleItemIngredient(outputs, view, gridContainer, player); handleFluidIngredient(fluidOutputs, view); } @@ -213,9 +184,9 @@ public class GridRecipeTransferHandler implements IRecipeTransferHandler list, IRecipeSlotView slotView, IngredientTracker tracker) { + private void handleItemIngredient(List list, IRecipeSlotView slotView, GridContainerMenu gridContainer, Player player) { if (slotView != null && slotView.getIngredients(VanillaTypes.ITEM_STACK).findAny().isPresent()) { - ItemStack stack = tracker.findBestMatch(slotView.getIngredients(VanillaTypes.ITEM_STACK).toList()); + ItemStack stack = IngredientTracker.getTracker(gridContainer).findBestMatch(gridContainer, player, slotView.getIngredients(VanillaTypes.ITEM_STACK).toList()); if (stack.isEmpty() && slotView.getDisplayedIngredient(VanillaTypes.ITEM_STACK).isPresent()) { stack = slotView.getDisplayedIngredient(VanillaTypes.ITEM_STACK).get(); diff --git a/src/main/java/com/refinedmods/refinedstorage/integration/jei/Ingredient.java b/src/main/java/com/refinedmods/refinedstorage/integration/jei/Ingredient.java index c2aa43de1..9764745b6 100644 --- a/src/main/java/com/refinedmods/refinedstorage/integration/jei/Ingredient.java +++ b/src/main/java/com/refinedmods/refinedstorage/integration/jei/Ingredient.java @@ -2,7 +2,7 @@ package com.refinedmods.refinedstorage.integration.jei; import mezz.jei.api.gui.ingredient.IRecipeSlotView; -import java.util.UUID; +import java.util.*; class Ingredient { private final IRecipeSlotView slotView; @@ -16,7 +16,7 @@ class Ingredient { } public boolean isAvailable() { - return getMissingAmount() == 0; + return getMissingAmount() <= 0; } public int getMissingAmount() { @@ -42,4 +42,36 @@ class Ingredient { public void fulfill(int amount) { fulfilled += amount; } + + static class IngredientList { + List ingredients = new ArrayList<>(); + + void add(Ingredient ingredient) { + ingredients.add(ingredient); + } + + public boolean hasMissing() { + return ingredients.stream().anyMatch(ingredient -> !ingredient.isAvailable()); + } + + public boolean hasMissingButAutocraftingAvailable() { + return ingredients.stream().anyMatch(ingredient -> !ingredient.isAvailable() && ingredient.isCraftable()); + } + + public boolean isAutocraftingAvailable() { + return ingredients.stream().anyMatch(Ingredient::isCraftable); + } + + public Map createCraftingRequests() { + Map toRequest = new HashMap<>(); + + for (Ingredient ingredient : ingredients) { + if (!ingredient.isAvailable() && ingredient.isCraftable()) { + toRequest.merge(ingredient.getCraftStackId(), ingredient.getMissingAmount(), Integer::sum); + } + } + + return toRequest; + } + } } diff --git a/src/main/java/com/refinedmods/refinedstorage/integration/jei/IngredientTracker.java b/src/main/java/com/refinedmods/refinedstorage/integration/jei/IngredientTracker.java index dd59c3310..a99e0deab 100644 --- a/src/main/java/com/refinedmods/refinedstorage/integration/jei/IngredientTracker.java +++ b/src/main/java/com/refinedmods/refinedstorage/integration/jei/IngredientTracker.java @@ -2,124 +2,214 @@ package com.refinedmods.refinedstorage.integration.jei; import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern; import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternProvider; +import com.refinedmods.refinedstorage.api.network.grid.GridType; import com.refinedmods.refinedstorage.api.util.IComparer; import com.refinedmods.refinedstorage.apiimpl.API; +import com.refinedmods.refinedstorage.container.GridContainerMenu; import com.refinedmods.refinedstorage.item.PatternItem; +import com.refinedmods.refinedstorage.screen.grid.GridScreen; import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; +import com.refinedmods.refinedstorage.screen.grid.stack.ItemGridStack; +import com.refinedmods.refinedstorage.screen.grid.view.IGridView; +import com.refinedmods.refinedstorage.util.ItemStackKey; import mezz.jei.api.constants.VanillaTypes; -import mezz.jei.api.gui.ingredient.IRecipeSlotView; -import mezz.jei.api.gui.ingredient.IRecipeSlotsView; -import mezz.jei.api.recipe.RecipeIngredientRole; import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.registries.ForgeRegistries; -import javax.annotation.Nullable; import java.util.*; public class IngredientTracker { - private final List ingredients = new ArrayList<>(); - private final Map storedItems = new HashMap<>(); - private boolean doTransfer; - public IngredientTracker(IRecipeSlotsView recipeLayout, boolean doTransfer) { - for (IRecipeSlotView slotView : recipeLayout.getSlotViews(RecipeIngredientRole.INPUT)) { - Optional optionalItemStack = slotView.getIngredients(VanillaTypes.ITEM_STACK).findAny(); + private static IngredientTracker INSTANCE; - optionalItemStack.ifPresent(stack -> ingredients.add(new Ingredient(slotView, stack.getCount()))); + private final Map storedItems = new HashMap<>(); + private final Map patternItems = new HashMap<>(); + private final Map craftableItems = new HashMap<>(); + + public static IngredientTracker getTracker(GridContainerMenu gridContainer) { + if (INSTANCE == null) { + INSTANCE = new IngredientTracker(gridContainer); + } + return INSTANCE; + } + + public static void invalidate() { + INSTANCE = null; + } + + public IngredientTracker(GridContainerMenu gridContainer) { + + // Using IGridView#getStacks will return a *filtered* list of items in the view, + // which will cause problems - especially if the user uses JEI synchronised searching. + // Instead, we will use IGridView#getAllStacks which provides an unordered view of all GridStacks. + IGridView view = ((GridScreen) gridContainer.getScreenInfoProvider()).getView(); + + //Existing stacks are synced by the fact that they are both referencing the same object. However, new stacks need to be added. + view.addDeltaListener((iGridStack -> { + if (iGridStack instanceof ItemGridStack stack) { + if (stack.isCraftable()) { + craftableItems.put(new ItemStackKey(stack.getStack()), stack.getId()); + } else { + addStack(stack.getStack()); + } + + } + })); + Collection gridStacks = view.getAllStacks(); + + // Check grid + if (gridContainer.getGrid().isGridActive()) { + for (IGridStack gridStack : gridStacks) { + if (gridStack instanceof ItemGridStack stackInGrid) { + + // for craftables we should easily be able to take the hit from hashing the nbt + if (stackInGrid.isCraftable()) { + craftableItems.put(new ItemStackKey(stackInGrid.getStack()), gridStack.getId()); + } else { // for non-craftables we don't hash nbt to avoid the performance hit + addStack(stackInGrid.getStack()); + } + } + } + } + } + + public void addStack(ItemStack stack) { + if (stack.isEmpty()) { + return; + } + if (stack.getItem() instanceof ICraftingPatternProvider) { + ICraftingPattern pattern = PatternItem.fromCache(Minecraft.getInstance().level, stack); + if (pattern.isValid()) { + for (ItemStack outputStack : pattern.getOutputs()) { + patternItems.merge(new ItemStackKey(outputStack), 1, Integer::sum); + } + } + + } else { + storedItems.merge(new ItemStackKey(stack), stack.getCount(), Integer::sum); } - this.doTransfer = doTransfer; } - public Collection getIngredients() { - return ingredients; + + public ItemStack findBestMatch(GridContainerMenu gridContainer, Player player, List list) { + ItemStack resultStack = ItemStack.EMPTY; + int count = 0; + + + for (ItemStack listStack : list) { + + //check crafting matrix + if (gridContainer.getGrid().getGridType().equals(GridType.CRAFTING)) { + CraftingContainer craftingMatrix = gridContainer.getGrid().getCraftingMatrix(); + if (craftingMatrix != null) { + for (int matrixSlot = 0; matrixSlot < craftingMatrix.getContainerSize(); matrixSlot++) { + ItemStack stackInSlot = craftingMatrix.getItem(matrixSlot); + if (API.instance().getComparer().isEqual(listStack, stackInSlot, IComparer.COMPARE_NBT)) { + if (stackInSlot.getCount() > count) { + count = stackInSlot.getCount(); + resultStack = stackInSlot; + } + } + } + } + } + + //check inventory + for (int inventorySlot = 0; inventorySlot < player.getInventory().getContainerSize(); inventorySlot++) { + ItemStack stackInSlot = player.getInventory().getItem(inventorySlot); + if (API.instance().getComparer().isEqual(listStack, stackInSlot, IComparer.COMPARE_NBT)) { + if (stackInSlot.getCount() > count) { + count = stackInSlot.getCount(); + resultStack = stackInSlot; + } + } + } + + //check storage + var stored = storedItems.get(new ItemStackKey(listStack)); + if (stored != null) { + if (stored > count) { + resultStack = listStack; + count = stored; + } + } + } + + //If the item is not in storage check patterns autocrafting + if (count == 0) { + for (ItemStack itemStack : list) { + ItemStackKey key = new ItemStackKey(itemStack); + if (craftableItems.get(key) != null) { + resultStack = itemStack; + break; + } else if (patternItems.get(key) != null) { + resultStack = itemStack; + break; + } + } + } + + return resultStack; } - public void addAvailableStack(ItemStack stack, @Nullable IGridStack gridStack) { - int available = stack.getCount(); - if (doTransfer) { - if (stack.getItem() instanceof ICraftingPatternProvider) { - ICraftingPattern pattern = PatternItem.fromCache(Minecraft.getInstance().level, stack); - if (pattern.isValid()) { - for (ItemStack outputStack : pattern.getOutputs()) { - storedItems.merge(registryName(outputStack.getItem()), outputStack.getCount(), Integer::sum); + public void updateAvailability(Ingredient.IngredientList ingredientList, GridContainerMenu gridContainer, Player player) { + Map usedMatrixStacks = new HashMap<>(); + Map usedInventoryStacks = new HashMap<>(); + Map usedStoredStacks = new HashMap<>(); + + //Gather available Stacks + for (Ingredient ingredient : ingredientList.ingredients) { + ingredient.getSlotView().getIngredients(VanillaTypes.ITEM_STACK).takeWhile(stack -> !ingredient.isAvailable()).forEach(stack -> { + + ingredient.setCraftStackId(craftableItems.get(new ItemStackKey(stack))); + // Check grid crafting slots + if (gridContainer.getGrid().getGridType().equals(GridType.CRAFTING)) { + CraftingContainer craftingMatrix = gridContainer.getGrid().getCraftingMatrix(); + if (craftingMatrix != null) { + for (int matrixSlot = 0; matrixSlot < craftingMatrix.getContainerSize(); matrixSlot++) { + if (checkStack(usedMatrixStacks, ingredient, stack, matrixSlot, craftingMatrix.getItem(matrixSlot))) { + return; + } + } } } - } else { - storedItems.merge(registryName(stack.getItem()), available, Integer::sum); - } - } - - for (Ingredient ingredient : ingredients) { - if (available == 0) { - return; - } - - Optional match = ingredient - .getSlotView() - .getIngredients(VanillaTypes.ITEM_STACK) - .filter(s -> API.instance().getComparer().isEqual(stack, s, IComparer.COMPARE_NBT)) - .findFirst(); - - if (match.isPresent()) { - // Craftables and non-craftables are 2 different gridstacks - // As such we need to ignore craftable stacks as they are not actual items - if (gridStack != null && gridStack.isCraftable()) { - ingredient.setCraftStackId(gridStack.getId()); - } else if (!ingredient.isAvailable()) { - int needed = ingredient.getMissingAmount(); - int used = Math.min(available, needed); - ingredient.fulfill(used); - available -= used; + //read inventory + for (int inventorySlot = 0; inventorySlot < player.getInventory().getContainerSize(); inventorySlot++) { + if (checkStack(usedInventoryStacks, ingredient, stack, inventorySlot, player.getInventory().getItem(inventorySlot))) { + return; + } } - } + + //Check Stored Stacks + ItemStackKey key = new ItemStackKey(stack); + Integer stored = storedItems.get(key); + if (stored != null) { + Integer used = usedStoredStacks.get(key); + int amount = Math.min(ingredient.getMissingAmount(), used == null ? stored : stored - used); + if (amount > 0) { + ingredient.fulfill(amount); + usedStoredStacks.put(key, used == null ? amount : used + amount); + } + } + }); } } - public boolean hasMissing() { - return ingredients.stream().anyMatch(ingredient -> !ingredient.isAvailable()); - } - - public boolean hasMissingButAutocraftingAvailable() { - return ingredients.stream().anyMatch(ingredient -> !ingredient.isAvailable() && ingredient.isCraftable()); - } - - public boolean isAutocraftingAvailable() { - return ingredients.stream().anyMatch(Ingredient::isCraftable); - } - - public Map createCraftingRequests() { - Map toRequest = new HashMap<>(); - - for (Ingredient ingredient : ingredients) { - if (!ingredient.isAvailable() && ingredient.isCraftable()) { - toRequest.merge(ingredient.getCraftStackId(), ingredient.getMissingAmount(), Integer::sum); + private boolean checkStack(Map usedMatrixStacks, Ingredient ingredient, ItemStack stack, int slot, ItemStack stackInSlot) { + if (API.instance().getComparer().isEqual(stack, stackInSlot, IComparer.COMPARE_NBT)) { + Integer used = usedMatrixStacks.get(slot); + int amount = Math.min(ingredient.getMissingAmount(), used == null ? stackInSlot.getCount() : stackInSlot.getCount() - used); + if (amount > 0) { + ingredient.fulfill(amount); + usedMatrixStacks.put(slot, amount); } + return ingredient.isAvailable(); } - - return toRequest; + return false; } - public ItemStack findBestMatch(List list) { - ItemStack stack = ItemStack.EMPTY; - int count = 0; - - for (ItemStack itemStack : list) { - Integer stored = storedItems.get(registryName(itemStack.getItem())); - if (stored != null && stored > count) { - stack = itemStack; - count = stored; - } - } - - return stack; - } - - private ResourceLocation registryName(final Item item) { - return ForgeRegistries.ITEMS.getKey(item); - } } diff --git a/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferCraftingGridError.java b/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferCraftingGridError.java index c04a9dfda..b0e58f7c4 100644 --- a/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferCraftingGridError.java +++ b/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferCraftingGridError.java @@ -8,7 +8,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; - import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -17,10 +16,11 @@ public class RecipeTransferCraftingGridError implements IRecipeTransferError { protected static final Color AUTOCRAFTING_HIGHLIGHT_COLOR = new Color(0.0f, 0.0f, 1.0f, 0.4f); private static final Color MISSING_HIGHLIGHT_COLOR = new Color(1.0f, 0.0f, 0.0f, 0.4f); private static final boolean HOST_OS_IS_MACOS = System.getProperty("os.name").equals("Mac OS X"); - protected final IngredientTracker tracker; + protected final Ingredient.IngredientList ingredientList; - public RecipeTransferCraftingGridError(IngredientTracker tracker) { - this.tracker = tracker; + + public RecipeTransferCraftingGridError(Ingredient.IngredientList ingredientList) { + this.ingredientList = ingredientList; } @Override @@ -28,6 +28,16 @@ public class RecipeTransferCraftingGridError implements IRecipeTransferError { return Type.COSMETIC; } + @Override + public int getButtonHighlightColor() { + if (ingredientList.hasMissingButAutocraftingAvailable()) { + return AUTOCRAFTING_HIGHLIGHT_COLOR.getRGB(); + } else if (ingredientList.hasMissing()) { + return MISSING_HIGHLIGHT_COLOR.getRGB(); + } + return IRecipeTransferError.super.getButtonHighlightColor(); + } + @Override public void showError(PoseStack poseStack, int mouseX, int mouseY, IRecipeSlotsView recipeSlotsView, int recipeX, int recipeY) { poseStack.translate(recipeX, recipeY, 0); @@ -44,7 +54,7 @@ public class RecipeTransferCraftingGridError implements IRecipeTransferError { boolean craftMessage = false; boolean missingMessage = false; - for (Ingredient ingredient : tracker.getIngredients()) { + for (Ingredient ingredient : ingredientList.ingredients) { if (!ingredient.isAvailable()) { if (ingredient.isCraftable()) { ingredient.getSlotView().drawHighlight(stack, AUTOCRAFTING_HIGHLIGHT_COLOR.getRGB()); diff --git a/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferPatternGridError.java b/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferPatternGridError.java index dbc608b34..9aac904ea 100644 --- a/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferPatternGridError.java +++ b/src/main/java/com/refinedmods/refinedstorage/integration/jei/RecipeTransferPatternGridError.java @@ -4,13 +4,12 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; - import java.util.ArrayList; import java.util.List; public class RecipeTransferPatternGridError extends RecipeTransferCraftingGridError { - public RecipeTransferPatternGridError(IngredientTracker tracker) { - super(tracker); + public RecipeTransferPatternGridError(Ingredient.IngredientList ingredients) { + super(ingredients); } @Override @@ -20,7 +19,7 @@ public class RecipeTransferPatternGridError extends RecipeTransferCraftingGridEr boolean craftMessage = false; - for (Ingredient ingredient : tracker.getIngredients()) { + for (Ingredient ingredient : ingredientList.ingredients) { if (ingredient.isCraftable()) { ingredient.getSlotView().drawHighlight(stack, AUTOCRAFTING_HIGHLIGHT_COLOR.getRGB()); craftMessage = true; diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/BaseScreen.java b/src/main/java/com/refinedmods/refinedstorage/screen/BaseScreen.java index 276e690ae..2b24dcfa8 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/BaseScreen.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/BaseScreen.java @@ -73,7 +73,7 @@ public abstract class BaseScreen extends Abstra executeLater(AbstractContainerScreen.class, callback); } - private void runActions() { + public void runActions() { runActions(getClass()); runActions(AbstractContainerScreen.class); } diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java index 13a9995a0..381738dba 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java @@ -10,6 +10,12 @@ import com.refinedmods.refinedstorage.api.network.grid.IGrid; import com.refinedmods.refinedstorage.api.network.grid.handler.IItemGridHandler; import com.refinedmods.refinedstorage.apiimpl.network.node.GridNetworkNode; import com.refinedmods.refinedstorage.apiimpl.render.ElementDrawers; +import com.refinedmods.refinedstorage.blockentity.NetworkNodeBlockEntity; +import com.refinedmods.refinedstorage.blockentity.config.IType; +import com.refinedmods.refinedstorage.blockentity.data.BlockEntitySynchronizationManager; +import com.refinedmods.refinedstorage.blockentity.grid.GridBlockEntity; +import com.refinedmods.refinedstorage.blockentity.grid.portable.IPortableGrid; +import com.refinedmods.refinedstorage.blockentity.grid.portable.PortableGridBlockEntity; import com.refinedmods.refinedstorage.container.GridContainerMenu; import com.refinedmods.refinedstorage.network.grid.*; import com.refinedmods.refinedstorage.screen.BaseScreen; @@ -24,12 +30,6 @@ import com.refinedmods.refinedstorage.screen.widget.ScrollbarWidget; import com.refinedmods.refinedstorage.screen.widget.SearchWidget; import com.refinedmods.refinedstorage.screen.widget.TabListWidget; import com.refinedmods.refinedstorage.screen.widget.sidebutton.*; -import com.refinedmods.refinedstorage.blockentity.NetworkNodeBlockEntity; -import com.refinedmods.refinedstorage.blockentity.config.IType; -import com.refinedmods.refinedstorage.blockentity.data.BlockEntitySynchronizationManager; -import com.refinedmods.refinedstorage.blockentity.grid.GridBlockEntity; -import com.refinedmods.refinedstorage.blockentity.grid.portable.IPortableGrid; -import com.refinedmods.refinedstorage.blockentity.grid.portable.PortableGridBlockEntity; import com.refinedmods.refinedstorage.util.RenderUtils; import com.refinedmods.refinedstorage.util.TimeUtils; import net.minecraft.ChatFormatting; @@ -37,7 +37,6 @@ import net.minecraft.client.resources.language.I18n; import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; - import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; @@ -658,6 +657,7 @@ public class GridScreen extends BaseScreen implements IScreen if (!RS.CLIENT_CONFIG.getGrid().getRememberSearchQuery()) { searchQuery = ""; } + getView().removed(); } public SearchWidget getSearchField() { diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java index 96f6a470a..1600b836a 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java @@ -1,6 +1,7 @@ package com.refinedmods.refinedstorage.screen.grid.view; import com.refinedmods.refinedstorage.api.network.grid.IGrid; +import com.refinedmods.refinedstorage.integration.jei.IngredientTracker; import com.refinedmods.refinedstorage.screen.grid.GridScreen; import com.refinedmods.refinedstorage.screen.grid.filtering.GridFilterParser; import com.refinedmods.refinedstorage.screen.grid.sorting.IGridSorter; @@ -9,6 +10,7 @@ import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; import javax.annotation.Nullable; import java.util.*; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -22,6 +24,8 @@ public class GridViewImpl implements IGridView { private boolean active = false; private List stacks = new ArrayList<>(); + private List> deltaListeners = new ArrayList<>(); + public GridViewImpl(GridScreen screen, IGridSorter defaultSorter, List sorters) { this.screen = screen; this.defaultSorter = defaultSorter; @@ -73,6 +77,17 @@ public class GridViewImpl implements IGridView { this.screen.updateScrollbar(); } + @Override + public void addDeltaListener(Consumer listener) { + deltaListeners.add(listener); + } + + @Override + public void removed() { + deltaListeners.clear(); + IngredientTracker.invalidate(); + } + private Comparator getActiveSort() { IGrid grid = screen.getGrid(); SortingDirection sortingDirection = grid.getSortingDirection() == IGrid.SORTING_DIRECTION_DESCENDING ? SortingDirection.DESCENDING : SortingDirection.ASCENDING; @@ -153,6 +168,9 @@ public class GridViewImpl implements IGridView { if (craftingStack != null && shouldSort && activeFilters.test(existing)) { stacks.remove(craftingStack); } + + deltaListeners.forEach(consumer -> consumer.accept(stack)); + } else { if (shouldSort) { stacks.remove(existing); diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/IGridView.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/IGridView.java index 866040abd..bd4aa145c 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/IGridView.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/IGridView.java @@ -6,6 +6,7 @@ import javax.annotation.Nullable; import java.util.Collection; import java.util.List; import java.util.UUID; +import java.util.function.Consumer; public interface IGridView { List getStacks(); @@ -24,4 +25,8 @@ public interface IGridView { boolean canCraft(); void sort(); + + void addDeltaListener(Consumer listener); + + void removed(); }