From f2d6d8525aa74329c6491f57afad6570aec25791 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Mon, 13 Jul 2020 22:08:26 +0800 Subject: Performance Improvements Signed-off-by: shedaniel --- .../me/shedaniel/rei/RoughlyEnoughItemsCore.java | 8 +- .../java/me/shedaniel/rei/api/ConfigManager.java | 2 + .../java/me/shedaniel/rei/api/DisplayHelper.java | 2 + .../java/me/shedaniel/rei/api/EntryRegistry.java | 48 +++++-- .../java/me/shedaniel/rei/api/RecipeHelper.java | 2 + .../shedaniel/rei/gui/ConfigReloadingScreen.java | 5 - .../rei/gui/config/entry/FilteringEntry.java | 10 +- .../rei/gui/config/entry/FilteringScreen.java | 3 +- .../java/me/shedaniel/rei/gui/modules/Menu.java | 13 +- .../entries/EntryStackSubsetsMenuEntry.java | 5 +- .../shedaniel/rei/gui/widget/EntryListWidget.java | 13 +- .../rei/gui/widget/FavoritesListWidget.java | 15 +- .../rei/impl/AmountIgnoredEntryStackWrapper.java | 67 +++++++++ .../me/shedaniel/rei/impl/EntryRegistryImpl.java | 154 ++++++--------------- .../rei/impl/FluidSupportProviderImpl.java | 4 +- .../me/shedaniel/rei/impl/RecipeHelperImpl.java | 6 +- .../rei/impl/filtering/FilteringContext.java | 14 +- .../rei/impl/filtering/FilteringContextImpl.java | 60 ++++++-- .../impl/filtering/rules/ManualFilteringRule.java | 16 +-- .../impl/filtering/rules/SearchFilteringRule.java | 11 +- .../shedaniel/rei/tests/plugin/REITestPlugin.java | 11 +- .../me/shedaniel/rei/utils/CollectionUtils.java | 14 ++ 22 files changed, 272 insertions(+), 211 deletions(-) create mode 100644 src/main/java/me/shedaniel/rei/impl/AmountIgnoredEntryStackWrapper.java (limited to 'src/main/java/me') diff --git a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index 1ac85319f..950b6f331 100644 --- a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/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(); } diff --git a/src/main/java/me/shedaniel/rei/api/ConfigManager.java b/src/main/java/me/shedaniel/rei/api/ConfigManager.java index f85d528e5..358ef22af 100644 --- a/src/main/java/me/shedaniel/rei/api/ConfigManager.java +++ b/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(); } diff --git a/src/main/java/me/shedaniel/rei/api/DisplayHelper.java b/src/main/java/me/shedaniel/rei/api/DisplayHelper.java index fbf753a98..fe5c77950 100644 --- a/src/main/java/me/shedaniel/rei/api/DisplayHelper.java +++ b/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(); } diff --git a/src/main/java/me/shedaniel/rei/api/EntryRegistry.java b/src/main/java/me/shedaniel/rei/api/EntryRegistry.java index 56c9aac19..723f468bf 100644 --- a/src/main/java/me/shedaniel/rei/api/EntryRegistry.java +++ b/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 getStacksList(); + @Deprecated + @ApiStatus.ScheduledForRemoval + @NotNull + default List getStacksList() { + return getEntryStacks().collect(Collectors.toList()); + } + @NotNull + Stream getEntryStacks(); + + @NotNull List getPreFilteredList(); - List appendStacksForItem(Item item); + @NotNull + List 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 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 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); } diff --git a/src/main/java/me/shedaniel/rei/api/RecipeHelper.java b/src/main/java/me/shedaniel/rei/api/RecipeHelper.java index fc6724634..26f17e81f 100644 --- a/src/main/java/me/shedaniel/rei/api/RecipeHelper.java +++ b/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(); } diff --git a/src/main/java/me/shedaniel/rei/gui/ConfigReloadingScreen.java b/src/main/java/me/shedaniel/rei/gui/ConfigReloadingScreen.java index b9e557d21..12d1fa039 100644 --- a/src/main/java/me/shedaniel/rei/gui/ConfigReloadingScreen.java +++ b/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; - } } diff --git a/src/main/java/me/shedaniel/rei/gui/config/entry/FilteringEntry.java b/src/main/java/me/shedaniel/rei/gui/config/entry/FilteringEntry.java index 1109e6b19..f55269f0b 100644 --- a/src/main/java/me/shedaniel/rei/gui/config/entry/FilteringEntry.java +++ b/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> { Consumer> saveConsumer; Consumer>> rulesSaveConsumer; List defaultValue; - List configFiltered; + Set configFiltered; List> rules; boolean edited = false; final FilteringScreen filteringScreen = new FilteringScreen(this); @@ -62,7 +61,8 @@ public class FilteringEntry extends AbstractConfigListEntry> { public FilteringEntry(int width, List configFiltered, List> rules, List defaultValue, Consumer> saveConsumer, Consumer>> 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> { @Override public List getValue() { - return configFiltered; + return Lists.newArrayList(configFiltered); } @Override diff --git a/src/main/java/me/shedaniel/rei/gui/config/entry/FilteringScreen.java b/src/main/java/me/shedaniel/rei/gui/config/entry/FilteringScreen.java index 2b9c84985..cbc70982b 100644 --- a/src/main/java/me/shedaniel/rei/gui/config/entry/FilteringScreen.java +++ b/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; diff --git a/src/main/java/me/shedaniel/rei/gui/modules/Menu.java b/src/main/java/me/shedaniel/rei/gui/modules/Menu.java index 16bc8e218..b33c2c3ea 100644 --- a/src/main/java/me/shedaniel/rei/gui/modules/Menu.java +++ b/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 stacks = EntryRegistry.getInstance().getStacksList(); + EntryRegistry instance = EntryRegistry.getInstance(); + List stacks = instance.getEntryStacks().collect(Collectors.toList()); Map 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 list; + List 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 groupMenu = getOrCreateSubEntryInMap(itemGroups, "_item_group_" + group.getId()); for (ItemStack stack : list) { putEntryInMap(groupMenu, EntryStack.create(stack)); diff --git a/src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java b/src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java index 4586ebc91..9b20b376d 100644 --- a/src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java +++ b/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 filteredStacks = ConfigObject.getInstance().getFilteredStacks(); if (isFiltered == null) { + List filteredStacks = ConfigObject.getInstance().getFilteredStacks(); isFiltered = CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(filteredStacks, stack) != null; } return isFiltered; diff --git a/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java b/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java index b079c0eb1..481c24adb 100644 --- a/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java +++ b/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 list = Lists.newArrayList(); boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty(); - List workingItems = checkCraftable ? RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)) : null; + Set workingItems = checkCraftable ? new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount)) : null; + if (checkCraftable) + workingItems.addAll(RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create))); List 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)); } diff --git a/src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java b/src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java index d3b66c117..16b5bb917 100644 --- a/src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java +++ b/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 list = Lists.newArrayList(); boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty(); - List workingItems = checkCraftable ? RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)) : null; + Set 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 list = Lists.newArrayList(); boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled() && !ScreenHelper.inventoryStacks.isEmpty(); - List workingItems = checkCraftable ? RecipeHelper.getInstance().findCraftableEntriesByItems(CollectionUtils.map(ScreenHelper.inventoryStacks, EntryStack::create)) : null; + Set 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)); } diff --git a/src/main/java/me/shedaniel/rei/impl/AmountIgnoredEntryStackWrapper.java b/src/main/java/me/shedaniel/rei/impl/AmountIgnoredEntryStackWrapper.java new file mode 100644 index 000000000..42526da97 --- /dev/null +++ b/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; + } +} \ No newline at end of file diff --git a/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java b/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java index b3274ae94..a4fccb16a 100644 --- a/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java +++ b/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 preFilteredList = Lists.newCopyOnWriteArrayList(); private final List entries = Lists.newCopyOnWriteArrayList(); - private final Queue>> queueRegisterEntryStackAfter = Queues.newConcurrentLinkedQueue(); - private List reloadList; - private boolean doingDistinct = false; + private final List reloadingRegistry = Lists.newArrayList(); + private boolean reloading; private static EntryStack findFirstOrNullEqualsEntryIgnoreAmount(Collection 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> pair = queueRegisterEntryStackAfter.poll(); - if (pair == null) - break; - registerEntriesAfter(pair.getLeft(), pair.getRight()); - } - doingDistinct = false; - Set 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 getStacksList() { - return RecipeHelper.getInstance().arePluginsLoading() || doingDistinct ? reloadList : entries; + @NotNull + public Stream getEntryStacks() { + return entries.stream(); } @Override + @NotNull public List getPreFilteredList() { return preFilteredList; } public void refilter() { long started = System.currentTimeMillis(); - FilteringContextImpl context = new FilteringContextImpl(getStacksList()); + + FilteringContextImpl context = new FilteringContextImpl(entries); List> rules = ConfigObject.getInstance().getFilteringRules(); for (int i = rules.size() - 1; i >= 0; i--) { context.handleResult(rules.get(i).processFilteredStacks(context)); } + + Set set = Sets.newLinkedHashSet(); + set.addAll(CollectionUtils.map(entries, AmountIgnoredEntryStackWrapper::new)); + Collection hiddenStacks = context.getHiddenStacks(); + set.removeAll(CollectionUtils.map(hiddenStacks, AmountIgnoredEntryStackWrapper::new)); preFilteredList.clear(); - Collection 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 appendStacksForItem(Item item) { - DefaultedList list = new DefaultedLinkedList<>(Lists.newLinkedList(), null); + public List appendStacksForItem(@NotNull Item item) { + DefaultedList 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 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 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 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 extends DefaultedList { - public DefaultedLinkedList(List delegate, @Nullable E initialElement) { - super(delegate, initialElement); + if (afterStack != null) { + int index = entries.lastIndexOf(afterStack); + entries.addAll(index, stacks); + } else entries.addAll(stacks); } } } diff --git a/src/main/java/me/shedaniel/rei/impl/FluidSupportProviderImpl.java b/src/main/java/me/shedaniel/rei/impl/FluidSupportProviderImpl.java index d14ac271b..a26ee663f 100644 --- a/src/main/java/me/shedaniel/rei/impl/FluidSupportProviderImpl.java +++ b/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 providers = Lists.newArrayList(); + private final List 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(); diff --git a/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java b/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java index bcdea853d..60f01a738 100644 --- a/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java +++ b/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"); diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java index f6066597b..335af1d33 100644 --- a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java +++ b/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> getStacks(); + Collection getStacks(FilteringContextType type); - default Set getStacks(FilteringContextType type) { - return getStacks().get(type); - } - - default Set getShownStacks() { + default Collection getShownStacks() { return getStacks(FilteringContextType.SHOWN); } - default Set getUnsetStacks() { + default Collection getUnsetStacks() { return getStacks(FilteringContextType.DEFAULT); } - default Set getHiddenStacks() { + default Collection getHiddenStacks() { return getStacks(FilteringContextType.HIDDEN); } } diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java index 830593d62..ef13b2c55 100644 --- a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java +++ b/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> stacks; + private final Map> stacks; + private final Map> cachedStacks; public FilteringContextImpl(List allStacks) { this(Maps.newHashMap()); getUnsetStacks().addAll(allStacks); } - public FilteringContextImpl(Map> stacks) { + public FilteringContextImpl(Map> 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> getStacks() { - return stacks; + public Collection 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 hiddenStacks = CollectionUtils.map(result.getHiddenStacks(), AmountIgnoredEntryStackWrapper::new); + Collection shownStacks = CollectionUtils.map(result.getShownStacks(), AmountIgnoredEntryStackWrapper::new); - getHiddenStacks().removeAll(result.getShownStacks()); - getUnsetStacks().removeAll(result.getShownStacks()); - getShownStacks().addAll(result.getShownStacks()); + List> 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(); } } diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java b/src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java index a3b176168..a5143d395 100644 --- a/src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java +++ b/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 stacks, FilteringResult result) { - List filteredStacks = ConfigObject.getInstance().getFilteredStacks(); + private void processList(Collection stacks, FilteringResult result) { + Set filteredStacks = Sets.newHashSet(CollectionUtils.map(ConfigObject.getInstance().getFilteredStacks(), EntryStack::hashIgnoreAmount)); List 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 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"); diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java b/src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java index e50137858..432985ce8 100644 --- a/src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java +++ b/src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java @@ -108,17 +108,16 @@ public class SearchFilteringRule extends AbstractFilteringRule stacks, List>> completableFutures) { + private void processList(Collection stacks, List>> completableFutures) { int size = 100; - List stacks1 = Lists.newArrayList(stacks); - Iterator iterator = stacks1.iterator(); - for (int i = 0; i < stacks1.size(); i += size) { + Iterator 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 output = Lists.newArrayList(); for (; start[0] < end; start[0]++) { - EntryStack stack = stacks1.get(start[0]); + EntryStack stack = ((List) stacks).get(start[0]); boolean shown = SearchArgument.canSearchTermsBeAppliedTo(stack, arguments); if (shown) { output.add(stack); diff --git a/src/main/java/me/shedaniel/rei/tests/plugin/REITestPlugin.java b/src/main/java/me/shedaniel/rei/tests/plugin/REITestPlugin.java index a7b061bd6..de3e66da4 100644 --- a/src/main/java/me/shedaniel/rei/tests/plugin/REITestPlugin.java +++ b/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; } diff --git a/src/main/java/me/shedaniel/rei/utils/CollectionUtils.java b/src/main/java/me/shedaniel/rei/utils/CollectionUtils.java index 333bdda2e..bf2e75949 100644 --- a/src/main/java/me/shedaniel/rei/utils/CollectionUtils.java +++ b/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 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 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 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 list, EntryStack stack) { for (EntryStack t : list) { if (t.equalsIgnoreAmount(stack)) @@ -143,6 +149,14 @@ public class CollectionUtils { return l; } + public static List map(Collection list, Function function) { + List l = Lists.newArrayList(); + for (T t : list) { + l.add(function.apply(t)); + } + return l; + } + public static List map(T[] list, Function function) { List l = Lists.newArrayList(); for (T t : list) { -- cgit