ソースを参照

Fix brewing potions not appearing and allow scrolling in the tabs for villager like recipe viewing screen

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 4 年 前
コミット
a8445af105
16 ファイル変更134 行追加100 行削除
  1. 2 0
      RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ClientHelper.java
  2. 2 0
      RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/REIHelper.java
  3. 2 1
      RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeDisplay.java
  4. 11 1
      RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeHelper.java
  5. 1 1
      RoughlyEnoughItems-default-plugin/src/main/java/me/shedaniel/rei/plugin/brewing/DefaultBrewingDisplay.java
  6. 7 14
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java
  7. 15 6
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java
  8. 4 5
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java
  9. 2 2
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java
  10. 26 28
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/ClientHelperImpl.java
  11. 27 9
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java
  12. 25 26
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java
  13. 7 5
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/ScreenHelper.java
  14. 1 1
      RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java
  15. 1 0
      RoughlyEnoughItems-runtime/src/main/resources/roughlyenoughitems-runtime.accessWidener
  16. 1 1
      gradle.properties

+ 2 - 0
RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ClientHelper.java

@@ -65,6 +65,8 @@ public interface ClientHelper {
      */
     void setCheating(boolean cheating);
     
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     List<ItemStack> getInventoryItemsTypes();
     
     /**

+ 2 - 0
RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/REIHelper.java

@@ -65,6 +65,8 @@ public interface REIHelper {
     
     @NotNull
     @ApiStatus.Internal
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     List<ItemStack> getInventoryStacks();
     
     void queueTooltip(@Nullable Tooltip tooltip);

+ 2 - 1
RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeDisplay.java

@@ -42,9 +42,10 @@ public interface RecipeDisplay {
     
     /**
      * @return a list of outputs
+     * @deprecated Use {@link RecipeDisplay#getResultingEntries()}
      */
     @Deprecated
-    @ApiStatus.ScheduledForRemoval
+    @ApiStatus.ScheduledForRemoval(inVersion = "1.17")
     @NotNull
     default List<EntryStack> getOutputEntries() {
         return Collections.emptyList();

+ 11 - 1
RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeHelper.java

@@ -81,7 +81,17 @@ public interface RecipeHelper {
      * @param inventoryItems the materials
      * @return the list of craftable entries
      */
-    List<EntryStack> findCraftableEntriesByItems(List<EntryStack> inventoryItems);
+    List<EntryStack> findCraftableEntriesByItems(Iterable<EntryStack> inventoryItems);
+    
+    /**
+     * Gets all craftable items from materials.
+     *
+     * @param inventoryItems the materials
+     * @return the list of craftable entries
+     */
+    default List<EntryStack> findCraftableEntriesByItems(List<EntryStack> inventoryItems) {
+        return findCraftableEntriesByItems((Iterable<EntryStack>) inventoryItems);
+    }
     
     /**
      * Registers a category

+ 1 - 1
RoughlyEnoughItems-default-plugin/src/main/java/me/shedaniel/rei/plugin/brewing/DefaultBrewingDisplay.java

@@ -80,7 +80,7 @@ public class DefaultBrewingDisplay implements RecipeDisplay {
         for (int i = 0; i < slot * 2; i++)
             stack.add(EntryStack.empty());
         for (int i = 0; i < 6 - slot * 2; i++)
-            stack.addAll(getOutputEntries());
+            stack.add(output);
         return stack;
     }
     

+ 7 - 14
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java

@@ -74,10 +74,7 @@ import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
 
 @ApiStatus.Internal
 public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverlay {
@@ -498,7 +495,6 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl
     
     @Override
     public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
-        List<ItemStack> currentStacks = ClientHelper.getInstance().getInventoryItemsTypes();
         if (shouldReInit) {
             ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
             init();
@@ -510,9 +506,12 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl
                 }
             }
         }
-        if (ConfigManager.getInstance().isCraftableOnlyEnabled() && ((currentStacks.size() != ScreenHelper.inventoryStacks.size()) || !hasSameListContent(new LinkedList<>(ScreenHelper.inventoryStacks), currentStacks))) {
-            ScreenHelper.inventoryStacks = currentStacks;
-            ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
+        if (ConfigManager.getInstance().isCraftableOnlyEnabled()) {
+            Set<EntryStack> currentStacks = ClientHelperImpl.getInstance()._getInventoryItemsTypes();
+            if (!currentStacks.equals(ScreenHelper.inventoryStacks)) {
+                ScreenHelper.inventoryStacks = currentStacks;
+                ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
+            }
         }
         if (OverlaySearchField.isSearching) {
             matrices.pushPose();
@@ -596,12 +595,6 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl
         ScreenHelper.drawHoveringWidget(matrices, mouseX, mouseY, renderTooltipCallback, tooltipWidth, tooltipHeight, 0);
     }
     
-    private boolean hasSameListContent(List<ItemStack> list1, List<ItemStack> list2) {
-        list1.sort(Comparator.comparing(Object::toString));
-        list2.sort(Comparator.comparing(Object::toString));
-        return CollectionUtils.mapAndJoinToString(list1, Object::toString, "").equals(CollectionUtils.mapAndJoinToString(list2, Object::toString, ""));
-    }
-    
     public void addTooltip(@Nullable Tooltip tooltip) {
         if (tooltip != null)
             TOOLTIPS.add(tooltip);

+ 15 - 6
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java

@@ -290,10 +290,10 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
     }
     
     @Override
-    public boolean mouseScrolled(double double_1, double double_2, double double_3) {
+    public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
         double height = scrolling.getMaxScrollHeight();
-        if (scrollListBounds.contains(double_1, double_2) && height > scrollListBounds.height - 2) {
-            scrolling.offset(ClothConfigInitializer.getScrollStep() * -double_3, true);
+        if (scrollListBounds.contains(mouseX, mouseY) && height > scrollListBounds.height - 2) {
+            scrolling.offset(ClothConfigInitializer.getScrollStep() * -amount, true);
             if (scrollBarAlphaFuture == 0)
                 scrollBarAlphaFuture = 1f;
             if (System.currentTimeMillis() - scrollBarAlphaFutureTime > 300f)
@@ -301,10 +301,19 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
             return true;
         }
         for (GuiEventListener listener : children())
-            if (listener.mouseScrolled(double_1, double_2, double_3))
+            if (listener.mouseScrolled(mouseX, mouseY, amount))
                 return true;
+        int tabSize = ConfigObject.getInstance().isUsingCompactTabs() ? 24 : 28;
+        if (mouseX >= bounds.x && mouseX <= bounds.getMaxX() && mouseY >= bounds.y - tabSize && mouseY < bounds.y) {
+            if (amount < 0) selectedCategoryIndex++;
+            else if (amount > 0) selectedCategoryIndex--;
+            if (selectedCategoryIndex < 0) selectedCategoryIndex = categories.size() - 1;
+            else if (selectedCategoryIndex >= categories.size()) selectedCategoryIndex = 0;
+            ClientHelperImpl.getInstance().openRecipeViewingScreen(categoryMap, categories.get(selectedCategoryIndex).getIdentifier(), ingredientStackToNotice, resultStackToNotice);
+            return true;
+        }
         if (bounds.contains(PointHelper.ofMouse())) {
-            if (double_3 < 0 && categoryMap.get(categories.get(selectedCategoryIndex)).size() > 1) {
+            if (amount < 0 && categoryMap.get(categories.get(selectedCategoryIndex)).size() > 1) {
                 selectedRecipeIndex++;
                 if (selectedRecipeIndex >= categoryMap.get(categories.get(selectedCategoryIndex)).size())
                     selectedRecipeIndex = 0;
@@ -318,7 +327,7 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
                 return true;
             }
         }
-        return super.mouseScrolled(double_1, double_2, double_3);
+        return super.mouseScrolled(mouseX, mouseY, amount);
     }
     
     @Override

+ 4 - 5
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java

@@ -23,6 +23,7 @@
 
 package me.shedaniel.rei.gui.widget;
 
+import com.google.common.base.Stopwatch;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.mojang.blaze3d.vertex.PoseStack;
@@ -429,7 +430,7 @@ public class EntryListWidget extends WidgetWithBounds {
     }
     
     public void updateSearch(String searchTerm, boolean ignoreLastSearch) {
-        long started = System.nanoTime();
+        Stopwatch stopwatch = Stopwatch.createStarted();
         if (ignoreLastSearch || this.lastSearchTerm == null || !this.lastSearchTerm.equals(searchTerm)) {
             this.lastSearchTerm = searchTerm;
             this.lastSearchArguments = SearchArgument.processSearchTerm(searchTerm);
@@ -437,7 +438,7 @@ public class EntryListWidget extends WidgetWithBounds {
             boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty();
             Set<Integer> workingItems = checkCraftable ? Sets.newHashSet() : null;
             if (checkCraftable)
-                workingItems.addAll(CollectionUtils.map(RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)), EntryStack::hashIgnoreAmount));
+                workingItems.addAll(CollectionUtils.map(RecipeHelper.getInstance().findCraftableEntriesByItems(ScreenHelper.inventoryStacks), EntryStack::hashIgnoreAmount));
             List<EntryStack> stacks = EntryRegistry.getInstance().getPreFilteredList();
             if (stacks instanceof CopyOnWriteArrayList && !stacks.isEmpty()) {
                 if (ConfigObject.getInstance().shouldAsyncSearch()) {
@@ -488,10 +489,8 @@ public class EntryListWidget extends WidgetWithBounds {
         FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
         if (favoritesListWidget != null)
             favoritesListWidget.updateSearch(this, searchTerm);
-        long ended = System.nanoTime();
-        long time = ended - started;
         if (ConfigObject.getInstance().doDebugSearchTimeRequired())
-            RoughlyEnoughItemsCore.LOGGER.info("Search Used: %.2fms", time * 1e-6);
+            RoughlyEnoughItemsCore.LOGGER.info("Search Used: %s", stopwatch.stop().toString());
         updateEntriesPosition();
     }
     

+ 2 - 2
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java

@@ -201,7 +201,7 @@ public class FavoritesListWidget extends WidgetWithBounds {
                 boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty();
                 Set<Integer> workingItems = checkCraftable ? Sets.newHashSet() : null;
                 if (checkCraftable)
-                    workingItems.addAll(CollectionUtils.map(RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)), EntryStack::hashIgnoreAmount));
+                    workingItems.addAll(CollectionUtils.map(RecipeHelper.getInstance().findCraftableEntriesByItems(ScreenHelper.inventoryStacks), EntryStack::hashIgnoreAmount));
                 for (EntryStack stack : ConfigObject.getInstance().getFavorites()) {
                     if (listWidget.canLastSearchTermsBeAppliedTo(stack)) {
                         if (checkCraftable && !workingItems.contains(stack.hashIgnoreAmount()))
@@ -222,7 +222,7 @@ public class FavoritesListWidget extends WidgetWithBounds {
                 boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty();
                 Set<Integer> workingItems = checkCraftable ? Sets.newHashSet() : null;
                 if (checkCraftable)
-                    workingItems.addAll(CollectionUtils.map(RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)), EntryStack::hashIgnoreAmount));
+                    workingItems.addAll(CollectionUtils.map(RecipeHelper.getInstance().findCraftableEntriesByItems(ScreenHelper.inventoryStacks), EntryStack::hashIgnoreAmount));
                 for (EntryStack stack : ConfigObject.getInstance().getFavorites()) {
                     if (checkCraftable && !workingItems.contains(stack.hashIgnoreAmount()))
                         continue;

+ 26 - 28
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/ClientHelperImpl.java

@@ -65,6 +65,8 @@ import org.jetbrains.annotations.Nullable;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static me.shedaniel.rei.impl.Internals.attachInstance;
 
@@ -206,10 +208,15 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
     
     @Override
     public List<ItemStack> getInventoryItemsTypes() {
-        List<ItemStack> inventoryStacks = new ArrayList<>(Minecraft.getInstance().player.inventory.items);
-        inventoryStacks.addAll(Minecraft.getInstance().player.inventory.armor);
-        inventoryStacks.addAll(Minecraft.getInstance().player.inventory.offhand);
-        return inventoryStacks;
+        return Minecraft.getInstance().player.inventory.compartments.stream().flatMap(Collection::stream).collect(Collectors.toList());
+    }
+    
+    @ApiStatus.Internal
+    public Set<EntryStack> _getInventoryItemsTypes() {
+        return Minecraft.getInstance().player.inventory.compartments.stream()
+                .flatMap(Collection::stream)
+                .map(EntryStack::create)
+                .collect(Collectors.toSet());
     }
     
     @ApiStatus.ScheduledForRemoval
@@ -269,7 +276,20 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
         modNameCache.put("global", "Global");
     }
     
-    public static final class ViewSearchBuilder implements ClientHelper.ViewSearchBuilder {
+    private static abstract class AbstractViewSearchBuilder implements ClientHelper.ViewSearchBuilder {
+        @Override
+        public ClientHelper.ViewSearchBuilder fillPreferredOpenedCategory() {
+            if (getPreferredOpenedCategory() == null) {
+                Screen currentScreen = Minecraft.getInstance().screen;
+                if (currentScreen instanceof RecipeScreen) {
+                    setPreferredOpenedCategory(((RecipeScreen) currentScreen).getCurrentCategory());
+                }
+            }
+            return this;
+        }
+    }
+    
+    public static final class ViewSearchBuilder extends AbstractViewSearchBuilder {
         @NotNull private final Set<ResourceLocation> categories = new HashSet<>();
         @NotNull private final List<EntryStack> recipesFor = new ArrayList<>();
         @NotNull private final List<EntryStack> usagesFor = new ArrayList<>();
@@ -332,17 +352,6 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
             return this.preferredOpenedCategory;
         }
         
-        @Override
-        public ClientHelper.ViewSearchBuilder fillPreferredOpenedCategory() {
-            if (getPreferredOpenedCategory() == null) {
-                Screen currentScreen = Minecraft.getInstance().screen;
-                if (currentScreen instanceof RecipeScreen) {
-                    setPreferredOpenedCategory(((RecipeScreen) currentScreen).getCurrentCategory());
-                }
-            }
-            return this;
-        }
-        
         @Override
         public ClientHelper.ViewSearchBuilder setInputNotice(@Nullable EntryStack stack) {
             this.inputNotice = stack;
@@ -374,7 +383,7 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
         }
     }
     
-    public static final class LegacyWrapperViewSearchBuilder implements ClientHelper.ViewSearchBuilder {
+    public static final class LegacyWrapperViewSearchBuilder extends AbstractViewSearchBuilder {
         @NotNull private final Map<RecipeCategory<?>, List<RecipeDisplay>> map;
         @Nullable private ResourceLocation preferredOpenedCategory = null;
         @Nullable private EntryStack inputNotice;
@@ -431,17 +440,6 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
             return this.preferredOpenedCategory;
         }
         
-        @Override
-        public ClientHelper.ViewSearchBuilder fillPreferredOpenedCategory() {
-            if (getPreferredOpenedCategory() == null) {
-                Screen currentScreen = Minecraft.getInstance().screen;
-                if (currentScreen instanceof RecipeScreen) {
-                    setPreferredOpenedCategory(((RecipeScreen) currentScreen).getCurrentCategory());
-                }
-            }
-            return this;
-        }
-        
         @Override
         public ClientHelper.ViewSearchBuilder setInputNotice(@Nullable EntryStack stack) {
             this.inputNotice = stack;

+ 27 - 9
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java

@@ -23,13 +23,14 @@
 
 package me.shedaniel.rei.impl;
 
+import com.google.common.base.Stopwatch;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.EntryRegistry;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.impl.filtering.FilteringContextImpl;
+import me.shedaniel.rei.impl.filtering.FilteringContextType;
 import me.shedaniel.rei.impl.filtering.FilteringRule;
 import me.shedaniel.rei.utils.CollectionUtils;
 import net.fabricmc.api.EnvType;
@@ -43,6 +44,7 @@ import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 @ApiStatus.Internal
@@ -86,21 +88,37 @@ public class EntryRegistryImpl implements EntryRegistry {
     @Override
     @ApiStatus.Experimental
     public void refilter() {
-        long started = System.currentTimeMillis();
+        Stopwatch stopwatch = Stopwatch.createStarted();
         
         FilteringContextImpl context = new FilteringContextImpl(entries);
         List<FilteringRule<?>> rules = ((ConfigObjectImpl) ConfigObject.getInstance()).getFilteringRules();
+        Stopwatch innerStopwatch = Stopwatch.createStarted();
         for (int i = rules.size() - 1; i >= 0; i--) {
-            context.handleResult(rules.get(i).processFilteredStacks(context));
+            innerStopwatch.reset().start();
+            FilteringRule<?> rule = rules.get(i);
+            context.handleResult(rule.processFilteredStacks(context));
+            RoughlyEnoughItemsCore.LOGGER.debug("Refiltered rule [%s] in %s.", FilteringRule.REGISTRY.getKey(rule).toString(), innerStopwatch.stop().toString());
         }
         
-        Set<AmountIgnoredEntryStackWrapper> set = CollectionUtils.mapParallel(entries, AmountIgnoredEntryStackWrapper::new, Sets::newLinkedHashSet);
-        set.removeAll(CollectionUtils.mapParallel(context.getHiddenStacks(), AmountIgnoredEntryStackWrapper::new, Sets::newHashSet));
-        preFilteredList.clear();
-        preFilteredList.addAll(CollectionUtils.mapParallel(set, AmountIgnoredEntryStackWrapper::unwrap));
+        Set<AmountIgnoredEntryStackWrapper> hiddenStacks = context.stacks.get(FilteringContextType.HIDDEN);
+        if (hiddenStacks.isEmpty()) {
+            preFilteredList.clear();
+            preFilteredList.addAll(entries);
+        } else {
+            preFilteredList.clear();
+            preFilteredList.addAll(entries.parallelStream()
+                    .map(AmountIgnoredEntryStackWrapper::new)
+                    .filter(not(hiddenStacks::contains))
+                    .map(AmountIgnoredEntryStackWrapper::unwrap)
+                    .collect(Collectors.toList()));
+        }
         
-        long time = System.currentTimeMillis() - started;
-        RoughlyEnoughItemsCore.LOGGER.info("Refiltered %d entries with %d rules in %dms.", entries.size() - preFilteredList.size(), rules.size(), time);
+        RoughlyEnoughItemsCore.LOGGER.debug("Refiltered %d entries with %d rules in %s.", entries.size() - preFilteredList.size(), rules.size(), stopwatch.stop().toString());
+    }
+    
+    static <T> Predicate<T> not(Predicate<? super T> target) {
+        Objects.requireNonNull(target);
+        return (Predicate<T>) target.negate();
     }
     
     public void reset() {

+ 25 - 26
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java

@@ -23,6 +23,7 @@
 
 package me.shedaniel.rei.impl;
 
+import com.google.common.base.Stopwatch;
 import com.google.common.collect.*;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
@@ -42,6 +43,7 @@ import net.minecraft.world.InteractionResult;
 import net.minecraft.world.InteractionResultHolder;
 import net.minecraft.world.item.crafting.Recipe;
 import net.minecraft.world.item.crafting.RecipeManager;
+import org.apache.commons.lang3.tuple.MutablePair;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -77,7 +79,7 @@ public class RecipeHelperImpl implements RecipeHelper {
     private boolean arePluginsLoading = false;
     
     @Override
-    public List<EntryStack> findCraftableEntriesByItems(List<EntryStack> inventoryItems) {
+    public List<EntryStack> findCraftableEntriesByItems(Iterable<EntryStack> inventoryItems) {
         List<EntryStack> craftables = new ArrayList<>();
         for (List<RecipeDisplay> value : recipeDisplays.values())
             for (RecipeDisplay recipeDisplay : Lists.newArrayList(value)) {
@@ -149,7 +151,7 @@ public class RecipeHelperImpl implements RecipeHelper {
     
     @Override
     public Map<RecipeCategory<?>, List<RecipeDisplay>> buildMapFor(ClientHelper.ViewSearchBuilder builder) {
-        long start = Util.getNanos();
+        Stopwatch stopwatch = Stopwatch.createStarted();
         Set<ResourceLocation> categories = builder.getCategories();
         List<EntryStack> recipesFor = builder.getRecipesFor();
         List<EntryStack> usagesFor = builder.getUsagesFor();
@@ -244,9 +246,8 @@ public class RecipeHelperImpl implements RecipeHelper {
             }
         }
         
-        long end = Util.getNanos();
-        String message = String.format("Built Recipe View in %dμs for %d categories, %d recipes for, %d usages for and %d live recipe generators.",
-                (end - start) / 1000, categories.size(), recipesFor.size(), usagesFor.size(), liveRecipeGenerators.size());
+        String message = String.format("Built Recipe View in %s for %d categories, %d recipes for, %d usages for and %d live recipe generators.",
+                stopwatch.stop().toString(), categories.size(), recipesFor.size(), usagesFor.size(), liveRecipeGenerators.size());
         if (ConfigObject.getInstance().doDebugSearchTimeRequired()) {
             RoughlyEnoughItemsCore.LOGGER.info(message);
         } else {
@@ -305,24 +306,20 @@ public class RecipeHelperImpl implements RecipeHelper {
             autoCraftAreaSupplierMap.put(category, rectangle);
     }
     
-    private void startSection(Object[] sectionData, String section) {
-        sectionData[0] = Util.getNanos();
-        sectionData[2] = section;
+    private void startSection(MutablePair<Stopwatch, String> sectionData, String section) {
+        sectionData.setRight(section);
         RoughlyEnoughItemsCore.LOGGER.debug("Reloading Section: \"%s\"", section);
+        sectionData.getLeft().start();
     }
     
-    private void endSection(Object[] sectionData) {
-        sectionData[1] = Util.getNanos();
-        long time = (long) sectionData[1] - (long) sectionData[0];
-        String section = (String) sectionData[2];
-        if (time >= 1000000) {
-            RoughlyEnoughItemsCore.LOGGER.debug("Reloading Section: \"%s\" done in %.2fms", section, time / 1000000.0F);
-        } else {
-            RoughlyEnoughItemsCore.LOGGER.debug("Reloading Section: \"%s\" done in %.2fμs", section, time / 1000.0F);
-        }
+    private void endSection(MutablePair<Stopwatch, String> sectionData) {
+        sectionData.getLeft().stop();
+        String section = sectionData.getRight();
+        RoughlyEnoughItemsCore.LOGGER.debug("Reloading Section: \"%s\" done in %s", section, sectionData.getLeft().toString());
+        sectionData.getLeft().reset();
     }
     
-    private void pluginSection(Object[] sectionData, String sectionName, List<REIPluginV0> list, Consumer<REIPluginV0> consumer) {
+    private void pluginSection(MutablePair<Stopwatch, String> sectionData, String sectionName, List<REIPluginV0> list, Consumer<REIPluginV0> consumer) {
         for (REIPluginV0 plugin : list) {
             try {
                 startSection(sectionData, sectionName + " for " + plugin.getPluginIdentifier().toString());
@@ -345,7 +342,7 @@ public class RecipeHelperImpl implements RecipeHelper {
     
     public void recipesLoaded(RecipeManager recipeManager) {
         long startTime = Util.getMillis();
-        Object[] sectionData = {0L, 0L, ""};
+        MutablePair<Stopwatch, String> sectionData = new MutablePair<>(Stopwatch.createUnstarted(), "");
         
         startSection(sectionData, "reset-data");
         arePluginsLoading = true;
@@ -401,14 +398,16 @@ public class RecipeHelperImpl implements RecipeHelper {
         startSection(sectionData, "recipe-functions");
         if (!recipeFunctions.isEmpty()) {
             @SuppressWarnings("rawtypes") List<Recipe> allSortedRecipes = getAllSortedRecipes();
-            Collections.reverse(allSortedRecipes);
-            for (RecipeFunction recipeFunction : recipeFunctions) {
-                try {
-                    for (Recipe<?> recipe : CollectionUtils.filter(allSortedRecipes, recipe -> recipeFunction.recipeFilter.test(recipe))) {
-                        registerDisplay(recipeFunction.category, (RecipeDisplay) recipeFunction.mappingFunction.apply(recipe), 0);
+            for (int i = allSortedRecipes.size() - 1; i >= 0; i--) {
+                Recipe recipe = allSortedRecipes.get(i);
+                for (RecipeFunction recipeFunction : recipeFunctions) {
+                    try {
+                        if (recipeFunction.recipeFilter.test(recipe)) {
+                            registerDisplay(recipeFunction.category, (RecipeDisplay) recipeFunction.mappingFunction.apply(recipe), 0);
+                        }
+                    } catch (Throwable e) {
+                        RoughlyEnoughItemsCore.LOGGER.error("Failed to add recipes!", e);
                     }
-                } catch (Throwable e) {
-                    RoughlyEnoughItemsCore.LOGGER.error("Failed to add recipes!", e);
                 }
             }
         }

+ 7 - 5
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/ScreenHelper.java

@@ -58,9 +58,8 @@ import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import static me.shedaniel.rei.impl.Internals.attachInstance;
 
@@ -71,7 +70,7 @@ public class ScreenHelper implements ClientModInitializer, REIHelper {
     private static final ResourceLocation DISPLAY_TEXTURE_DARK = new ResourceLocation("roughlyenoughitems", "textures/gui/display_dark.png");
     private OverlaySearchField searchField;
     @ApiStatus.Internal
-    public static List<ItemStack> inventoryStacks = Lists.newArrayList();
+    public static Set<EntryStack> inventoryStacks = Sets.newHashSet();
     private static ContainerScreenOverlay overlay;
     private static AbstractContainerScreen<?> previousContainerScreen = null;
     private static LinkedHashSet<RecipeScreen> lastRecipeScreen = Sets.newLinkedHashSetWithExpectedSize(5);
@@ -101,7 +100,10 @@ public class ScreenHelper implements ClientModInitializer, REIHelper {
     
     @Override
     public @NotNull List<ItemStack> getInventoryStacks() {
-        return inventoryStacks;
+        return inventoryStacks.stream()
+                .map(EntryStack::getItemStack)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
     }
     
     @Nullable

+ 1 - 1
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java

@@ -43,7 +43,7 @@ import java.util.concurrent.TimeoutException;
 
 @Environment(EnvType.CLIENT)
 public class FilteringContextImpl implements FilteringContext {
-    private final Map<FilteringContextType, Set<AmountIgnoredEntryStackWrapper>> stacks;
+    public final Map<FilteringContextType, Set<AmountIgnoredEntryStackWrapper>> stacks;
     private final Map<FilteringContextType, Collection<EntryStack>> cachedStacks;
     
     public FilteringContextImpl(List<EntryStack> allStacks) {

+ 1 - 0
RoughlyEnoughItems-runtime/src/main/resources/roughlyenoughitems-runtime.accessWidener

@@ -11,3 +11,4 @@ accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScr
 accessible field net/minecraft/client/gui/components/ImageButton resourceLocation Lnet/minecraft/resources/ResourceLocation;
 accessible method net/minecraft/client/gui/GuiComponent innerBlit (Lcom/mojang/math/Matrix4f;IIIIIFFFF)V
 accessible field net/minecraft/world/item/CreativeModeTab langId Ljava/lang/String;
+accessible field net/minecraft/world/entity/player/Inventory compartments Ljava/util/List;

+ 1 - 1
gradle.properties

@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx3G
-mod_version=5.2.9
+mod_version=5.2.10
 supported_version=1.16.2
 minecraft_version=1.16.2-rc1
 yarn_version=1.16.2-rc1+build.4+legacy.20w09a+build.8