diff options
14 files changed, 300 insertions, 112 deletions
diff --git a/forge/build.gradle b/forge/build.gradle index 962677d6e..584222009 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -49,12 +49,6 @@ processServerComponentResources { } loom { - launches { - all { - arg "--mixin", "rei-jei-internals-workaround.mixins.json" - } - } - forge { mixinConfig "rei.mixins.json" } @@ -70,6 +64,7 @@ dependencies { shadowCommon(project(path: it, configuration: "transformProductionForge")) { transitive false } } + modRuntime("curse.maven:lazy-dfu-forge-460819:3544496") // modRuntime("curse.maven:chiselsbits-231095:3492889") // modRuntime("curse.maven:jumbofurnace-390880:3120970") // modRuntime("curse.maven:cyclic-239286:3221427") diff --git a/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java index 7eed62ba2..6ed68874e 100644 --- a/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java +++ b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java @@ -27,9 +27,11 @@ import com.google.common.collect.ImmutableList; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry; +import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import me.shedaniel.rei.api.common.plugins.PluginManager; import me.shedaniel.rei.api.common.registry.ReloadStage; import me.shedaniel.rei.api.common.util.EntryStacks; @@ -39,6 +41,7 @@ import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.TextComponent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -61,7 +64,7 @@ public class REITestPlugin implements REIClientPlugin { @Override public void registerEntries(EntryRegistry registry) { - int times = 100; + int times = 10; for (Item item : Registry.ITEM) { EntryStack<ItemStack> base = EntryStacks.of(item); registry.addEntriesAfter(base, IntStream.range(0, times).mapToObj(value -> transformStack(EntryStacks.of(item))).collect(Collectors.toList())); @@ -75,6 +78,17 @@ public class REITestPlugin implements REIClientPlugin { } @Override + public void registerCollapsibleEntries(CollapsibleEntryRegistry registry) { + int i = 0; + for (Item item : Registry.ITEM) { + if (i++ % 10 != 0) + continue; + registry.group(Registry.ITEM.getKey(item), new TextComponent(Registry.ITEM.getKey(item).toString()), + stack -> stack.getType() == VanillaEntryTypes.ITEM && stack.<ItemStack>castValue().is(item)); + } + } + + @Override public void registerItemComparators(ItemComparatorRegistry registry) { registry.registerNbt(Registry.ITEM.stream().toArray(Item[]::new)); } diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java index 266dfd47d..6b59b2418 100644 --- a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java @@ -192,7 +192,11 @@ public class EntryRegistryImpl implements EntryRegistry { if (afterEntry != null) { int index = registryList.lastIndexOf(afterEntry); - registryList.addAll(index, filtered, hashes); + if (index != -1) { + registryList.addAll(index, filtered, hashes); + } else { + registryList.addAll(filtered, hashes); + } } else registryList.addAll(filtered, hashes); for (EntryRegistryListener listener : listeners) { diff --git a/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java index a1a8b7558..1d51eb0f2 100644 --- a/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java @@ -34,19 +34,18 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.registry.ReloadStage; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.client.util.ThreadCreator; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import java.util.stream.Collectors; public enum BasicFilteringRuleImpl implements BasicFilteringRule<Pair<LongSet, LongSet>> { INSTANCE; + private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-BasicFiltering").asService(); private final List<EntryStack<?>> hidden = new ArrayList<>(), shown = new ArrayList<>(); @Override @@ -73,7 +72,7 @@ public enum BasicFilteringRuleImpl implements BasicFilteringRule<Pair<LongSet, L } } return output; - })); + }, EXECUTOR_SERVICE)); } try { CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).get(5, TimeUnit.MINUTES); diff --git a/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java index dcc1c9500..b7e06da86 100644 --- a/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java @@ -32,16 +32,16 @@ import me.shedaniel.rei.api.client.entry.filtering.*; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.client.util.ThreadCreator; import java.util.Collection; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import java.util.stream.Collectors; public class ManualFilteringRule implements FilteringRule<LongSet> { + private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-ManualFiltering").asService(); + @Override public FilteringRuleType<? extends FilteringRule<LongSet>> getType() { return ManualFilteringRuleType.INSTANCE; @@ -61,7 +61,7 @@ public class ManualFilteringRule implements FilteringRule<LongSet> { } } return output; - })); + }, EXECUTOR_SERVICE)); } try { CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).get(5, TimeUnit.MINUTES); diff --git a/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java index 9ab987936..035f0f868 100644 --- a/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java @@ -30,6 +30,7 @@ import me.shedaniel.rei.api.client.entry.filtering.*; import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.impl.client.util.ThreadCreator; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.util.StringUtil; @@ -37,13 +38,11 @@ import net.minecraft.util.Unit; import java.util.Collection; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import java.util.function.Supplier; public class SearchFilteringRule implements FilteringRule<Unit> { + private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-SearchFiltering").asService(); String filterStr; Supplier<SearchFilter> filter; boolean show; @@ -101,7 +100,7 @@ public class SearchFilteringRule implements FilteringRule<Unit> { } } return output; - })); + }, EXECUTOR_SERVICE)); } } } diff --git a/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java index dfbf67866..875ce19c3 100644 --- a/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java +++ b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java @@ -32,6 +32,7 @@ import me.shedaniel.rei.api.common.transfer.info.MenuInfo; import me.shedaniel.rei.api.common.transfer.info.MenuInfoProvider; import me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry; import me.shedaniel.rei.api.common.transfer.info.MenuSerializationContext; +import me.shedaniel.rei.impl.common.InternalLogger; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.nbt.CompoundTag; @@ -53,11 +54,28 @@ public class MenuInfoRegistryImpl implements MenuInfoRegistry { map.computeIfAbsent(category, id -> Maps.newLinkedHashMap()) .computeIfAbsent(menuClass, c -> Lists.newArrayList()) .add(menuInfo); + InternalLogger.getInstance().debug("Added menu info for %s [%s]: %s", menuClass, category, menuInfo); } @Override public <D extends Display> void registerGeneric(Predicate<CategoryIdentifier<?>> categoryPredicate, MenuInfoProvider<?, D> menuInfo) { - mapGeneric.computeIfAbsent(categoryPredicate, id -> Lists.newArrayList()).add(menuInfo); + mapGeneric.computeIfAbsent(new Predicate<>() { + @Override + public boolean test(CategoryIdentifier<?> categoryIdentifier) { + return categoryPredicate.test(categoryIdentifier); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + }, id -> Lists.newArrayList()).add(menuInfo); + InternalLogger.getInstance().debug("Added generic menu info for: %s", menuInfo); } @Override @@ -122,6 +140,11 @@ public class MenuInfoRegistryImpl implements MenuInfoRegistry { } @Override + public void endReload() { + InternalLogger.getInstance().debug("Registered %d menu infos", infoSize()); + } + + @Override public void acceptPlugin(REIServerPlugin plugin) { plugin.registerMenuInfo(this); } diff --git a/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java index 8724af7d1..d4bd7b6e1 100644 --- a/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java @@ -47,6 +47,8 @@ import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.search.argument.type.ArgumentType; import me.shedaniel.rei.impl.client.search.argument.type.ArgumentTypesRegistry; import me.shedaniel.rei.impl.client.search.result.ArgumentApplicableResult; +import me.shedaniel.rei.impl.client.util.ThreadCreator; +import me.shedaniel.rei.impl.common.InternalLogger; import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -60,10 +62,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -71,6 +70,7 @@ import java.util.regex.Pattern; @ApiStatus.Internal @Environment(EnvType.CLIENT) public class Argument<T, R> { + private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-ArgumentCache").asService(); public static final Short2ObjectMap<Long2ObjectMap<Object>> SEARCH_CACHE = Short2ObjectMaps.synchronize(new Short2ObjectOpenHashMap<>()); private static final Object NO_CACHE = new Object(); private static final AtomicReference<String> lastLanguage = new AtomicReference<>(); @@ -264,7 +264,7 @@ public class Argument<T, R> { } public static Long prepareStart = null; - public static Collection<EntryStack<?>> prepareStacks = null; + public static List<HashedEntryStackWrapper> prepareStacks = null; public static IntIntPair prepareStage = null; public static IntIntPair[] currentStages = null; @@ -272,22 +272,34 @@ public class Argument<T, R> { if (prepareStage != null || currentStages != null) return; try { prepareStart = Util.getEpochMillis(); - prepareStacks = stacks; + Long2ObjectMap<Object>[] caches = CollectionUtils.map(argumentTypes, Argument::getSearchCache).toArray(Long2ObjectMap[]::new); + prepareStacks = CollectionUtils.mapAndFilter(stacks, stack -> { + for (Long2ObjectMap<Object> cache : caches) { + if (!cache.containsKey(stack.hashExact())) { + return true; + } + } + + return false; + }, HashedEntryStackWrapper::new); + if (prepareStacks.isEmpty()) { + return; + } + InternalLogger.getInstance().trace("Preparing " + prepareStacks.size() + " stacks for search arguments"); prepareStage = new IntIntMutablePair(0, argumentTypes.size()); currentStages = new IntIntPair[argumentTypes.size()]; - List<HashedEntryStackWrapper> hashedStacks = CollectionUtils.map(stacks, HashedEntryStackWrapper::new); int searchPartitionSize = ConfigObject.getInstance().getAsyncSearchPartitionSize(); - boolean async = ConfigObject.getInstance().shouldAsyncSearch() && stacks.size() > searchPartitionSize * 4; + boolean async = ConfigObject.getInstance().shouldAsyncSearch() && prepareStacks.size() > searchPartitionSize * 4; List<CompletableFuture<Long2ObjectMap<Object>>> futures = Lists.newArrayList(); List<Pair<ArgumentType<?, ?>, CompletableFuture<Long2ObjectMap<Object>>>> pairs = Lists.newArrayList(); for (ArgumentType<?, ?> argumentType : argumentTypes) { prepareStage.first(prepareStage.firstInt() + 1); Long2ObjectMap<Object> map = getSearchCache(argumentType); - IntIntPair currentStage = currentStages[prepareStage.firstInt() - 1] = new IntIntMutablePair(0, hashedStacks.size()); + IntIntPair currentStage = currentStages[prepareStage.firstInt() - 1] = new IntIntMutablePair(0, prepareStacks.size()); if (async) { - for (Collection<HashedEntryStackWrapper> partitionStacks : CollectionUtils.partition(hashedStacks, searchPartitionSize)) { + for (Collection<HashedEntryStackWrapper> partitionStacks : CollectionUtils.partition(prepareStacks, searchPartitionSize)) { CompletableFuture<Long2ObjectMap<Object>> future = CompletableFuture.supplyAsync(() -> { Long2ObjectMap<Object> out = new Long2ObjectArrayMap<>(searchPartitionSize + 1); for (HashedEntryStackWrapper stack : partitionStacks) { @@ -300,14 +312,14 @@ public class Argument<T, R> { } } return out; - }).whenComplete((objectLong2ObjectMap, throwable) -> { + }, EXECUTOR_SERVICE).whenComplete((objectLong2ObjectMap, throwable) -> { currentStage.first(currentStage.firstInt() + partitionStacks.size()); }); futures.add(future); pairs.add(Pair.of(argumentType, future)); } } else { - for (HashedEntryStackWrapper stack : hashedStacks) { + for (HashedEntryStackWrapper stack : prepareStacks) { currentStage.first(currentStage.firstInt() + 1); if (map.get(stack.hashExact()) == null) { @@ -324,14 +336,17 @@ public class Argument<T, R> { if (async) { try { CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(30, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { + } catch (ExecutionException | TimeoutException e) { e.printStackTrace(); + } catch (InterruptedException ignore) { } for (Pair<ArgumentType<?, ?>, CompletableFuture<Long2ObjectMap<Object>>> pair : pairs) { Long2ObjectMap<Object> now = pair.second().getNow(null); if (now != null) getSearchCache(pair.left()).putAll(now); } } + + InternalLogger.getInstance().debug("Prepared " + prepareStacks.size() + " stacks for search arguments in " + (Util.getEpochMillis() - prepareStart) + "ms"); } finally { prepareStart = null; prepareStacks = null; diff --git a/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java index 532792d8e..0a04608be 100644 --- a/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java @@ -99,7 +99,7 @@ public class InputMethodRegistryImpl implements InputMethodRegistry { }).join(); service.shutdown(); - InternalLogger.getInstance().debug("Registered %d input methods: ", inputMethods.size(), + InternalLogger.getInstance().debug("Registered %d input methods: %s", inputMethods.size(), inputMethods.values().stream().map(inputMethod -> inputMethod.getName().getString()).collect(Collectors.joining(", "))); } diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListSearchManager.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListSearchManager.java index 2be121ddf..da2ab2eaf 100644 --- a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListSearchManager.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListSearchManager.java @@ -32,7 +32,6 @@ import me.shedaniel.rei.api.client.gui.config.EntryPanelOrdering; import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntry; import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; -import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.view.Views; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; @@ -47,6 +46,7 @@ import org.apache.logging.log4j.Level; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.BooleanSupplier; import java.util.function.Consumer; public class EntryListSearchManager { @@ -78,12 +78,16 @@ public class EntryListSearchManager { if (ignoreLastSearch) searchManager.markDirty(); searchManager.updateFilter(searchTerm); if (searchManager.isDirty()) { - searchManager.getAsync(list -> { - List</*EntryStack<?> | CollapsedStack*/ Object> finalList = collapse(copyAndOrder(list)); + searchManager.getAsync((list, filter) -> { + if (!filter.getFilter().equals(searchTerm)) return; + if (searchManager.getSearchFilter() == null || searchManager.getSearchFilter() != filter) return; + InternalLogger.getInstance().log(ConfigObject.getInstance().doDebugSearchTimeRequired() ? Level.INFO : Level.TRACE, "Search \"%s\" Used [%s]: %s", filter.getFilter(), Thread.currentThread().toString(), stopwatch.toString()); + List</*EntryStack<?> | CollapsedStack*/ Object> finalList = collapse(copyAndOrder(list), () -> searchManager.getSearchFilter() != null && searchManager.getSearchFilter() == filter); - InternalLogger.getInstance().log(ConfigObject.getInstance().doDebugSearchTimeRequired() ? Level.INFO : Level.TRACE, "Search Used: %s", stopwatch.stop().toString()); + InternalLogger.getInstance().log(ConfigObject.getInstance().doDebugSearchTimeRequired() ? Level.INFO : Level.TRACE, "Search \"%s\" Used and Applied [%s]: %s", filter.getFilter(), Thread.currentThread().toString(), stopwatch.stop().toString()); - Minecraft.getInstance().executeBlocking(() -> { + Minecraft.getInstance().submit(() -> { + if (searchManager.getSearchFilter() == null || searchManager.getSearchFilter() != filter) return; update.accept(finalList); }); }); @@ -104,7 +108,7 @@ public class EntryListSearchManager { return list; } - private List</*EntryStack<?> | CollapsedStack*/ Object> collapse(List<EntryStack<?>> stacks) { + private List</*EntryStack<?> | CollapsedStack*/ Object> collapse(List<EntryStack<?>> stacks, BooleanSupplier isValid) { CollapsibleEntryRegistry collapsibleRegistry = CollapsibleEntryRegistry.getInstance(); Map<CollapsibleEntry, @Nullable CollapsedStack> entries = new HashMap<>(); @@ -112,8 +116,12 @@ public class EntryListSearchManager { entries.put(entry, null); } + if (!isValid.getAsBoolean()) return List.of(); + List</*EntryStack<?> | CollapsedStack*/ Object> list = new ArrayList<>(); + int i = 0; + for (EntryStack<?> stack : stacks) { long hashExact = EntryStacks.hashExact(stack); boolean matchedAny = false; @@ -138,6 +146,8 @@ public class EntryListSearchManager { } } + if (i++ % 50 == 0 && !isValid.getAsBoolean()) return List.of(); + if (!matchedAny) { list.add(stack); } diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/dragging/DraggingContextImpl.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/dragging/DraggingContextImpl.java index e041e4daf..3e579a207 100644 --- a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/dragging/DraggingContextImpl.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/dragging/DraggingContextImpl.java @@ -166,6 +166,10 @@ public class DraggingContextImpl extends Widget implements DraggingContext<Scree @Override public boolean mouseReleased(double d, double e, int i) { + if (i != 0) { + return false; + } + drop(); return false; } diff --git a/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java index 0fb426a34..442fda91c 100644 --- a/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java @@ -24,31 +24,33 @@ package me.shedaniel.rei.impl.client.search; import com.google.common.collect.Lists; +import dev.architectury.platform.Platform; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.util.ThreadCreator; import org.jetbrains.annotations.Nullable; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.*; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.UnaryOperator; public class AsyncSearchManager implements SearchManager { + private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-AsyncSearchManager").asService(); private final Supplier<List<EntryStack<?>>> stacksProvider; private final Supplier<Predicate<EntryStack<?>>> additionalPredicateSupplier; private final UnaryOperator<EntryStack<?>> transformer; - private Predicate<EntryStack<?>> additionalPredicate; + private ExecutorTuple executor; private SearchFilter filter; - private boolean dirty = false; - private boolean filterDirty = false; - private CompletableFuture<List<EntryStack<?>>> future; - private List<EntryStack<?>> last; + private Map.Entry<List<EntryStack<?>>, SearchFilter> last; public AsyncSearchManager(Supplier<List<EntryStack<?>>> stacksProvider, Supplier<Predicate<EntryStack<?>>> additionalPredicateSupplier, UnaryOperator<EntryStack<?>> transformer) { this.stacksProvider = stacksProvider; @@ -58,95 +60,157 @@ public class AsyncSearchManager implements SearchManager { @Override public void markDirty() { - this.dirty = true; + synchronized (AsyncSearchManager.this) { + this.last = null; + } } - @Override - public void markFilterDirty() { - this.filterDirty = true; + private record ExecutorTuple(SearchFilter filter, CompletableFuture<Map.Entry<List<EntryStack<?>>, SearchFilter>> future) { } @Override public void updateFilter(String filter) { if (this.filter == null || !this.filter.getFilter().equals(filter)) { + if (this.executor != null) { + this.executor.future().cancel(Platform.isFabric()); + } + this.executor = null; this.filter = SearchProvider.getInstance().createFilter(filter); - markDirty(); - markFilterDirty(); } } @Override public boolean isDirty() { - return last == null || dirty; + synchronized (AsyncSearchManager.this) { + return this.last == null || this.last.getValue() != this.filter; + } } @Override - public boolean isFilterDirty() { - return filterDirty; + public Future<?> getAsync(BiConsumer<List<EntryStack<?>>, SearchFilter> consumer) { + if (this.executor == null || this.executor.filter() != filter) { + if (this.executor != null) { + this.executor.future().cancel(Platform.isFabric()); + } + this.executor = new ExecutorTuple(filter, get(EXECUTOR_SERVICE)); + } + SearchFilter savedFilter = filter; + return (this.executor = new ExecutorTuple(this.executor.filter(), this.executor.future().thenApplyAsync(result -> { + if (savedFilter == filter) { + consumer.accept(result.getKey(), result.getValue()); + } + + return result; + }, EXECUTOR_SERVICE))).future(); } @Override - public Future<Void> getAsync(Consumer<List<EntryStack<?>>> consumer) { - if (future == null || future.isCancelled() || future.isDone() || future.isCompletedExceptionally()) { - if (future != null) future.cancel(true); - future = CompletableFuture.supplyAsync(this) - .exceptionally(throwable -> { - throwable.printStackTrace(); - return null; - }); + public List<EntryStack<?>> get() { + return getNow(); + } + + public List<EntryStack<?>> getNow() { + try { + return get(Runnable::run).get().getKey(); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } catch (InterruptedException | CancellationException e) { + return Lists.newArrayList(); } - return future.thenAccept(consumer); } - @Override - public List<EntryStack<?>> get() { + public CompletableFuture<Map.Entry<List<EntryStack<?>>, SearchFilter>> get(Executor executor) { if (isDirty()) { - this.additionalPredicate = additionalPredicateSupplier.get(); - int searchPartitionSize = ConfigObject.getInstance().getAsyncSearchPartitionSize(); - List<EntryStack<?>> stacks = stacksProvider.get(); - last = new ArrayList<>(); + Map.Entry<List<EntryStack<?>>, SearchFilter> last; + synchronized (AsyncSearchManager.this) |
