aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java53
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java14
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java6
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/ArgumentCache.java8
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java1
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java1
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterWatcher.java85
-rwxr-xr-xruntime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json2
11 files changed, 148 insertions, 32 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java
index 11672222d..c23bf2b64 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java
@@ -177,6 +177,10 @@ public class EntryListSearchManager {
return list;
}
+ public AsyncSearchManager getSearchManager() {
+ return searchManager;
+ }
+
public boolean matches(EntryStack<?> stack) {
return searchManager.matches(stack);
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java
index 5c7836576..c1ab15fba 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java
@@ -31,13 +31,16 @@ 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 me.shedaniel.rei.impl.common.InternalLogger;
import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper;
+import net.minecraft.Util;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
@@ -48,8 +51,8 @@ public class AsyncSearchManager {
private final Supplier<List<HashedEntryStackWrapper>> stacksProvider;
private final Supplier<Predicate<HashedEntryStackWrapper>> additionalPredicateSupplier;
private final UnaryOperator<HashedEntryStackWrapper> transformer;
- private volatile ExecutorTuple executor;
private volatile Map.Entry<List<HashedEntryStackWrapper>, SearchFilter> last;
+ public volatile ExecutorTuple executor;
public volatile SearchFilter filter;
public AsyncSearchManager(Supplier<List<HashedEntryStackWrapper>> stacksProvider, Supplier<Predicate<HashedEntryStackWrapper>> additionalPredicateSupplier, UnaryOperator<HashedEntryStackWrapper> transformer) {
@@ -62,8 +65,15 @@ public class AsyncSearchManager {
this.last = null;
}
- private record ExecutorTuple(SearchFilter filter,
- CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> future) {
+ public record ExecutorTuple(SearchFilter filter,
+ CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> future,
+ Steps steps) {
+ }
+
+ public static class Steps {
+ public long startTime = 0;
+ public AtomicInteger partitionsDone = new AtomicInteger(0);
+ public int totalPartitions = 0;
}
public void updateFilter(String filter) {
@@ -85,7 +95,8 @@ public class AsyncSearchManager {
if (this.executor != null) {
this.executor.future().cancel(Platform.isFabric());
}
- this.executor = new ExecutorTuple(filter, get(EXECUTOR_SERVICE));
+ Steps steps = new Steps();
+ this.executor = new ExecutorTuple(filter, get(EXECUTOR_SERVICE, steps), steps);
}
SearchFilter savedFilter = filter;
return (this.executor = new ExecutorTuple(this.executor.filter(), this.executor.future().thenApplyAsync(result -> {
@@ -94,12 +105,12 @@ public class AsyncSearchManager {
}
return result;
- }, EXECUTOR_SERVICE))).future();
+ }, EXECUTOR_SERVICE), executor.steps)).future();
}
public List<HashedEntryStackWrapper> getNow() {
try {
- return get(Runnable::run).get().getKey();
+ return get(Runnable::run, new Steps()).get().getKey();
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException | CancellationException e) {
@@ -107,12 +118,12 @@ public class AsyncSearchManager {
}
}
- public CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> get(Executor executor) {
+ public CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> get(Executor executor, Steps steps) {
if (isDirty()) {
Map.Entry<List<HashedEntryStackWrapper>, SearchFilter> last;
last = this.last;
return get(this.filter, this.additionalPredicateSupplier.get(), this.transformer,
- this.stacksProvider.get(), last, this, executor)
+ this.stacksProvider.get(), last, this, executor, steps)
.thenApply(entry -> {
this.last = entry;
return entry;
@@ -124,25 +135,34 @@ public class AsyncSearchManager {
public static CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> get(SearchFilter filter, Predicate<HashedEntryStackWrapper> additionalPredicate,
UnaryOperator<HashedEntryStackWrapper> transformer, List<HashedEntryStackWrapper> stacks, Map.Entry<List<HashedEntryStackWrapper>, SearchFilter> last,
- AsyncSearchManager manager, Executor executor) {
+ AsyncSearchManager manager, Executor executor, Steps steps) {
int searchPartitionSize = ConfigObject.getInstance().getAsyncSearchPartitionSize();
boolean shouldAsync = ConfigObject.getInstance().shouldAsyncSearch() && stacks.size() > searchPartitionSize * 4;
+ InternalLogger.getInstance().debug("Starting Search: \"" + filter.getFilter() + "\" with " + stacks.size() + " stacks, shouldAsync: " + shouldAsync + " on " + Thread.currentThread().getName());
if (!stacks.isEmpty()) {
if (shouldAsync) {
List<CompletableFuture<List<HashedEntryStackWrapper>>> futures = Lists.newArrayList();
- for (Iterable<HashedEntryStackWrapper> partitionStacks : CollectionUtils.partition(stacks, Math.max(searchPartitionSize, stacks.size() * 3 / Runtime.getRuntime().availableProcessors()))) {
+ int partitions = 0;
+ for (Iterable<HashedEntryStackWrapper> partitionStacks : CollectionUtils.partition(stacks, searchPartitionSize * 4)) {
+ final int finalPartitions = partitions;
futures.add(CompletableFuture.supplyAsync(() -> {
List<HashedEntryStackWrapper> filtered = Lists.newArrayList();
+ if (manager.filter != filter) throw new CancellationException();
for (HashedEntryStackWrapper stack : partitionStacks) {
- if (stack != null && filter.test(stack.unwrap(), stack.hashExact()) && additionalPredicate.test(stack)) {
+ if (stack != null && test(filter, stack.unwrap(), stack.hashExact()) && additionalPredicate.test(stack)) {
filtered.add(transformer.apply(stack));
}
if (manager.filter != filter) throw new CancellationException();
}
+ steps.partitionsDone.incrementAndGet();
return filtered;
}, executor));
+ partitions++;
}
+ steps.startTime = Util.getEpochMillis();
+ steps.totalPartitions = partitions;
+ InternalLogger.getInstance().debug("Async Search: " + partitions + " partitions for \"" + filter.getFilter() + "\"");
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.orTimeout(90, TimeUnit.SECONDS)
.thenApplyAsync($ -> {
@@ -163,7 +183,7 @@ public class AsyncSearchManager {
List<HashedEntryStackWrapper> list = new ArrayList<>();
for (HashedEntryStackWrapper stack : stacks) {
- if (filter.test(stack.unwrap(), stack.hashExact()) && additionalPredicate.test(stack)) {
+ if (test(filter, stack.unwrap(), stack.hashExact()) && additionalPredicate.test(stack)) {
list.add(transformer.apply(stack));
}
if (manager.filter != filter) throw new CancellationException();
@@ -176,6 +196,15 @@ public class AsyncSearchManager {
return CompletableFuture.completedFuture(new AbstractMap.SimpleImmutableEntry<>(Lists.newArrayList(), filter));
}
+ private static boolean test(SearchFilter filter, EntryStack<?> stack, long hashExact) {
+ try {
+ return filter.test(stack, hashExact);
+ } catch (Throwable throwable) {
+ InternalLogger.getInstance().debug("Error while testing filter", throwable);
+ return false;
+ }
+ }
+
public boolean matches(EntryStack<?> stack) {
return filter.test(stack);
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java
index c19d3f0c1..6b1205d63 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java
@@ -34,11 +34,8 @@ import me.shedaniel.rei.impl.client.search.argument.AlternativeArgument;
import me.shedaniel.rei.impl.client.search.argument.Argument;
import me.shedaniel.rei.impl.client.search.argument.CompoundArgument;
import me.shedaniel.rei.impl.client.search.argument.type.ArgumentType;
-import me.shedaniel.rei.impl.client.util.CrashReportUtils;
import me.shedaniel.rei.impl.common.InternalLogger;
import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper;
-import net.minecraft.CrashReport;
-import net.minecraft.CrashReportCategory;
import java.util.Collection;
import java.util.List;
@@ -72,7 +69,7 @@ public class SearchProviderImpl implements SearchProvider {
.map(Argument::getArgument)
.distinct()
.collect(Collectors.toList()));
- InternalLogger.getInstance().debug("Created search filter with %s using %s", filter, inputMethod.getName().getString());
+ InternalLogger.getInstance().debug("Created search filter with \"%s\" using %s", filter, inputMethod.getName().getString());
}
@Override
@@ -80,14 +77,7 @@ public class SearchProviderImpl implements SearchProvider {
try {
return Argument.matches(stack, hashExact, arguments.get(), inputMethod);
} catch (Throwable throwable) {
- CrashReport report = CrashReportUtils.essential(throwable, "Testing entry with search filter");
- CrashReportCategory category = report.addCategory("Search entry details");
- try {
- stack.fillCrashReport(report, category);
- } catch (Throwable throwable1) {
- category.setDetailError("Filling Report", throwable1);
- }
- throw CrashReportUtils.throwReport(report);
+ throw new RuntimeException("Failed to test search filter: \"" + filter + "\" with stack [" + stack.getType().getIdentifier() + "@" + stack.getIdentifier() + "!" + stack.getValue() + "]", throwable);
}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java
index 7b8dc7d18..bd5034aa3 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java
@@ -55,7 +55,7 @@ import java.util.regex.Pattern;
@ApiStatus.Internal
@Environment(EnvType.CLIENT)
public class Argument<T, R> {
- private static final Object NO_CACHE = new Object();
+ public static final Object NO_CACHE = new Object();
private static final AtomicReference<String> LAST_LANGUAGE = new AtomicReference<>();
public static ArgumentCache cache = new ArgumentCache();
private final ArgumentType<T, R> argumentType;
@@ -81,13 +81,13 @@ public class Argument<T, R> {
Collection<HashedEntryStackWrapper> stacks = new AbstractCollection<>() {
@Override
public Iterator<HashedEntryStackWrapper> iterator() {
- return Iterators.transform(((EntryRegistryImpl) EntryRegistry.getInstance()).getPreFilteredComplexList().iterator(),
+ return Iterators.transform(((EntryRegistryImpl) EntryRegistry.getInstance()).getComplexList().iterator(),
HashedEntryStackWrapper::normalize);
}
@Override
public int size() {
- return EntryRegistry.getInstance().getPreFilteredList().size();
+ return ((EntryRegistryImpl) EntryRegistry.getInstance()).getComplexList().size();
}
};
if (cache) {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/ArgumentCache.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/ArgumentCache.java
index d0a443d3c..033331360 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/ArgumentCache.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/ArgumentCache.java
@@ -134,10 +134,10 @@ public class ArgumentCache {
Long2ObjectMap<Object> out = new Long2ObjectArrayMap<>(stacks.size() + 1);
for (HashedEntryStackWrapper stack : stacks) {
if (cacheMap.get(stack.hashExact()) == null) {
- Object data = argumentType.cacheData(stack.unwrap());
-
- if (data != null) {
- out.put(stack.hashExact(), data);
+ try {
+ Object data = argumentType.cacheData(stack.unwrap());
+ out.put(stack.hashExact(), data == null ? Argument.NO_CACHE : data);
+ } catch (Throwable ignored) {
}
}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java
index d49b7c2cd..d373cee44 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java
@@ -54,7 +54,7 @@ public final class ThreadCreator {
public ExecutorService asService(int poolSize) {
return new ForkJoinPool(poolSize, pool -> {
ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
- worker.setName(group().getName() + "-" + worker.getPoolIndex());
+ worker.setName(group().getName() + "-" + threadId().getAndIncrement());
worker.setContextClassLoader(getClass().getClassLoader());
return worker;
}, ($, exception) -> {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java
index 73f54172f..cf9c5b865 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java
@@ -231,6 +231,7 @@ public abstract class AbstractEntryStack<A> implements EntryStack<A>, Renderer {
}
return tooltip.getValue();
} catch (Throwable throwable) {
+ if (context.isSearch()) throw throwable;
CrashReport report = CrashReportUtils.essential(throwable, "Getting tooltips");
CrashReportUtils.renderer(report, this);
throw CrashReportUtils.throwReport(report);
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java
index a9d476878..942e61ad8 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java
@@ -120,6 +120,10 @@ public class EntryRegistryImpl implements EntryRegistry {
return Collections.unmodifiableList(filteredList.getComplexList());
}
+ public List<HashedEntryStackWrapper> getComplexList() {
+ return Collections.unmodifiableList(registryList.collectHashed());
+ }
+
@Override
public void refilter() {
List<HashedEntryStackWrapper> stacks = registryList.collectHashed();
diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java
index 96bfa0751..339f0d7b0 100644
--- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java
+++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java
@@ -93,6 +93,7 @@ public class DefaultClientRuntimePlugin implements REIClientPlugin {
REIRuntimeImpl.getInstance().addHintProvider(watcher);
REIRuntimeImpl.getInstance().addHintProvider(new SearchBarHighlightWatcher());
REIRuntimeImpl.getInstance().addHintProvider(new SearchFilterPrepareWatcher());
+ REIRuntimeImpl.getInstance().addHintProvider(new SearchFilterWatcher());
REIRuntimeImpl.getInstance().addHintProvider(new InputMethodWatcher());
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterWatcher.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterWatcher.java
new file mode 100644
index 000000000..37aaab934
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterWatcher.java
@@ -0,0 +1,85 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.plugin.client.runtime;
+
+import com.google.common.collect.ImmutableList;
+import me.shedaniel.math.Color;
+import me.shedaniel.math.Point;
+import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
+import me.shedaniel.rei.impl.client.gui.hints.HintProvider;
+import me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListSearchManager;
+import me.shedaniel.rei.impl.client.search.AsyncSearchManager;
+import net.minecraft.Util;
+import net.minecraft.network.chat.Component;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+
+public class SearchFilterWatcher implements HintProvider {
+ private Double lastProcess;
+
+ @Override
+ public List<Component> provide() {
+ lastProcess = null;
+ try {
+ AsyncSearchManager searchManager = EntryListSearchManager.INSTANCE.getSearchManager();
+ if (searchManager.executor != null) {
+ if (searchManager.executor.future().isDone()) return Collections.emptyList();
+ if (searchManager.executor.future().isCancelled()) return Collections.emptyList();
+ if (searchManager.executor.future().isCompletedExceptionally()) return Collections.emptyList();
+ AsyncSearchManager.Steps steps = searchManager.executor.steps();
+ if (steps.startTime == 0 || steps.totalPartitions == 0) return Collections.emptyList();
+ if (Util.getEpochMillis() - steps.startTime < 1000) return Collections.emptyList();
+ lastProcess = steps.partitionsDone.get() / (double) steps.totalPartitions;
+ return ImmutableList.of(Component.translatable("text.rei.searching"),
+ Component.translatable("text.rei.searching.step", Math.round(lastProcess * 100)));
+ }
+ } catch (NullPointerException ignored) {
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ @Nullable
+ public Tooltip provideTooltip(Point mouse) {
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public Double getProgress() {
+ return lastProcess;
+ }
+
+ @Override
+ public Color getColor() {
+ return Color.ofTransparent(0x5003fc24);
+ }
+
+ @Override
+ public List<HintButton> getButtons() {
+ return Collections.emptyList();
+ }
+}
diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
index 680d7019f..35d9f23d0 100755
--- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
+++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
@@ -19,6 +19,8 @@
"text.rei.inventory.highlighting.enabled.tooltip": "This makes slots that does not match\nthe search filter gray.\nDouble click the search bar to toggle this mode.",
"text.rei.caching.search": "REI caching search results...",
"text.rei.caching.search.step": "Step %d/%d (%s%%):",
+ "text.rei.searching": "REI searching results...",
+ "text.rei.searching.step": "This is slower on the first search.\nProgress: %s%%",
"text.rei.config.menu.dark_theme": "Dark Theme",
"text.rei.config.menu.craftable_filter": "Craftable Filter",
"text.rei.config.menu.display": "Display Settings...",