Rework Ingredient tracker to track stored items and compare IngredientList against that
This commit is contained in:
@@ -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
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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<GridContainerMenu, Object> {
|
||||
@@ -58,26 +58,38 @@ public class GridRecipeTransferHandler implements IRecipeTransferHandler<GridCon
|
||||
|
||||
@Override
|
||||
public @Nullable IRecipeTransferError transferRecipe(GridContainerMenu container, Object recipe, IRecipeSlotsView recipeSlots, Player player, boolean maxTransfer, boolean doTransfer) {
|
||||
if (!(container.getScreenInfoProvider() instanceof GridScreen)) {
|
||||
if (!(container.getScreenInfoProvider() instanceof GridScreen gridScreen)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//When JEI is open the screen no longer ticks and doesn't run Actions. However, we do still want to run the actions that update the grid to keep the stored items up to date
|
||||
gridScreen.runActions();
|
||||
|
||||
Ingredient.IngredientList ingredientList = new Ingredient.IngredientList();
|
||||
for (IRecipeSlotView slotView : recipeSlots.getSlotViews(RecipeIngredientRole.INPUT)) {
|
||||
Optional<ItemStack> 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<GridCon
|
||||
)
|
||||
));
|
||||
} else {
|
||||
moveItems(container, recipe, recipeLayout, tracker);
|
||||
moveItems(container, recipe, recipeLayout, player);
|
||||
}
|
||||
} else {
|
||||
if (tracker.hasMissing()) {
|
||||
return new RecipeTransferCraftingGridError(tracker);
|
||||
if (ingredientList.hasMissing()) {
|
||||
return new RecipeTransferCraftingGridError(ingredientList);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IRecipeTransferError transferRecipeForPatternGrid(GridContainerMenu container, Object recipe, IRecipeSlotsView recipeLayout, Player player, boolean doTransfer) {
|
||||
IngredientTracker tracker = createTracker(container, recipeLayout, player, doTransfer);
|
||||
|
||||
private IRecipeTransferError transferRecipeForPatternGrid(GridContainerMenu container, Object recipe, IRecipeSlotsView recipeLayout, Player player, boolean doTransfer, Ingredient.IngredientList ingredientList) {
|
||||
if (doTransfer) {
|
||||
moveItems(container, recipe, recipeLayout, tracker);
|
||||
moveItems(container, recipe, recipeLayout, player);
|
||||
} else {
|
||||
if (tracker.isAutocraftingAvailable()) {
|
||||
return new RecipeTransferPatternGridError(tracker);
|
||||
if (ingredientList.isAutocraftingAvailable()) {
|
||||
return new RecipeTransferPatternGridError(ingredientList);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IngredientTracker createTracker(GridContainerMenu container, IRecipeSlotsView recipeLayout, Player player, boolean doTransfer) {
|
||||
IngredientTracker tracker = new IngredientTracker(recipeLayout, doTransfer);
|
||||
|
||||
// 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.
|
||||
Collection<IGridStack> 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<GridCon
|
||||
RS.NETWORK_HANDLER.sendToServer(new GridTransferMessage(inputs));
|
||||
}
|
||||
|
||||
private void moveForProcessing(IRecipeSlotsView recipeLayout, IngredientTracker tracker) {
|
||||
private void moveForProcessing(IRecipeSlotsView recipeLayout, GridContainerMenu gridContainer, Player player) {
|
||||
List<ItemStack> inputs = new LinkedList<>();
|
||||
List<ItemStack> outputs = new LinkedList<>();
|
||||
|
||||
@@ -194,13 +165,13 @@ public class GridRecipeTransferHandler implements IRecipeTransferHandler<GridCon
|
||||
|
||||
List<IRecipeSlotView> inputSlots = recipeLayout.getSlotViews(RecipeIngredientRole.INPUT);
|
||||
for (IRecipeSlotView view : inputSlots) {
|
||||
handleItemIngredient(inputs, view, tracker);
|
||||
handleItemIngredient(inputs, view, gridContainer, player);
|
||||
handleFluidIngredient(fluidInputs, view);
|
||||
}
|
||||
|
||||
List<IRecipeSlotView> 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<GridCon
|
||||
}
|
||||
}
|
||||
|
||||
private void handleItemIngredient(List<ItemStack> list, IRecipeSlotView slotView, IngredientTracker tracker) {
|
||||
private void handleItemIngredient(List<ItemStack> 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();
|
||||
|
@@ -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<Ingredient> 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<UUID, Integer> createCraftingRequests() {
|
||||
Map<UUID, Integer> toRequest = new HashMap<>();
|
||||
|
||||
for (Ingredient ingredient : ingredients) {
|
||||
if (!ingredient.isAvailable() && ingredient.isCraftable()) {
|
||||
toRequest.merge(ingredient.getCraftStackId(), ingredient.getMissingAmount(), Integer::sum);
|
||||
}
|
||||
}
|
||||
|
||||
return toRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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<Ingredient> ingredients = new ArrayList<>();
|
||||
private final Map<ResourceLocation, Integer> storedItems = new HashMap<>();
|
||||
private boolean doTransfer;
|
||||
|
||||
public IngredientTracker(IRecipeSlotsView recipeLayout, boolean doTransfer) {
|
||||
for (IRecipeSlotView slotView : recipeLayout.getSlotViews(RecipeIngredientRole.INPUT)) {
|
||||
Optional<ItemStack> optionalItemStack = slotView.getIngredients(VanillaTypes.ITEM_STACK).findAny();
|
||||
private static IngredientTracker INSTANCE;
|
||||
|
||||
optionalItemStack.ifPresent(stack -> ingredients.add(new Ingredient(slotView, stack.getCount())));
|
||||
private final Map<ItemStackKey, Integer> storedItems = new HashMap<>();
|
||||
private final Map<ItemStackKey, Integer> patternItems = new HashMap<>();
|
||||
private final Map<ItemStackKey, UUID> 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<IGridStack> 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<Ingredient> getIngredients() {
|
||||
return ingredients;
|
||||
|
||||
public ItemStack findBestMatch(GridContainerMenu gridContainer, Player player, List<ItemStack> 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<Integer, Integer> usedMatrixStacks = new HashMap<>();
|
||||
Map<Integer, Integer> usedInventoryStacks = new HashMap<>();
|
||||
Map<ItemStackKey, Integer> 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<ItemStack> 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<UUID, Integer> createCraftingRequests() {
|
||||
Map<UUID, Integer> toRequest = new HashMap<>();
|
||||
|
||||
for (Ingredient ingredient : ingredients) {
|
||||
if (!ingredient.isAvailable() && ingredient.isCraftable()) {
|
||||
toRequest.merge(ingredient.getCraftStackId(), ingredient.getMissingAmount(), Integer::sum);
|
||||
private boolean checkStack(Map<Integer, Integer> 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<ItemStack> 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);
|
||||
}
|
||||
}
|
||||
|
@@ -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());
|
||||
|
@@ -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;
|
||||
|
@@ -73,7 +73,7 @@ public abstract class BaseScreen<T extends AbstractContainerMenu> extends Abstra
|
||||
executeLater(AbstractContainerScreen.class, callback);
|
||||
}
|
||||
|
||||
private void runActions() {
|
||||
public void runActions() {
|
||||
runActions(getClass());
|
||||
runActions(AbstractContainerScreen.class);
|
||||
}
|
||||
|
@@ -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<GridContainerMenu> implements IScreen
|
||||
if (!RS.CLIENT_CONFIG.getGrid().getRememberSearchQuery()) {
|
||||
searchQuery = "";
|
||||
}
|
||||
getView().removed();
|
||||
}
|
||||
|
||||
public SearchWidget getSearchField() {
|
||||
|
@@ -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<IGridStack> stacks = new ArrayList<>();
|
||||
|
||||
private List<Consumer<IGridStack>> deltaListeners = new ArrayList<>();
|
||||
|
||||
public GridViewImpl(GridScreen screen, IGridSorter defaultSorter, List<IGridSorter> sorters) {
|
||||
this.screen = screen;
|
||||
this.defaultSorter = defaultSorter;
|
||||
@@ -73,6 +77,17 @@ public class GridViewImpl implements IGridView {
|
||||
this.screen.updateScrollbar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDeltaListener(Consumer<IGridStack> listener) {
|
||||
deltaListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
deltaListeners.clear();
|
||||
IngredientTracker.invalidate();
|
||||
}
|
||||
|
||||
private Comparator<IGridStack> 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);
|
||||
|
@@ -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<IGridStack> getStacks();
|
||||
@@ -24,4 +25,8 @@ public interface IGridView {
|
||||
boolean canCraft();
|
||||
|
||||
void sort();
|
||||
|
||||
void addDeltaListener(Consumer<IGridStack> listener);
|
||||
|
||||
void removed();
|
||||
}
|
||||
|
Reference in New Issue
Block a user