فهرست منبع

Performance Improvements

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 5 سال پیش
والد
کامیت
e7ab293918
23فایلهای تغییر یافته به همراه273 افزوده شده و 212 حذف شده
  1. 1 1
      gradle.properties
  2. 5 3
      src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java
  3. 2 0
      src/main/java/me/shedaniel/rei/api/ConfigManager.java
  4. 2 0
      src/main/java/me/shedaniel/rei/api/DisplayHelper.java
  5. 35 13
      src/main/java/me/shedaniel/rei/api/EntryRegistry.java
  6. 2 0
      src/main/java/me/shedaniel/rei/api/RecipeHelper.java
  7. 0 5
      src/main/java/me/shedaniel/rei/gui/ConfigReloadingScreen.java
  8. 5 5
      src/main/java/me/shedaniel/rei/gui/config/entry/FilteringEntry.java
  9. 1 2
      src/main/java/me/shedaniel/rei/gui/config/entry/FilteringScreen.java
  10. 5 8
      src/main/java/me/shedaniel/rei/gui/modules/Menu.java
  11. 2 3
      src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java
  12. 6 7
      src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java
  13. 9 6
      src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java
  14. 67 0
      src/main/java/me/shedaniel/rei/impl/AmountIgnoredEntryStackWrapper.java
  15. 42 112
      src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java
  16. 2 2
      src/main/java/me/shedaniel/rei/impl/FluidSupportProviderImpl.java
  17. 3 3
      src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java
  18. 5 9
      src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java
  19. 48 12
      src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java
  20. 5 11
      src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java
  21. 5 6
      src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java
  22. 7 4
      src/main/java/me/shedaniel/rei/tests/plugin/REITestPlugin.java
  23. 14 0
      src/main/java/me/shedaniel/rei/utils/CollectionUtils.java

+ 1 - 1
gradle.properties

@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx3G
-mod_version=4.8.1
+mod_version=4.9.0
 supported_version=1.16.x
 minecraft_version=1.16.1
 yarn_version=1.16.1+build.4+legacy.20w09a+build.8

+ 5 - 3
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java

@@ -242,12 +242,14 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer {
                         field.setAccessible(true);
                         Logger logger = (Logger) field.get(instance);
                         if (logger.getName().toLowerCase(Locale.ROOT).contains("subsystem")) {
-                            if (!new File(instance.getConfigDirectory(), "roughlyenoughitems/.ignoresubsystem").exists()) {
+                            File reiConfigFolder = new File(instance.getConfigDirectory(), "roughlyenoughitems");
+                            File ignoreFile = new File(reiConfigFolder, ".ignoresubsystem");
+                            if (!ignoreFile.exists()) {
                                 RoughlyEnoughItemsState.warn("Subsystem is detected (probably though Aristois), please contact support from them if anything happens.");
                                 RoughlyEnoughItemsState.onContinue(() -> {
                                     try {
-                                        new File(instance.getConfigDirectory(), "roughlyenoughitems").mkdirs();
-                                        new File(instance.getConfigDirectory(), "roughlyenoughitems/.ignoresubsystem").createNewFile();
+                                        reiConfigFolder.mkdirs();
+                                        ignoreFile.createNewFile();
                                     } catch (IOException e) {
                                         e.printStackTrace();
                                     }

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

@@ -28,6 +28,7 @@ import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.screen.Screen;
+import org.jetbrains.annotations.NotNull;
 
 @Environment(EnvType.CLIENT)
 public interface ConfigManager {
@@ -35,6 +36,7 @@ public interface ConfigManager {
     /**
      * @return the api instance of {@link me.shedaniel.rei.impl.ConfigManagerImpl}
      */
+    @NotNull
     static ConfigManager getInstance() {
         return RoughlyEnoughItemsCore.getConfigManager();
     }

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

@@ -31,6 +31,7 @@ import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.util.ActionResult;
 import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.List;
 import java.util.function.Supplier;
@@ -43,6 +44,7 @@ public interface DisplayHelper {
     /**
      * @return the api instance of {@link me.shedaniel.rei.impl.DisplayHelperImpl}
      */
+    @NotNull
     static DisplayHelper getInstance() {
         return RoughlyEnoughItemsCore.getDisplayHelper();
     }

+ 35 - 13
src/main/java/me/shedaniel/rei/api/EntryRegistry.java

@@ -30,10 +30,15 @@ import net.fabricmc.api.Environment;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @Environment(EnvType.CLIENT)
 public interface EntryRegistry {
@@ -41,6 +46,7 @@ public interface EntryRegistry {
     /**
      * @return the api instance of {@link me.shedaniel.rei.impl.EntryRegistryImpl}
      */
+    @NotNull
     static EntryRegistry getInstance() {
         return RoughlyEnoughItemsCore.getEntryRegistry();
     }
@@ -50,11 +56,21 @@ public interface EntryRegistry {
      *
      * @return a stacks list
      */
-    List<EntryStack> getStacksList();
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
+    @NotNull
+    default List<EntryStack> getStacksList() {
+        return getEntryStacks().collect(Collectors.toList());
+    }
     
+    @NotNull
+    Stream<EntryStack> getEntryStacks();
+    
+    @NotNull
     List<EntryStack> getPreFilteredList();
     
-    List<ItemStack> appendStacksForItem(Item item);
+    @NotNull
+    List<ItemStack> appendStacksForItem(@NotNull Item item);
     
     /**
      * Gets all possible stacks from an item
@@ -62,9 +78,10 @@ public interface EntryRegistry {
      * @param item the item to find
      * @return the array of possible stacks
      */
-    ItemStack[] getAllStacksFromItem(Item item);
+    @NotNull
+    ItemStack[] getAllStacksFromItem(@NotNull Item item);
     
-    default void registerEntry(EntryStack stack) {
+    default void registerEntry(@NotNull EntryStack stack) {
         registerEntryAfter(null, stack);
     }
     
@@ -74,8 +91,8 @@ public interface EntryRegistry {
      * @param afterEntry the stack to put after
      * @param stack      the stack to register
      */
-    default void registerEntryAfter(EntryStack afterEntry, EntryStack stack) {
-        registerEntryAfter(afterEntry, stack, true);
+    default void registerEntryAfter(@Nullable EntryStack afterEntry, @NotNull EntryStack stack) {
+        registerEntriesAfter(afterEntry, Collections.singletonList(stack));
     }
     
     /**
@@ -87,11 +104,16 @@ public interface EntryRegistry {
      * @see #queueRegisterEntryAfter(EntryStack, Collection) for a faster method
      */
     @Deprecated
-    @ApiStatus.Internal
-    void registerEntryAfter(EntryStack afterEntry, EntryStack stack, boolean checkAlreadyContains);
-    
+    @ApiStatus.ScheduledForRemoval
+    default void registerEntryAfter(@Nullable EntryStack afterEntry, @NotNull EntryStack stack, boolean checkAlreadyContains) {
+        registerEntryAfter(afterEntry, stack);
+    }
     
-    void queueRegisterEntryAfter(EntryStack afterEntry, Collection<? extends EntryStack> stacks);
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
+    default void queueRegisterEntryAfter(@Nullable EntryStack afterEntry, @NotNull Collection<@NotNull ? extends EntryStack> stacks) {
+        registerEntriesAfter(afterEntry, stacks);
+    }
     
     /**
      * Registers multiple stacks to the item list
@@ -99,7 +121,7 @@ public interface EntryRegistry {
      * @param afterStack the stack to put after
      * @param stacks     the stacks to register
      */
-    default void registerEntriesAfter(EntryStack afterStack, EntryStack... stacks) {
+    default void registerEntriesAfter(@Nullable EntryStack afterStack, @NotNull EntryStack... stacks) {
         registerEntriesAfter(afterStack, Arrays.asList(stacks));
     }
     
@@ -109,14 +131,14 @@ public interface EntryRegistry {
      * @param afterStack the stack to put after
      * @param stacks     the stacks to register
      */
-    void registerEntriesAfter(EntryStack afterStack, Collection<? extends EntryStack> stacks);
+    void registerEntriesAfter(@Nullable EntryStack afterStack, @NotNull Collection<@NotNull ? extends EntryStack> stacks);
     
     /**
      * Registers multiple stacks to the item list
      *
      * @param stacks the stacks to register
      */
-    default void registerEntries(EntryStack... stacks) {
+    default void registerEntries(@NotNull EntryStack... stacks) {
         registerEntriesAfter(null, stacks);
     }
     

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

@@ -32,6 +32,7 @@ import net.minecraft.recipe.Recipe;
 import net.minecraft.recipe.RecipeManager;
 import net.minecraft.util.Identifier;
 import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.List;
 import java.util.Map;
@@ -45,6 +46,7 @@ public interface RecipeHelper {
     /**
      * @return the api instance of {@link me.shedaniel.rei.impl.RecipeHelperImpl}
      */
+    @NotNull
     static RecipeHelper getInstance() {
         return RoughlyEnoughItemsCore.getRecipeHelper();
     }

+ 0 - 5
src/main/java/me/shedaniel/rei/gui/ConfigReloadingScreen.java

@@ -68,9 +68,4 @@ public class ConfigReloadingScreen extends Screen {
         this.drawCenteredString(matrices, this.textRenderer, string_3, this.width / 2, this.height / 2 - 41, 8421504);
         super.render(matrices, int_1, int_2, float_1);
     }
-    
-    @Override
-    public boolean isPauseScreen() {
-        return false;
-    }
 }

+ 5 - 5
src/main/java/me/shedaniel/rei/gui/config/entry/FilteringEntry.java

@@ -38,8 +38,7 @@ import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.text.TranslatableText;
 import org.jetbrains.annotations.ApiStatus;
 
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
 import java.util.function.Consumer;
 
 @ApiStatus.Internal
@@ -48,7 +47,7 @@ public class FilteringEntry extends AbstractConfigListEntry<List<EntryStack>> {
     Consumer<List<EntryStack>> saveConsumer;
     Consumer<List<FilteringRule<?>>> rulesSaveConsumer;
     List<EntryStack> defaultValue;
-    List<EntryStack> configFiltered;
+    Set<EntryStack> configFiltered;
     List<FilteringRule<?>> rules;
     boolean edited = false;
     final FilteringScreen filteringScreen = new FilteringScreen(this);
@@ -62,7 +61,8 @@ public class FilteringEntry extends AbstractConfigListEntry<List<EntryStack>> {
     public FilteringEntry(int width, List<EntryStack> configFiltered, List<FilteringRule<?>> rules, List<EntryStack> defaultValue, Consumer<List<EntryStack>> saveConsumer, Consumer<List<FilteringRule<?>>> rulesSaveConsumer) {
         super(NarratorManager.EMPTY, false);
         this.width = width;
-        this.configFiltered = configFiltered;
+        this.configFiltered = new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount));
+        this.configFiltered.addAll(configFiltered);
         this.rules = Lists.newArrayList(rules);
         this.defaultValue = defaultValue;
         this.saveConsumer = saveConsumer;
@@ -71,7 +71,7 @@ public class FilteringEntry extends AbstractConfigListEntry<List<EntryStack>> {
     
     @Override
     public List<EntryStack> getValue() {
-        return configFiltered;
+        return Lists.newArrayList(configFiltered);
     }
     
     @Override

+ 1 - 2
src/main/java/me/shedaniel/rei/gui/config/entry/FilteringScreen.java

@@ -42,7 +42,6 @@ import me.shedaniel.rei.gui.OverlaySearchField;
 import me.shedaniel.rei.gui.widget.EntryWidget;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.SearchArgument;
-import me.shedaniel.rei.utils.CollectionUtils;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.gui.screen.Screen;
@@ -495,7 +494,7 @@ public class FilteringScreen extends Screen {
         
         public boolean isFiltered() {
             if (dirty) {
-                filtered = CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(filteringEntry.configFiltered, getCurrentEntry()) != null;
+                filtered = filteringEntry.configFiltered.contains(getCurrentEntry());
                 dirty = false;
             }
             return filtered;

+ 5 - 8
src/main/java/me/shedaniel/rei/gui/modules/Menu.java

@@ -40,19 +40,18 @@ import me.shedaniel.rei.gui.modules.entries.EntryStackSubsetsMenuEntry;
 import me.shedaniel.rei.gui.modules.entries.SubSubsetsMenuEntry;
 import me.shedaniel.rei.gui.widget.LateRenderable;
 import me.shedaniel.rei.gui.widget.WidgetWithBounds;
-import me.shedaniel.rei.impl.EntryRegistryImpl;
 import me.shedaniel.rei.utils.CollectionUtils;
 import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemGroup;
 import net.minecraft.item.ItemStack;
-import net.minecraft.util.collection.DefaultedList;
 import net.minecraft.util.registry.Registry;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 @ApiStatus.Experimental
 @ApiStatus.Internal
@@ -86,7 +85,8 @@ public class Menu extends WidgetWithBounds implements LateRenderable {
     }
     
     public static Menu createSubsetsMenuFromRegistry(Point menuStartPoint) {
-        List<EntryStack> stacks = EntryRegistry.getInstance().getStacksList();
+        EntryRegistry instance = EntryRegistry.getInstance();
+        List<EntryStack> stacks = instance.getEntryStacks().collect(Collectors.toList());
         Map<String, Object> entries = Maps.newHashMap();
         {
             // All Entries group
@@ -102,12 +102,9 @@ public class Menu extends WidgetWithBounds implements LateRenderable {
                 ItemGroup group = item.getGroup();
                 if (group == null)
                     continue;
-                DefaultedList<ItemStack> list;
+                List<ItemStack> list;
                 try {
-                    list = new EntryRegistryImpl.DefaultedLinkedList<>(Lists.newLinkedList(), null);
-                    item.appendStacks(group, list);
-                    if (list.isEmpty())
-                        list.add(item.getStackForRender());
+                    list = instance.appendStacksForItem(item);
                     Map<String, Object> groupMenu = getOrCreateSubEntryInMap(itemGroups, "_item_group_" + group.getId());
                     for (ItemStack stack : list) {
                         putEntryInMap(groupMenu, EntryStack.create(stack));

+ 2 - 3
src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java

@@ -39,8 +39,7 @@ import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.sound.SoundEvents;
 import org.jetbrains.annotations.ApiStatus;
 
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 
 @ApiStatus.Experimental
 @ApiStatus.Internal
@@ -131,8 +130,8 @@ public class EntryStackSubsetsMenuEntry extends MenuEntry {
     }
     
     public boolean isFiltered() {
-        List<EntryStack> filteredStacks = ConfigObject.getInstance().getFilteredStacks();
         if (isFiltered == null) {
+            List<EntryStack> filteredStacks = ConfigObject.getInstance().getFilteredStacks();
             isFiltered = CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(filteredStacks, stack) != null;
         }
         return isFiltered;

+ 6 - 7
src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java

@@ -56,10 +56,7 @@ import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.*;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
@@ -494,7 +491,9 @@ public class EntryListWidget extends WidgetWithBounds {
             this.lastSearchArguments = SearchArgument.processSearchTerm(searchTerm);
             List<EntryStack> list = Lists.newArrayList();
             boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty();
-            List<EntryStack> workingItems = checkCraftable ? RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)) : null;
+            Set<EntryStack> workingItems = checkCraftable ? new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount)) : null;
+            if (checkCraftable)
+                workingItems.addAll(RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)));
             List<EntryStack> stacks = EntryRegistry.getInstance().getPreFilteredList();
             if (stacks instanceof CopyOnWriteArrayList && !stacks.isEmpty()) {
                 if (ConfigObject.getInstance().shouldAsyncSearch()) {
@@ -508,7 +507,7 @@ public class EntryListWidget extends WidgetWithBounds {
                             for (; start[0] < end; start[0]++) {
                                 EntryStack stack = stacks.get(start[0]);
                                 if (canLastSearchTermsBeAppliedTo(stack)) {
-                                    if (workingItems != null && CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(workingItems, stack) == null)
+                                    if (workingItems != null && workingItems.contains(stack))
                                         continue;
                                     filtered.add(stack.copy().setting(EntryStack.Settings.RENDER_COUNTS, EntryStack.Settings.FALSE).setting(EntryStack.Settings.Item.RENDER_ENCHANTMENT_GLINT, RENDER_ENCHANTMENT_GLINT));
                                 }
@@ -529,7 +528,7 @@ public class EntryListWidget extends WidgetWithBounds {
                 } else {
                     for (EntryStack stack : stacks) {
                         if (canLastSearchTermsBeAppliedTo(stack)) {
-                            if (workingItems != null && CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(workingItems, stack) == null)
+                            if (workingItems != null && workingItems.contains(stack))
                                 continue;
                             list.add(stack.copy().setting(EntryStack.Settings.RENDER_COUNTS, EntryStack.Settings.FALSE).setting(EntryStack.Settings.Item.RENDER_ENCHANTMENT_GLINT, RENDER_ENCHANTMENT_GLINT));
                         }

+ 9 - 6
src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java

@@ -47,8 +47,7 @@ import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 
 import static me.shedaniel.rei.gui.widget.EntryListWidget.*;
 
@@ -188,10 +187,12 @@ public class FavoritesListWidget extends WidgetWithBounds {
             if (ConfigObject.getInstance().doSearchFavorites()) {
                 List<EntryStack> list = Lists.newArrayList();
                 boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty();
-                List<EntryStack> workingItems = checkCraftable ? RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)) : null;
+                Set<EntryStack> workingItems = checkCraftable ? new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount)) : null;
+                if (checkCraftable)
+                    workingItems.addAll(RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)));
                 for (EntryStack stack : ConfigObject.getInstance().getFavorites()) {
                     if (listWidget.canLastSearchTermsBeAppliedTo(stack)) {
-                        if (checkCraftable && CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(workingItems, stack) == null)
+                        if (checkCraftable && workingItems.contains(stack))
                             continue;
                         list.add(stack.copy().setting(EntryStack.Settings.RENDER_COUNTS, EntryStack.Settings.FALSE).setting(EntryStack.Settings.Item.RENDER_ENCHANTMENT_GLINT, RENDER_ENCHANTMENT_GLINT));
                     }
@@ -207,9 +208,11 @@ public class FavoritesListWidget extends WidgetWithBounds {
             } else {
                 List<EntryStack> list = Lists.newArrayList();
                 boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty();
-                List<EntryStack> workingItems = checkCraftable ? RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)) : null;
+                Set<EntryStack> workingItems = checkCraftable ? new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount)) : null;
+                if (checkCraftable)
+                    workingItems.addAll(RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)));
                 for (EntryStack stack : ConfigObject.getInstance().getFavorites()) {
-                    if (checkCraftable && CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(workingItems, stack) == null)
+                    if (checkCraftable && workingItems.contains(stack))
                         continue;
                     list.add(stack.copy().setting(EntryStack.Settings.RENDER_COUNTS, EntryStack.Settings.FALSE).setting(EntryStack.Settings.Item.RENDER_ENCHANTMENT_GLINT, RENDER_ENCHANTMENT_GLINT));
                 }

+ 67 - 0
src/main/java/me/shedaniel/rei/impl/AmountIgnoredEntryStackWrapper.java

@@ -0,0 +1,67 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl;
+
+import me.shedaniel.rei.api.EntryStack;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.Objects;
+
+@ApiStatus.Internal
+@Environment(EnvType.CLIENT)
+public class AmountIgnoredEntryStackWrapper {
+    private final EntryStack stack;
+    private int hash = -1390123012;
+    
+    public AmountIgnoredEntryStackWrapper(EntryStack stack) {
+        this.stack = Objects.requireNonNull(stack);
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        
+        AmountIgnoredEntryStackWrapper that = (AmountIgnoredEntryStackWrapper) o;
+        return hashCode() == that.hashCode();
+    }
+    
+    @Override
+    public int hashCode() {
+        if (hash == -1390123012) {
+            hash = stack.hashIgnoreAmount();
+        }
+        return hash;
+    }
+    
+    public boolean isEmpty() {
+        return stack.isEmpty();
+    }
+    
+    public EntryStack unwrap() {
+        return stack;
+    }
+}

+ 42 - 112
src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java

@@ -24,26 +24,25 @@
 package me.shedaniel.rei.impl;
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.Queues;
 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.api.RecipeHelper;
 import me.shedaniel.rei.impl.filtering.FilteringContextImpl;
 import me.shedaniel.rei.impl.filtering.FilteringRule;
+import me.shedaniel.rei.utils.CollectionUtils;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
-import net.minecraft.util.Pair;
 import net.minecraft.util.collection.DefaultedList;
 import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @ApiStatus.Internal
 @Environment(EnvType.CLIENT)
@@ -51,9 +50,8 @@ public class EntryRegistryImpl implements EntryRegistry {
     
     private final List<EntryStack> preFilteredList = Lists.newCopyOnWriteArrayList();
     private final List<EntryStack> entries = Lists.newCopyOnWriteArrayList();
-    private final Queue<Pair<EntryStack, Collection<? extends EntryStack>>> queueRegisterEntryStackAfter = Queues.newConcurrentLinkedQueue();
-    private List<EntryStack> reloadList;
-    private boolean doingDistinct = false;
+    private final List<AmountIgnoredEntryStackWrapper> reloadingRegistry = Lists.newArrayList();
+    private boolean reloading;
     
     private static EntryStack findFirstOrNullEqualsEntryIgnoreAmount(Collection<EntryStack> list, EntryStack obj) {
         for (EntryStack t : list) {
@@ -63,100 +61,67 @@ public class EntryRegistryImpl implements EntryRegistry {
         return null;
     }
     
-    public void distinct() {
+    public void finishReload() {
+        reloading = false;
         preFilteredList.clear();
-        doingDistinct = true;
-        while (true) {
-            Pair<EntryStack, Collection<? extends EntryStack>> pair = queueRegisterEntryStackAfter.poll();
-            if (pair == null)
-                break;
-            registerEntriesAfter(pair.getLeft(), pair.getRight());
-        }
-        doingDistinct = false;
-        Set<EntryStackWrapper> set = Sets.newLinkedHashSet();
-        set.addAll(reloadList.stream().map(EntryStackWrapper::new).collect(Collectors.toList()));
-        set.removeIf(EntryStackWrapper::isEmpty);
+        reloadingRegistry.removeIf(AmountIgnoredEntryStackWrapper::isEmpty);
         entries.clear();
-        entries.addAll(set.stream().map(EntryStackWrapper::unwrap).collect(Collectors.toList()));
-    }
-    
-    private static class EntryStackWrapper {
-        private final EntryStack stack;
-        
-        public EntryStackWrapper(EntryStack stack) {
-            this.stack = Objects.requireNonNull(stack);
-        }
-        
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            
-            EntryStackWrapper that = (EntryStackWrapper) o;
-            return stack.equalsAll(that.stack);
-        }
-        
-        @Override
-        public int hashCode() {
-            return stack.hashCode();
-        }
-        
-        public boolean isEmpty() {
-            return stack.isEmpty();
-        }
-        
-        public EntryStack unwrap() {
-            return stack;
-        }
+        entries.addAll(CollectionUtils.map(reloadingRegistry, AmountIgnoredEntryStackWrapper::unwrap));
+        reloadingRegistry.clear();
     }
     
     @Override
-    public List<EntryStack> getStacksList() {
-        return RecipeHelper.getInstance().arePluginsLoading() || doingDistinct ? reloadList : entries;
+    @NotNull
+    public Stream<EntryStack> getEntryStacks() {
+        return entries.stream();
     }
     
     @Override
+    @NotNull
     public List<EntryStack> getPreFilteredList() {
         return preFilteredList;
     }
     
     public void refilter() {
         long started = System.currentTimeMillis();
-        FilteringContextImpl context = new FilteringContextImpl(getStacksList());
+        
+        FilteringContextImpl context = new FilteringContextImpl(entries);
         List<FilteringRule<?>> rules = ConfigObject.getInstance().getFilteringRules();
         for (int i = rules.size() - 1; i >= 0; i--) {
             context.handleResult(rules.get(i).processFilteredStacks(context));
         }
+        
+        Set<AmountIgnoredEntryStackWrapper> set = Sets.newLinkedHashSet();
+        set.addAll(CollectionUtils.map(entries, AmountIgnoredEntryStackWrapper::new));
+        Collection<EntryStack> hiddenStacks = context.getHiddenStacks();
+        set.removeAll(CollectionUtils.map(hiddenStacks, AmountIgnoredEntryStackWrapper::new));
         preFilteredList.clear();
-        Collection<EntryStack> filteredStacks = context.getHiddenStacks();
-        for (EntryStack stack : getStacksList()) {
-            if (findFirstOrNullEqualsEntryIgnoreAmount(filteredStacks, stack) == null)
-                preFilteredList.add(stack);
-        }
+        preFilteredList.addAll(CollectionUtils.map(set, AmountIgnoredEntryStackWrapper::unwrap));
+        
         long time = System.currentTimeMillis() - started;
-        RoughlyEnoughItemsCore.LOGGER.info("Refiltered %d entries with %d rules in %dms.", filteredStacks.size(), rules.size(), time);
+        RoughlyEnoughItemsCore.LOGGER.info("Refiltered %d entries with %d rules in %dms.", entries.size() - preFilteredList.size(), rules.size(), time);
     }
     
     public void reset() {
-        doingDistinct = false;
-        reloadList = Lists.newArrayList();
-        queueRegisterEntryStackAfter.clear();
         entries.clear();
-        reloadList.clear();
+        reloadingRegistry.clear();
         preFilteredList.clear();
+        reloading = true;
     }
     
+    @NotNull
     @Override
-    public List<ItemStack> appendStacksForItem(Item item) {
-        DefaultedList<ItemStack> list = new DefaultedLinkedList<>(Lists.newLinkedList(), null);
+    public List<ItemStack> appendStacksForItem(@NotNull Item item) {
+        DefaultedList<ItemStack> list = DefaultedList.of();
         item.appendStacks(item.getGroup(), list);
         if (list.isEmpty())
-            list.add(item.getStackForRender());
+            return Collections.singletonList(item.getStackForRender());
         return list;
     }
     
+    @NotNull
     @Override
-    public ItemStack[] getAllStacksFromItem(Item item) {
+    public ItemStack[] getAllStacksFromItem(@NotNull Item item) {
         List<ItemStack> list = appendStacksForItem(item);
         ItemStack[] array = list.toArray(new ItemStack[0]);
         Arrays.sort(array, (a, b) -> ItemStack.areEqualIgnoreDamage(a, b) ? 0 : 1);
@@ -164,52 +129,17 @@ public class EntryRegistryImpl implements EntryRegistry {
     }
     
     @Override
-    @Deprecated
-    @ApiStatus.Internal
-    public void registerEntryAfter(EntryStack afterEntry, EntryStack stack, boolean checkAlreadyContains) {
-        if (stack.isEmpty())
-            return;
-        if (afterEntry == null) {
-            getStacksList().add(stack);
-        } else {
-            int last = getStacksList().size();
-            for (int i = last - 1; i >= 0; i--)
-                if (getStacksList().get(i).equalsAll(afterEntry)) {
-                    last = i + 1;
-                    break;
-                }
-            getStacksList().add(last, stack);
-        }
-    }
-    
-    @Override
-    public void queueRegisterEntryAfter(EntryStack afterEntry, Collection<? extends EntryStack> stacks) {
-        if (RecipeHelper.getInstance().arePluginsLoading()) {
-            queueRegisterEntryStackAfter.add(new Pair<>(afterEntry, stacks));
+    public void registerEntriesAfter(@Nullable EntryStack afterStack, @NotNull Collection<@NotNull ? extends EntryStack> stacks) {
+        if (reloading) {
+            int index = afterStack != null ? reloadingRegistry.lastIndexOf(new AmountIgnoredEntryStackWrapper(afterStack)) : -1;
+            if (index >= 0) {
+                reloadingRegistry.addAll(index, CollectionUtils.map(stacks, AmountIgnoredEntryStackWrapper::new));
+            } else reloadingRegistry.addAll(CollectionUtils.map(stacks, AmountIgnoredEntryStackWrapper::new));
         } else {
-            registerEntriesAfter(afterEntry, stacks);
-        }
-    }
-    
-    @Override
-    public void registerEntriesAfter(EntryStack afterStack, Collection<? extends EntryStack> stacks) {
-        if (afterStack != null) {
-            int index = getStacksList().size();
-            for (int i = index - 1; i >= 0; i--) {
-                if (getStacksList().get(i).equalsIgnoreAmount(afterStack)) {
-                    index = i + 1;
-                    break;
-                }
-            }
-            getStacksList().addAll(index, stacks);
-        } else
-            getStacksList().addAll(stacks);
-    }
-    
-    @ApiStatus.Internal
-    public static class DefaultedLinkedList<E> extends DefaultedList<E> {
-        public DefaultedLinkedList(List<E> delegate, @Nullable E initialElement) {
-            super(delegate, initialElement);
+            if (afterStack != null) {
+                int index = entries.lastIndexOf(afterStack);
+                entries.addAll(index, stacks);
+            } else entries.addAll(stacks);
         }
     }
 }

+ 2 - 2
src/main/java/me/shedaniel/rei/impl/FluidSupportProviderImpl.java

@@ -35,7 +35,7 @@ import java.util.Objects;
 @ApiStatus.Experimental
 @ApiStatus.Internal
 public class FluidSupportProviderImpl implements FluidSupportProvider {
-    private final List<FluidProvider> providers = Lists.newArrayList();
+    private final List<FluidProvider> providers = Lists.newCopyOnWriteArrayList();
     
     public void reset() {
         providers.clear();
@@ -52,7 +52,7 @@ public class FluidSupportProviderImpl implements FluidSupportProvider {
         if (itemStack.getType() != EntryStack.Type.ITEM)
             throw new IllegalArgumentException("EntryStack must be item!");
         for (FluidProvider provider : providers) {
-            EntryStack stack = Objects.requireNonNull(provider.itemToFluid(itemStack), provider.getClass() + " is creating null objects for itemToFluid!");
+            EntryStack stack = Objects.requireNonNull(provider.itemToFluid(itemStack));
             if (!stack.isEmpty()) return stack;
         }
         return EntryStack.empty();

+ 3 - 3
src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java

@@ -446,10 +446,10 @@ public class RecipeHelperImpl implements RecipeHelper {
         ((DisplayHelperImpl) DisplayHelper.getInstance()).resetCache();
         ScreenHelper.getOptionalOverlay().ifPresent(overlay -> overlay.shouldReInit = true);
         
-        startSection(sectionData, "entry-registry-distinct");
+        startSection(sectionData, "entry-registry-finalise");
         
-        // Remove duplicate entries
-        ((EntryRegistryImpl) EntryRegistry.getInstance()).distinct();
+        // Finish Reload
+        ((EntryRegistryImpl) EntryRegistry.getInstance()).finishReload();
         
         endSection(sectionData);
         startSection(sectionData, "entry-registry-refilter");

+ 5 - 9
src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java

@@ -26,27 +26,23 @@ package me.shedaniel.rei.impl.filtering;
 import me.shedaniel.rei.api.EntryStack;
 import org.jetbrains.annotations.ApiStatus;
 
-import java.util.Map;
+import java.util.Collection;
 import java.util.Set;
 
 @ApiStatus.Internal
 @ApiStatus.Experimental
 public interface FilteringContext {
-    Map<FilteringContextType, Set<EntryStack>> getStacks();
+    Collection<EntryStack> getStacks(FilteringContextType type);
     
-    default Set<EntryStack> getStacks(FilteringContextType type) {
-        return getStacks().get(type);
-    }
-    
-    default Set<EntryStack> getShownStacks() {
+    default Collection<EntryStack> getShownStacks() {
         return getStacks(FilteringContextType.SHOWN);
     }
     
-    default Set<EntryStack> getUnsetStacks() {
+    default Collection<EntryStack> getUnsetStacks() {
         return getStacks(FilteringContextType.DEFAULT);
     }
     
-    default Set<EntryStack> getHiddenStacks() {
+    default Collection<EntryStack> getHiddenStacks() {
         return getStacks(FilteringContextType.HIDDEN);
     }
 }

+ 48 - 12
src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java

@@ -23,41 +23,77 @@
 
 package me.shedaniel.rei.impl.filtering;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import me.shedaniel.rei.api.EntryStack;
+import me.shedaniel.rei.impl.AmountIgnoredEntryStackWrapper;
+import me.shedaniel.rei.utils.CollectionUtils;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 @Environment(EnvType.CLIENT)
 public class FilteringContextImpl implements FilteringContext {
-    private final Map<FilteringContextType, Set<EntryStack>> stacks;
+    private final Map<FilteringContextType, Set<AmountIgnoredEntryStackWrapper>> stacks;
+    private final Map<FilteringContextType, Collection<EntryStack>> cachedStacks;
     
     public FilteringContextImpl(List<EntryStack> allStacks) {
         this(Maps.newHashMap());
         getUnsetStacks().addAll(allStacks);
     }
     
-    public FilteringContextImpl(Map<FilteringContextType, Set<EntryStack>> stacks) {
+    public FilteringContextImpl(Map<FilteringContextType, Set<AmountIgnoredEntryStackWrapper>> stacks) {
         this.stacks = stacks;
+        this.cachedStacks = Maps.newHashMap();
         for (FilteringContextType type : FilteringContextType.values()) {
-            this.stacks.computeIfAbsent(type, t -> new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount)));
+            this.stacks.computeIfAbsent(type, t -> Sets.newHashSet());
+        }
+        fillCache();
+    }
+    
+    private void fillCache() {
+        this.cachedStacks.clear();
+        for (FilteringContextType type : FilteringContextType.values()) {
+            this.cachedStacks.put(type, CollectionUtils.map(stacks.get(type), AmountIgnoredEntryStackWrapper::unwrap));
         }
     }
     
     @Override
-    public Map<FilteringContextType, Set<EntryStack>> getStacks() {
-        return stacks;
+    public Collection<EntryStack> getStacks(FilteringContextType type) {
+        return cachedStacks.get(type);
     }
     
     public void handleResult(FilteringResult result) {
-        getUnsetStacks().removeAll(result.getHiddenStacks());
-        getShownStacks().removeAll(result.getHiddenStacks());
-        getHiddenStacks().addAll(result.getHiddenStacks());
+        Collection<AmountIgnoredEntryStackWrapper> hiddenStacks = CollectionUtils.map(result.getHiddenStacks(), AmountIgnoredEntryStackWrapper::new);
+        Collection<AmountIgnoredEntryStackWrapper> shownStacks = CollectionUtils.map(result.getShownStacks(), AmountIgnoredEntryStackWrapper::new);
         
-        getHiddenStacks().removeAll(result.getShownStacks());
-        getUnsetStacks().removeAll(result.getShownStacks());
-        getShownStacks().addAll(result.getShownStacks());
+        List<CompletableFuture<Void>> completableFutures = Lists.newArrayList();
+        completableFutures.add(CompletableFuture.runAsync(() -> {
+            this.stacks.get(FilteringContextType.DEFAULT).removeAll(hiddenStacks);
+            this.stacks.get(FilteringContextType.DEFAULT).removeAll(shownStacks);
+        }));
+        completableFutures.add(CompletableFuture.runAsync(() -> {
+            this.stacks.get(FilteringContextType.SHOWN).removeAll(hiddenStacks);
+            this.stacks.get(FilteringContextType.SHOWN).addAll(shownStacks);
+        }));
+        completableFutures.add(CompletableFuture.runAsync(() -> {
+            this.stacks.get(FilteringContextType.HIDDEN).addAll(hiddenStacks);
+            this.stacks.get(FilteringContextType.HIDDEN).removeAll(shownStacks);
+        }));
+        try {
+            CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).get(20, TimeUnit.SECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            e.printStackTrace();
+        }
+        fillCache();
     }
 }

+ 5 - 11
src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java

@@ -24,11 +24,13 @@
 package me.shedaniel.rei.impl.filtering.rules;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.impl.filtering.AbstractFilteringRule;
 import me.shedaniel.rei.impl.filtering.FilteringContext;
 import me.shedaniel.rei.impl.filtering.FilteringResult;
+import me.shedaniel.rei.utils.CollectionUtils;
 import net.minecraft.nbt.CompoundTag;
 import net.minecraft.text.Text;
 import net.minecraft.text.TranslatableText;
@@ -57,24 +59,16 @@ public class ManualFilteringRule extends AbstractFilteringRule<ManualFilteringRu
         return result;
     }
     
-    private void processList(Set<EntryStack> stacks, FilteringResult result) {
-        List<EntryStack> filteredStacks = ConfigObject.getInstance().getFilteredStacks();
+    private void processList(Collection<EntryStack> stacks, FilteringResult result) {
+        Set<Integer> filteredStacks = Sets.newHashSet(CollectionUtils.map(ConfigObject.getInstance().getFilteredStacks(), EntryStack::hashIgnoreAmount));
         List<EntryStack> filtered = Lists.newArrayList();
         for (EntryStack stack : stacks) {
-            if (findFirstOrNullEqualsEntryIgnoreAmount(filteredStacks, stack) != null)
+            if (filteredStacks.contains(stack.hashIgnoreAmount()))
                 filtered.add(stack);
         }
         result.hide(filtered);
     }
     
-    private static EntryStack findFirstOrNullEqualsEntryIgnoreAmount(Collection<EntryStack> list, EntryStack obj) {
-        for (EntryStack t : list) {
-            if (t.equalsIgnoreAmount(obj))
-                return t;
-        }
-        return null;
-    }
-    
     @Override
     public Text getTitle() {
         return new TranslatableText("rule.roughlyenoughitems.filtering.manual");

+ 5 - 6
src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java

@@ -108,17 +108,16 @@ public class SearchFilteringRule extends AbstractFilteringRule<SearchFilteringRu
         return new SearchFilteringRule("", Collections.singletonList(SearchArgument.SearchArguments.ALWAYS), true);
     }
     
-    private void processList(Set<EntryStack> stacks, List<CompletableFuture<List<EntryStack>>> completableFutures) {
+    private void processList(Collection<EntryStack> stacks, List<CompletableFuture<List<EntryStack>>> completableFutures) {
         int size = 100;
-        List<EntryStack> stacks1 = Lists.newArrayList(stacks);
-        Iterator<EntryStack> iterator = stacks1.iterator();
-        for (int i = 0; i < stacks1.size(); i += size) {
+        Iterator<EntryStack> iterator = stacks.iterator();
+        for (int i = 0; i < stacks.size(); i += size) {
             int[] start = {i};
             completableFutures.add(CompletableFuture.supplyAsync(() -> {
-                int end = Math.min(stacks1.size(), start[0] + size);
+                int end = Math.min(stacks.size(), start[0] + size);
                 List<EntryStack> output = Lists.newArrayList();
                 for (; start[0] < end; start[0]++) {
-                    EntryStack stack = stacks1.get(start[0]);
+                    EntryStack stack = ((List<EntryStack>) stacks).get(start[0]);
                     boolean shown = SearchArgument.canSearchTermsBeAppliedTo(stack, arguments);
                     if (shown) {
                         output.add(stack);

+ 7 - 4
src/main/java/me/shedaniel/rei/tests/plugin/REITestPlugin.java

@@ -26,17 +26,20 @@ package me.shedaniel.rei.tests.plugin;
 import me.shedaniel.rei.api.EntryRegistry;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.api.plugins.REIPluginV0;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.CompoundTag;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.registry.Registry;
 import org.apache.logging.log4j.LogManager;
 import org.jetbrains.annotations.TestOnly;
 
-import java.util.Collections;
 import java.util.Random;
 
 @TestOnly
+@Environment(EnvType.CLIENT)
 public class REITestPlugin implements REIPluginV0 {
     
     private Random random = new Random();
@@ -56,7 +59,7 @@ public class REITestPlugin implements REIPluginV0 {
         int times = 10;
         for (Item item : Registry.ITEM) {
             for (int i = 0; i < times; i++)
-                entryRegistry.queueRegisterEntryAfter(EntryStack.create(item), Collections.singleton(transformStack(EntryStack.create(item))));
+                entryRegistry.registerEntryAfter(EntryStack.create(item), transformStack(EntryStack.create(item)));
             try {
                 for (ItemStack stack : entryRegistry.appendStacksForItem(item)) {
                     for (int i = 0; i < times; i++)
@@ -68,8 +71,8 @@ public class REITestPlugin implements REIPluginV0 {
     }
     
     public EntryStack transformStack(EntryStack stack) {
-        stack.setAmount(random.nextInt(Byte.MAX_VALUE));
-        stack.setting(EntryStack.Settings.CHECK_AMOUNT, EntryStack.Settings.TRUE);
+        CompoundTag tag = stack.getItemStack().getOrCreateTag();
+        tag.putInt("Whatever", random.nextInt(Integer.MAX_VALUE));
         return stack;
     }
     

+ 14 - 0
src/main/java/me/shedaniel/rei/utils/CollectionUtils.java

@@ -26,6 +26,8 @@ package me.shedaniel.rei.utils;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import me.shedaniel.rei.api.EntryStack;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 
 import java.util.*;
 import java.util.function.Function;
@@ -73,6 +75,7 @@ public class CollectionUtils {
         return false;
     }
     
+    @Environment(EnvType.CLIENT)
     public static boolean anyMatchEqualsAll(List<EntryStack> list, EntryStack stack) {
         for (EntryStack t : list) {
             if (t.equalsAll(stack))
@@ -81,6 +84,7 @@ public class CollectionUtils {
         return false;
     }
     
+    @Environment(EnvType.CLIENT)
     public static boolean anyMatchEqualsEntryIgnoreAmount(List<EntryStack> list, EntryStack stack) {
         for (EntryStack t : list) {
             if (t.equalsIgnoreAmount(stack))
@@ -89,6 +93,7 @@ public class CollectionUtils {
         return false;
     }
     
+    @Environment(EnvType.CLIENT)
     public static EntryStack firstOrNullEqualsAll(List<EntryStack> list, EntryStack stack) {
         for (EntryStack t : list) {
             if (t.equalsAll(stack))
@@ -97,6 +102,7 @@ public class CollectionUtils {
         return null;
     }
     
+    @Environment(EnvType.CLIENT)
     public static EntryStack findFirstOrNullEqualsEntryIgnoreAmount(Collection<EntryStack> list, EntryStack stack) {
         for (EntryStack t : list) {
             if (t.equalsIgnoreAmount(stack))
@@ -143,6 +149,14 @@ public class CollectionUtils {
         return l;
     }
     
+    public static <T, R> List<R> map(Collection<T> list, Function<T, R> function) {
+        List<R> l = Lists.newArrayList();
+        for (T t : list) {
+            l.add(function.apply(t));
+        }
+        return l;
+    }
+    
     public static <T, R> List<R> map(T[] list, Function<T, R> function) {
         List<R> l = Lists.newArrayList();
         for (T t : list) {