From e35aa217aa3bbba5653201186add39de871fae07 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 27 Feb 2022 19:06:59 +0800 Subject: Fix #787 --- .../rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java | 2 +- .../shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/src/main') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java index e0c9206e4..78854bfa9 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java @@ -173,7 +173,7 @@ public abstract class AbstractDisplayViewingScreen extends Screen implements Dis protected void transformFiltering(List setupDisplay) { for (EntryWidget widget : Widgets.walk(setupDisplay, EntryWidget.class::isInstance)) { if (widget.getEntries().size() > 1) { - Collection> refiltered = EntryRegistry.getInstance().refilterNew(widget.getEntries()); + Collection> refiltered = EntryRegistry.getInstance().refilterNew(false, widget.getEntries()); if (!refiltered.isEmpty()) { widget.clearStacks(); widget.entries(refiltered); 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 247de3c47..ac523d3d5 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 @@ -197,7 +197,7 @@ public class EntryRegistryImpl implements EntryRegistry { int index = entries.lastIndexOf(afterEntry); entries.add(index, stack); } else entries.add(stack); - preFilteredList.addAll(refilterNew(Collections.singletonList(stack))); + preFilteredList.addAll(refilterNew(true, Collections.singletonList(stack))); queueSearchUpdate(); } } @@ -216,7 +216,7 @@ public class EntryRegistryImpl implements EntryRegistry { int index = entries.lastIndexOf(afterEntry); entries.addAll(index, filtered); } else entries.addAll(filtered); - preFilteredList.addAll(refilterNew(filtered)); + preFilteredList.addAll(refilterNew(true, filtered)); queueSearchUpdate(); } } @@ -231,8 +231,8 @@ public class EntryRegistryImpl implements EntryRegistry { @ApiStatus.Internal @Override - public Collection> refilterNew(Collection> entries) { - if (lastRefilterWarning != null) { + public Collection> refilterNew(boolean warn, Collection> entries) { + if (lastRefilterWarning != null && warn) { if (lastRefilterWarning.getValue() > 0 && System.currentTimeMillis() - lastRefilterWarning.getValue() > 5000) { RoughlyEnoughItemsCore.LOGGER.warn("Detected runtime EntryRegistry modification, this can be extremely dangerous, or be extremely inefficient!"); } -- cgit From 6ff07fe77b6d15157f262a766798e683e55c2c57 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Mon, 28 Feb 2022 10:05:31 +0800 Subject: Add search caching hint --- .../client/config/entries/ReloadPluginsEntry.java | 26 ++- .../impl/client/gui/widget/EntryListWidget.java | 32 ++-- .../rei/impl/client/gui/widget/EntryWidget.java | 6 +- .../rei/impl/client/search/AsyncSearchManager.java | 34 +++- .../rei/impl/client/search/SearchProviderImpl.java | 16 ++ .../rei/impl/client/search/argument/Argument.java | 113 ++++++++++-- .../argument/type/AlwaysMatchingArgumentType.java | 8 +- .../client/search/argument/type/ArgumentType.java | 5 +- .../argument/type/IdentifierArgumentType.java | 25 ++- .../search/argument/type/ModArgumentType.java | 22 +-- .../search/argument/type/RegexArgumentType.java | 13 +- .../search/argument/type/TagArgumentType.java | 33 ++-- .../search/argument/type/TextArgumentType.java | 12 +- .../search/argument/type/TooltipArgumentType.java | 31 ++-- .../client/runtime/DefaultClientRuntimePlugin.java | 1 + .../client/runtime/SearchFilterPrepareWatcher.java | 80 +++++++++ .../assets/roughlyenoughitems/lang/cs_cz.json | 7 + .../assets/roughlyenoughitems/lang/en_us.json | 3 + .../assets/roughlyenoughitems/lang/fr_fr.json | 21 ++- .../assets/roughlyenoughitems/lang/lol_us.json | 2 + .../assets/roughlyenoughitems/lang/pt_br.json | 47 +++-- .../assets/roughlyenoughitems/lang/ru_ru.json | 200 ++++++++++++--------- .../assets/roughlyenoughitems/lang/zh_cn.json | 39 +++- .../assets/roughlyenoughitems/lang/zh_tw.json | 26 +++ 24 files changed, 576 insertions(+), 226 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java (limited to 'runtime/src/main') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java index ad1d13cd5..fd715ede5 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java @@ -31,6 +31,7 @@ import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import me.shedaniel.rei.api.common.plugins.PluginManager; import me.shedaniel.rei.impl.client.gui.screen.ConfigReloadingScreen; +import me.shedaniel.rei.impl.client.search.argument.Argument; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.components.AbstractWidget; @@ -48,7 +49,7 @@ import java.util.Optional; @ApiStatus.Internal public class ReloadPluginsEntry extends AbstractConfigListEntry { private int width; - private AbstractWidget buttonWidget = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { + private AbstractWidget reloadPluginsButton = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear(); RoughlyEnoughItemsCoreClient.reloadPlugins(null, null); }) { @@ -62,12 +63,16 @@ public class ReloadPluginsEntry extends AbstractConfigListEntry { } } }; - private List children = ImmutableList.of(buttonWidget); + private AbstractWidget reloadSearchButton = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { + Argument.SEARCH_CACHE.clear(); + }); + private List children = ImmutableList.of(reloadPluginsButton, reloadSearchButton); public ReloadPluginsEntry(int width) { super(NarratorChatListener.NO_TITLE, false); this.width = width; - buttonWidget.setMessage(new TranslatableComponent("text.rei.reload_config")); + reloadPluginsButton.setMessage(new TranslatableComponent("text.rei.reload_config")); + reloadSearchButton.setMessage(new TranslatableComponent("text.rei.reload_search")); } @Override @@ -89,11 +94,16 @@ public class ReloadPluginsEntry extends AbstractConfigListEntry { public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta); Window window = Minecraft.getInstance().getWindow(); - this.buttonWidget.active = this.isEditable(); - this.buttonWidget.y = y; - this.buttonWidget.x = x + entryWidth / 2 - width / 2; - this.buttonWidget.setWidth(width); - this.buttonWidget.render(matrices, mouseX, mouseY, delta); + this.reloadPluginsButton.active = this.isEditable(); + this.reloadPluginsButton.y = y; + this.reloadPluginsButton.setWidth(width / 2 - 6); + this.reloadPluginsButton.x = x + entryWidth / 2 - width / 2; + this.reloadPluginsButton.render(matrices, mouseX, mouseY, delta); + this.reloadSearchButton.active = this.isEditable() && !Argument.SEARCH_CACHE.isEmpty(); + this.reloadSearchButton.y = y; + this.reloadSearchButton.setWidth(width / 2 - 6); + this.reloadSearchButton.x = x + entryWidth / 2 + 3; + this.reloadSearchButton.render(matrices, mouseX, mouseY, delta); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java index 8d0e8b291..28f6e2ca5 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java @@ -88,6 +88,7 @@ import org.apache.commons.lang3.mutable.MutableLong; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -508,26 +509,29 @@ public class EntryListWidget extends WidgetWithBounds implements OverlayListWidg if (ignoreLastSearch) searchManager.markDirty(); searchManager.updateFilter(searchTerm); if (searchManager.isDirty()) { - List> list = searchManager.get(); - EntryPanelOrdering ordering = ConfigObject.getInstance().getItemListOrdering(); - if (ordering == EntryPanelOrdering.NAME) - list.sort(ENTRY_NAME_COMPARER); - if (ordering == EntryPanelOrdering.GROUPS) - list.sort(ENTRY_GROUP_COMPARER); - if (!ConfigObject.getInstance().isItemListAscending()) { - Collections.reverse(list); - } - allStacks = list; + searchManager.getAsync(list -> { + list = new ArrayList<>(list); + EntryPanelOrdering ordering = ConfigObject.getInstance().getItemListOrdering(); + if (ordering == EntryPanelOrdering.NAME) + list.sort(ENTRY_NAME_COMPARER); + if (ordering == EntryPanelOrdering.GROUPS) + list.sort(ENTRY_GROUP_COMPARER); + if (!ConfigObject.getInstance().isItemListAscending()) { + Collections.reverse(list); + } + allStacks = list; + + if (ConfigObject.getInstance().doDebugSearchTimeRequired()) { + RoughlyEnoughItemsCore.LOGGER.info("Search Used: %s", stopwatch.stop().toString()); + } + updateEntriesPosition(); + }); } debugTime = ConfigObject.getInstance().doDebugRenderTimeRequired(); FavoritesListWidget favorites = ScreenOverlayImpl.getFavoritesListWidget(); if (favorites != null) { favorites.updateSearch(); } - if (ConfigObject.getInstance().doDebugSearchTimeRequired()) { - RoughlyEnoughItemsCore.LOGGER.info("Search Used: %s", stopwatch.stop().toString()); - } - updateEntriesPosition(); } public boolean matches(EntryStack stack) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java index a20825496..3f9cfe4cc 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java @@ -59,10 +59,7 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -230,6 +227,7 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget { @Override public EntryWidget entry(EntryStack stack) { + Objects.requireNonNull(stack); if (entryStacks.isEmpty()) { entryStacks = Collections.singletonList(stack); } else { 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 9e1a8934d..b1bc2ecd5 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 @@ -38,10 +38,8 @@ import me.shedaniel.rei.api.common.util.EntryStacks; import java.util.ArrayList; 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.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.UnaryOperator; @@ -53,6 +51,8 @@ public class AsyncSearchManager { private Predicate> additionalPredicate; private SearchFilter filter; private boolean dirty = false; + private boolean filterDirty = false; + private CompletableFuture>> future; private List> last; public AsyncSearchManager(Supplier>> stacksProvider, Supplier>> additionalPredicateSupplier, UnaryOperator> transformer) { @@ -78,10 +78,15 @@ public class AsyncSearchManager { this.dirty = true; } + public void markFilterDirty() { + this.filterDirty = true; + } + public void updateFilter(String filter) { if (this.filter == null || !this.filter.getFilter().equals(filter)) { this.filter = SearchProvider.getInstance().createFilter(filter); markDirty(); + markFilterDirty(); } } @@ -89,6 +94,22 @@ public class AsyncSearchManager { return last == null || dirty; } + public boolean isFilterDirty() { + return filterDirty; + } + + public Future getAsync(Consumer>> consumer) { + if (future == null || future.isCancelled() || future.isDone() || future.isCompletedExceptionally()) { + if (future != null) future.cancel(true); + future = CompletableFuture.supplyAsync(this::get) + .exceptionally(throwable -> { + throwable.printStackTrace(); + return null; + }); + } + return future.thenAccept(consumer); + } + public List> get() { if (isDirty()) { this.additionalPredicate = additionalPredicateSupplier.get(); @@ -97,6 +118,11 @@ public class AsyncSearchManager { last = new ArrayList<>(); if (!stacks.isEmpty()) { + if (filterDirty) { + filter.prepareFilter(stacks); + filterDirty = false; + } + if (ConfigObject.getInstance().shouldAsyncSearch() && stacks.size() > searchPartitionSize * 4) { List>>> futures = Lists.newArrayList(); for (Iterable> partitionStacks : CollectionUtils.partition(stacks, searchPartitionSize)) { 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 f91005c45..9a3948a86 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 @@ -26,14 +26,18 @@ package me.shedaniel.rei.impl.client.search; 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.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 net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; +import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; public class SearchProviderImpl implements SearchProvider { @Override @@ -49,10 +53,17 @@ public class SearchProviderImpl implements SearchProvider { public static class SearchFilterImpl implements SearchFilter { private final List arguments; private final String filter; + private final List> argumentTypes; public SearchFilterImpl(List arguments, String searchTerm) { this.arguments = arguments; this.filter = searchTerm; + this.argumentTypes = arguments.stream() + .flatMap(CompoundArgument::stream) + .flatMap(AlternativeArgument::stream) + .map(Argument::getArgument) + .distinct() + .collect(Collectors.toList()); } @Override @@ -71,6 +82,11 @@ public class SearchProviderImpl implements SearchProvider { } } + @Override + public void prepareFilter(Collection> stacks) { + Argument.prepareFilter(stacks, argumentTypes); + } + @Override public String getFilter() { return filter; 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 7366f869a..0844257ad 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 @@ -25,27 +25,33 @@ package me.shedaniel.rei.impl.client.search.argument; import com.google.common.base.MoreObjects; import com.google.common.collect.Lists; +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.IntIntMutablePair; +import it.unimi.dsi.fastutil.ints.IntIntPair; +import it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMaps; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.SearchMode; 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.search.IntRange; import me.shedaniel.rei.impl.client.search.argument.type.AlwaysMatchingArgumentType; 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.common.util.HashedEntryStackWrapper; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.util.Unit; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -53,6 +59,10 @@ 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.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -178,12 +188,11 @@ public class Argument { if (!Objects.equals(lastLanguage.getAndSet(newLanguage), newLanguage)) { SEARCH_CACHE.clear(); } - Mutable mutable = new MutableObject<>(); a: for (CompoundArgument arguments : compoundArguments) { for (AlternativeArgument argument : arguments) { - if (!matches(stack, argument, mutable)) { + if (!matches(stack, argument)) { continue a; } } @@ -194,12 +203,12 @@ public class Argument { return false; } - private static boolean matches(EntryStack stack, AlternativeArgument alternativeArgument, Mutable mutable) { + private static boolean matches(EntryStack stack, AlternativeArgument alternativeArgument) { if (alternativeArgument.isEmpty()) return true; long hashExact = EntryStacks.hashExact(stack); for (Argument argument : alternativeArgument) { - if (matches((short) argument.getArgument().getIndex(), argument.getArgument(), mutable, stack, hashExact, argument.getText(), argument.filterData) == argument.isRegular()) { + if (matches(argument.getArgument(), stack, hashExact, argument.getText(), argument.filterData) == argument.isRegular()) { return true; } } @@ -207,18 +216,98 @@ public class Argument { return false; } - private static boolean matches(short argumentIndex, ArgumentType argumentType, Mutable data, EntryStack stack, long hashExact, String filter, R filterData) { + private static Long2ObjectMap getSearchCache(ArgumentType argumentType) { + short argumentIndex = (short) argumentType.getIndex(); Long2ObjectMap map = SEARCH_CACHE.get(argumentIndex); if (map == null) { SEARCH_CACHE.put(argumentIndex, map = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>())); } - Z value = (Z) map.get(hashExact); - data.setValue(value); - boolean matches = argumentType.matches((Mutable) data, stack, filter, (T) filterData); + return map; + } + + private static boolean matches(ArgumentType argumentType, EntryStack stack, long hashExact, String filter, R filterData) { + Long2ObjectMap map = getSearchCache(argumentType); + B value = (B) map.get(hashExact); if (value == null) { - map.put(hashExact, data.getValue()); + value = argumentType.cacheData(stack); + map.put(hashExact, value); } - return matches; + return argumentType.matches(value, stack, filter, (T) filterData); + } + + public static Long prepareStart = null; + public static Collection> prepareStacks = null; + public static IntIntPair prepareStage = null; + public static IntIntPair[] currentStages = null; + + public static void prepareFilter(Collection> stacks, Collection> argumentTypes) { + if (prepareStage != null || currentStages != null) return; + prepareStart = Util.getEpochMillis(); + prepareStacks = stacks; + prepareStage = new IntIntMutablePair(0, argumentTypes.size()); + currentStages = new IntIntPair[argumentTypes.size()]; + List hashedStacks = CollectionUtils.map(stacks, HashedEntryStackWrapper::new); + int searchPartitionSize = ConfigObject.getInstance().getAsyncSearchPartitionSize(); + boolean async = ConfigObject.getInstance().shouldAsyncSearch() && stacks.size() > searchPartitionSize * 4; + List>> futures = Lists.newArrayList(); + List, CompletableFuture>>> pairs = Lists.newArrayList(); + + for (ArgumentType argumentType : argumentTypes) { + prepareStage.first(prepareStage.firstInt() + 1); + Long2ObjectMap map = getSearchCache(argumentType); + IntIntPair currentStage = currentStages[prepareStage.firstInt() - 1] = new IntIntMutablePair(0, hashedStacks.size()); + + if (async) { + for (Collection partitionStacks : CollectionUtils.partition(hashedStacks, searchPartitionSize)) { + CompletableFuture> future = CompletableFuture.supplyAsync(() -> { + Long2ObjectMap out = new Long2ObjectArrayMap<>(searchPartitionSize + 1); + for (HashedEntryStackWrapper stack : partitionStacks) { + if (map.get(stack.hashExact()) == null) { + Object data = argumentType.cacheData(stack.unwrap()); + + if (data != null) { + out.put(stack.hashExact(), data); + } + } + } + return out; + }).whenComplete((objectLong2ObjectMap, throwable) -> { + currentStage.first(currentStage.firstInt() + partitionStacks.size()); + }); + futures.add(future); + pairs.add(Pair.of(argumentType, future)); + } + } else { + for (HashedEntryStackWrapper stack : hashedStacks) { + currentStage.first(currentStage.firstInt() + 1); + + if (map.get(stack.hashExact()) == null) { + Object data = argumentType.cacheData(stack.unwrap()); + + if (data != null) { + map.put(stack.hashExact(), data); + } + } + } + } + } + + if (async) { + try { + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(10, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + e.printStackTrace(); + } + for (Pair, CompletableFuture>> pair : pairs) { + Long2ObjectMap now = pair.second().getNow(null); + if (now != null) getSearchCache(pair.left()).putAll(now); + } + } + + prepareStart = null; + prepareStacks = null; + prepareStage = null; + currentStages = null; } public ArgumentType getArgument() { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java index 5d498b95e..ee15b8496 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java @@ -28,7 +28,6 @@ import me.shedaniel.rei.impl.client.search.result.ArgumentApplicableResult; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.util.Unit; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal @@ -42,7 +41,12 @@ public final class AlwaysMatchingArgumentType extends ArgumentType { } @Override - public boolean matches(Mutable data, EntryStack stack, String searchText, Unit filterData) { + public Unit cacheData(EntryStack stack) { + return null; + } + + @Override + public boolean matches(Unit data, EntryStack stack, String searchText, Unit filterData) { return true; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java index f196f8854..7e0e75348 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java @@ -29,7 +29,6 @@ import me.shedaniel.rei.impl.client.search.result.ArgumentApplicableResult; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.chat.Style; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -83,7 +82,9 @@ public abstract class ArgumentType { return ArgumentApplicableResult.notApplicable(); } - public abstract boolean matches(Mutable data, EntryStack stack, String searchText, T filterData); + public abstract R cacheData(EntryStack stack); + + public abstract boolean matches(R data, EntryStack stack, String searchText, T filterData); public abstract T prepareSearchFilter(String searchText); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java index f490cac7a..350f3b6e6 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java @@ -32,7 +32,6 @@ import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -65,21 +64,19 @@ public final class IdentifierArgumentType extends ArgumentType { } @Override - public boolean matches(Mutable data, EntryStack stack, String searchText, Unit filterData) { - if (data.getValue() == null) { - ResourceLocation identifier = stack.getIdentifier(); - if (identifier == null) { - data.setValue(EMPTY); - } else { - String s = identifier.getPath(); - if (s.isEmpty()) { - data.setValue(EMPTY); - } else { - data.setValue(s); - } + public String cacheData(EntryStack stack) { + ResourceLocation identifier = stack.getIdentifier(); + if (identifier != null) { + String s = identifier.getPath(); + if (!s.isEmpty()) { + return s; } } - String identifier = data.getValue(); + return EMPTY; + } + + @Override + public boolean matches(String identifier, EntryStack stack, String searchText, Unit filterData) { return !identifier.isEmpty() && identifier.contains(searchText); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java index 458b5156b..06e8d35fc 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java @@ -31,9 +31,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -62,15 +60,17 @@ public final class ModArgumentType extends ArgumentType data, EntryStack stack, String searchText, Unit filterData) { - if (data.getValue() == null) { - String containingNs = stack.getContainingNamespace(); - data.setValue(containingNs != null ? new ModInfoPair( - containingNs, - null - ) : ModInfoPair.EMPTY); - } - ModInfoPair pair = data.getValue(); + @Nullable + public ModInfoPair cacheData(EntryStack stack) { + String containingNs = stack.getContainingNamespace(); + return containingNs != null ? new ModInfoPair( + containingNs, + null + ) : ModInfoPair.EMPTY; + } + + @Override + public boolean matches(@Nullable ModInfoPair pair, EntryStack stack, String searchText, Unit filterData) { if (pair.modId == null || pair.modId.contains(searchText)) return true; if (pair.modName == null) { pair.modName = ClientHelper.getInstance().getModFromModId(pair.modId).toLowerCase(Locale.ROOT); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java index 136941fa3..a1833154b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java @@ -29,7 +29,6 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -80,12 +79,14 @@ public final class RegexArgumentType extends ArgumentType<@Nullable Pattern, Str } @Override - public boolean matches(Mutable data, EntryStack stack, String searchText, @Nullable Pattern filterData) { + public String cacheData(EntryStack stack) { + return stack.asFormatStrippedText().getString(); + } + + @Override + public boolean matches(String data, EntryStack stack, String searchText, @Nullable Pattern filterData) { if (filterData == null) return false; - if (data.getValue() == null) { - data.setValue(stack.asFormatStrippedText().getString()); - } - Matcher matcher = filterData.matcher(data.getValue()); + Matcher matcher = filterData.matcher(data); return matcher != null && matcher.matches(); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java index e64ebff9b..fb74078b3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java @@ -32,7 +32,6 @@ import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -67,22 +66,26 @@ public final class TagArgumentType extends ArgumentType { } @Override - public boolean matches(Mutable data, EntryStack stack, String searchText, Unit filterData) { - if (data.getValue() == null) { - Collection tags = stack.getTagsFor(); - if (tags.isEmpty()) { - data.setValue(EMPTY_ARRAY); - } else { - data.setValue(new String[tags.size()]); - int i = 0; - - for (ResourceLocation identifier : tags) { - data.getValue()[i] = identifier.toString(); - i++; - } + public String[] cacheData(EntryStack stack) { + Collection tags = stack.getTagsFor(); + if (tags.isEmpty()) { + return EMPTY_ARRAY; + } else { + String[] arr = new String[tags.size()]; + int i = 0; + + for (ResourceLocation identifier : tags) { + arr[i] = identifier.toString(); + i++; } + + return arr; } - for (String tag : data.getValue()) { + } + + @Override + public boolean matches(String[] data, EntryStack stack, String searchText, Unit filterData) { + for (String tag : data) { if (!tag.isEmpty() && tag.contains(searchText)) { return true; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java index e17f0dadb..a3ee560f4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java @@ -28,7 +28,6 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.util.Unit; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -56,11 +55,12 @@ public final class TextArgumentType extends ArgumentType { } @Override - public boolean matches(Mutable data, EntryStack stack, String searchText, Unit filterData) { - if (data.getValue() == null) { - data.setValue(stack.asFormatStrippedText().getString().toLowerCase(Locale.ROOT)); - } - String value = data.getValue(); + public String cacheData(EntryStack stack) { + return stack.asFormatStrippedText().getString().toLowerCase(Locale.ROOT); + } + + @Override + public boolean matches(String value, EntryStack stack, String searchText, Unit filterData) { return !value.isEmpty() && value.contains(searchText); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java index dc8491615..372214b8a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java @@ -33,7 +33,6 @@ import net.fabricmc.api.Environment; import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; import net.minecraft.util.Unit; -import org.apache.commons.lang3.mutable.Mutable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -45,6 +44,7 @@ import java.util.StringJoiner; @Environment(EnvType.CLIENT) public final class TooltipArgumentType extends ArgumentType { public static final TooltipArgumentType INSTANCE = new TooltipArgumentType(); + public static final String INVALID = "INVALID_PIECE_OF_TOOLTIP_I_DONT_THINK_PEOPLE_WILL_EXACTLY_HAVE_THIS_REI_REI_REI"; private static final Style STYLE = Style.EMPTY.withColor(TextColor.fromRgb(0xffe0ad)); @Override @@ -69,13 +69,16 @@ public final class TooltipArgumentType extends ArgumentType { } @Override - public boolean matches(Mutable data, EntryStack stack, String searchText, Unit filterData) { - if (data.getValue() == null) { - String tooltip = tryGetEntryStackTooltip(stack, 0); - if (tooltip == null) return false; - data.setValue(tooltip.toLowerCase(Locale.ROOT)); - } - String tooltip = data.getValue(); + public String cacheData(EntryStack stack) { + String tooltip = tryGetEntryStackTooltip(stack, 0); + if (tooltip == null) return INVALID; + return tooltip.toLowerCase(Locale.ROOT); + } + + @Override + public boolean matches(String tooltip, EntryStack stack, String searchText, Unit filterData) { + //noinspection StringEquality + if (tooltip == INVALID) return false; return tooltip.isEmpty() || tooltip.contains(searchText); } @@ -84,13 +87,13 @@ public final class TooltipArgumentType extends ArgumentType { try { Tooltip tooltip = stack.getTooltip(new Point(), false); if (tooltip != null) { - StringJoiner joiner = new StringJoiner("\n"); - for (Tooltip.Entry entry : tooltip.entries()) { - if (entry.isText()) { - joiner.add(entry.getAsText().getString()); + StringJoiner joiner = new StringJoiner("\n"); + for (Tooltip.Entry entry : tooltip.entries()) { + if (entry.isText()) { + joiner.add(entry.getAsText().getString()); + } } - } - return joiner.toString(); + return joiner.toString(); } return ""; } catch (Throwable throwable) { 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 9101f7648..41c37ce83 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 @@ -91,6 +91,7 @@ public class DefaultClientRuntimePlugin implements REIClientPlugin { } REIRuntimeImpl.getInstance().addHintProvider(watcher); REIRuntimeImpl.getInstance().addHintProvider(new SearchBarHighlightWatcher()); + REIRuntimeImpl.getInstance().addHintProvider(new SearchFilterPrepareWatcher()); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java new file mode 100644 index 000000000..436f41724 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java @@ -0,0 +1,80 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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 it.unimi.dsi.fastutil.ints.IntIntPair; +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.search.argument.Argument; +import net.minecraft.Util; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +public class SearchFilterPrepareWatcher implements HintProvider { + private Double lastProcess; + + @Override + public List provide() { + lastProcess = null; + if (Argument.prepareStage != null && Argument.currentStages != null && Argument.prepareStacks != null && Argument.prepareStacks.size() > 100) { + if (Util.getEpochMillis() - Argument.prepareStart < 500) return Collections.emptyList(); + int prepareStageCurrent = Argument.prepareStage.firstInt(); + int prepareStageTotal = Argument.prepareStage.secondInt(); + IntIntPair currentStage = ArrayUtils.get(Argument.currentStages, prepareStageCurrent - 1); + int currentStageCurrent = currentStage == null ? 0 : currentStage.firstInt(); + int currentStageTotal = currentStage == null ? 0 : currentStage.secondInt(); + double prepareStageProgress = prepareStageTotal == 0 ? 0 : prepareStageCurrent / (double) prepareStageTotal; + double currentStageProgress = currentStageTotal == 0 ? 0 : currentStageCurrent / (double) currentStageTotal; + lastProcess = prepareStageTotal == 0 ? 0 : Math.max(0, prepareStageProgress - (1 - currentStageProgress) / prepareStageTotal); + return ImmutableList.of(new TranslatableComponent("text.rei.caching.search"), + new TranslatableComponent("text.rei.caching.search.step", prepareStageCurrent, prepareStageTotal, Math.round(lastProcess * 100))); + } + 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(0x50de38ff); + } +} diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/cs_cz.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/cs_cz.json index 1ec0f9219..9109c032a 100644 --- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/cs_cz.json +++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/cs_cz.json @@ -13,6 +13,11 @@ "text.rei.not.fully.initialized.tooltip": "Chybějící fáze: %s\nPokud toto nezmizí,\nzkuste hledat podporu s logy!", "text.rei.inventory.highlighting.enabled": "Zvýraznění inventáře zapnuto", "text.rei.inventory.highlighting.enabled.tooltip": "Tenhle režim dělá sloty neodpovídající\nfiltru hledání šedé.\nDvojitým kliknutím na vyhledávací lištu přepnete.", + "text.rei.config.menu.dark_theme": "Tmavý motiv", + "text.rei.config.menu.craftable_filter": "Filtrovat vyrobitelné", + "text.rei.config.menu.display": "Nastavení Zobrazení...", + "text.rei.config.menu.display.remove_recipe_book": "Odstranit knihu receptů", + "text.rei.config.menu.config": "Více Možností...", "category.rei.crafting": "Vyrábění", "category.rei.smelting": "Vypékání", "category.rei.smelting.fuel": "Palivo", @@ -39,6 +44,8 @@ "category.rei.beacon_payment": "Aktivace majáku", "category.rei.tilling": "Zorání půdy", "category.rei.pathing": "Vytvoření pěšiny", + "category.rei.waxing": "Voskovaní", + "category.rei.oxidizing": "Oxidujúci", "category.rei.information": "Informace", "text.rei.composting.chance": "§e%d%% šance", "text.rei.composting.page": "Strana %d", 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 e687b3565..92cfd0256 100755 --- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json +++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json @@ -13,6 +13,8 @@ "text.rei.not.fully.initialized.tooltip": "Missing stages: %s\nIf this does not go away,\ntry looking for support with the logs!", "text.rei.inventory.highlighting.enabled": "Inventory Highlighting On", "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.config.menu.dark_theme": "Dark Theme", "text.rei.config.menu.craftable_filter": "Craftable Filter", "text.rei.config.menu.display": "Display Settings...", @@ -102,6 +104,7 @@ "text.rei.time_button.name.evening": "Evening", "text.rei.time_button.name.night": "Night", "text.rei.reload_config": "Reload Plugins", + "text.rei.reload_search": "Reload Search", "text.rei.config.is.reloading": "Plugins are reloading!", "text.rei.enabled": "Yes", "text.rei.disabled": "No", diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/fr_fr.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/fr_fr.json index e5f988b67..c406fe398 100644 --- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/fr_fr.json +++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/fr_fr.json @@ -5,7 +5,7 @@ "text.rei.cheating_limited_enabled": "§bTriche activée (commandes activées)", "text.rei.cheating_enabled_no_perms": "§7Triche §cactivée §7(aucune permission)", "text.rei.cheating_limited_creative_enabled": "§aTriche activée (en mode Créatif)", - "text.rei.no_permission_cheat": "Les permissions d'opérateur sont requises pour obtenir des objets", + "text.rei.no_permission_cheat": "Les permissions d'opérateur sont requises pour se donner des objets", "text.rei.search.field.suggestion": "Rechercher...", "text.rei.feedback": "Avez-vous des retours à faire au developeur de REI ? %s pour envoyer vos retours!", "text.rei.feedback.link": "Cliquez ici pour visiter le formulaire Google", @@ -14,9 +14,11 @@ "text.rei.inventory.highlighting.enabled": "Surbrillance de l'inventaire activé", "text.rei.inventory.highlighting.enabled.tooltip": "Cela rend les emplacements non correspondant grisés.\nDouble-cliquez sur la barre de recherche pour activer ce mode.", "text.rei.config.menu.dark_theme": "Thème sombre", + "text.rei.config.menu.display": "Paramètres d'Affichages...", "text.rei.config.menu.display.remove_recipe_book": "Enlever le livre des recettes", "text.rei.config.menu.display.left_side_panel": "Panneau gauche", "text.rei.config.menu.display.scrolling_side_panel": "Défilement du panneau latéral", + "text.rei.config.menu.config": "Plus d'Options...", "category.rei.crafting": "Fabrication", "category.rei.smelting": "Cuisson", "category.rei.smelting.fuel": "Combustible", @@ -58,6 +60,7 @@ "ordering.rei.name": "Nom", "ordering.rei.item_groups": "Thème", "text.auto_craft.move_items": "Transférer les objets", + "text.auto_craft.move_items.tooltip": "Ctrl-Clique pour Déplacer des Items", "text.auto_craft.move_items.yog": "NullPointerException générée !", "error.rei.transfer.too_small": "Impossible de déplacer les objets vers une grille de %dx%d.", "error.rei.not.on.server": "REI n'est pas installé sur le serveur.", @@ -82,6 +85,10 @@ "text.rei.gamemode_button.tooltip.entry": "Basculer vers %s", "text.rei.weather_button.tooltip.dropdown": "Changer la météo : liste déroulante", "text.rei.weather_button.tooltip.entry": "Basculer vers %s", + "text.rei.time_button.name.morn": "Matin", + "text.rei.time_button.name.noon": "Midi", + "text.rei.time_button.name.evening": "Soir", + "text.rei.time_button.name.night": "Nuit", "text.rei.reload_config": "Recharger les plugins", "text.rei.config.is.reloading": "Les plugins sont en cours de rechargement !", "text.rei.enabled": "Oui", @@ -116,8 +123,12 @@ "text.rei.subsets": "Sous-ensembles", "text.rei.tiny_potato": "P'tites patates", "text.rei.add_favorite_widget": "Ajouter...", + "text.rei.dispose_here": "Placer ici", + "text.rei.crash.title": "REI a planté !", + "text.rei.crash.crash_report": "Ouvrir le Rapport de Crash", "favorite.section.gamemode": "Mode de jeu", "favorite.section.weather": "Météo", + "favorite.section.time": "Temps", "tooltip.rei.fluid_amount": "§7%d unités", "tooltip.rei.fluid_amount.forge": "§7%d mB", "tooltip.rei.drag_to_add_favorites": "§7Faites glisser vers le haut pour l'ajouter à vos favoris !", @@ -134,6 +145,7 @@ "config.roughlyenoughitems.functionality": "Fonctionnalité", "config.roughlyenoughitems.advanced": "Avancé", "config.roughlyenoughitems.cheating": "Triche :", + "config.roughlyenoughitems.cheating.when_creative": "En Mode Créatif", "config.roughlyenoughitems.favoritesEnabled": "Favoris activés :", "config.roughlyenoughitems.keyBindings": "Raccourcis clavier", "config.roughlyenoughitems.keyBindings.recipeKeybind": "Afficher la recette :", @@ -173,6 +185,9 @@ "config.roughlyenoughitems.layout.configButtonLocation.upper": "Plus haut", "config.roughlyenoughitems.layout.configButtonLocation.lower": "Bas", "config.roughlyenoughitems.layout.mergeDisplayUnderOne": "Fusionner les Affichages avec des Contenus Equivalents:", + "config.roughlyenoughitems.layout.favoriteAddWidgetMode.always_invisible": "Toujours Invisible", + "config.roughlyenoughitems.layout.favoriteAddWidgetMode.auto_hide": "Cacher Automatiquement", + "config.roughlyenoughitems.layout.favoriteAddWidgetMode.always_visible": "Toujours Visible", "config.roughlyenoughitems.filteredEntries.selectAll": "Tout sélectionner", "config.roughlyenoughitems.filteredEntries.selectNone": "Tout désélectionner", "config.roughlyenoughitems.filteredEntries.hide": "Masquer", @@ -253,6 +268,10 @@ "config.roughlyenoughitems.syntaxHighlightingMode.plain_underscored": "Simple (souligné)", "config.roughlyenoughitems.syntaxHighlightingMode.colorful": "Coloré", "config.roughlyenoughitems.syntaxHighlightingMode.colorful_underscored": "Coloré (souligné)", + "config.roughlyenoughitems.isFocusModeZoomed": "Entrée en Mode Focus :", + "config.roughlyenoughitems.isFocusModeZoomed.boolean.true": "Zoomé", + "config.roughlyenoughitems.isFocusModeZoomed.boolean.false": "Surligné", + "config.roughlyenoughitems.filtering.shouldFilterDisplays": "Le Filtre Devrait Afficher :", "config.roughlyenoughitems.filteringScreen": "Filtrage personnalisé", "config.roughlyenoughitems.filteringRulesScreen": "Règles de filtrage personnalisées", "config.roughlyenoughitems.filteringRulesScreen.new": "Créer une règle de filtrage", diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/lol_us.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/lol_us.json index 5a4efee55..0188c3867 100644 --- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/lol_us.json +++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/lol_us.json @@ -93,6 +93,7 @@ "text.rei.tiny_potato": "oh hi tiny poTATOz k?", "favorite.section.weather": "Weethr", "tooltip.rei.fluid_amount": "§7%d Unit", + "tooltip.rei.drag_to_add_favorites": "Drag dis up 2 add dis 2 ur favoritez!", "msg.rei.copied_recipe_id": "Copied Wecipe Identifiew", "msg.rei.recipe_id_details": "Wecipe ID: %s", "msg.rei.exported_recipe": "exportd recipe", @@ -106,6 +107,7 @@ "config.roughlyenoughitems.functionality": "funcTIONalitie", "config.roughlyenoughitems.advanced": "oH hi ADvancd plz?", "config.roughlyenoughitems.cheating": "Cheating:", + "config.roughlyenoughitems.cheating.when_creative": "Durin creativ mode", "config.roughlyenoughitems.favoritesEnabled": "favoritez inableD:", "config.roughlyenoughitems.keyBindings": "keybindingz", "config.roughlyenoughitems.keyBindings.recipeKeybind": "show recipe:", diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/pt_br.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/pt_br.json index 8507cc64b..47089c7cd 100644 --- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/pt_br.json +++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/pt_br.json @@ -7,9 +7,9 @@ "text.rei.cheating_limited_creative_enabled": "§aAtivar trapaças (modo Criativo)", "text.rei.no_permission_cheat": "Você precisa ser um operador para obter itens", "text.rei.search.field.suggestion": "Buscar...", - "text.rei.feedback": "Deseja enviar um feedback ao desenvolvedor do REI? %s para enviá-lo!", - "text.rei.feedback.link": "Clique aqui para acessar o formulário de feedback", - "text.rei.not.fully.initialized": "REI ainda não inicializado completamente!", + "text.rei.feedback": "Deseja enviar feedback ao desenvolvedor do REI? %s para enviá-lo!", + "text.rei.feedback.link": "Acesse o formulário de feedback", + "text.rei.not.fully.initialized": "O REI ainda não está completamente inicializado!", "text.rei.not.fully.initialized.tooltip": "Etapas restantes: %s\nSe isso continuar,\nverifique os registros!\n", "text.rei.inventory.highlighting.enabled": "Destaque de inventário ativado", "text.rei.inventory.highlighting.enabled.tooltip": "Os espaços não encontrados na busca\nficarão da cor cinza.\nClique duas vezes na barra de busca para ativar o modo.", @@ -17,6 +17,11 @@ "text.rei.config.menu.craftable_filter": "Fabricáveis", "text.rei.config.menu.display": "Exibição...", "text.rei.config.menu.display.remove_recipe_book": "Ocultar livro de receitas", + "text.rei.config.menu.display.left_side_mob_effects": "Efeitos de criaturas (esquerdo)", + "text.rei.config.menu.display.left_side_panel": "Painel do lado esquerdo", + "text.rei.config.menu.display.scrolling_side_panel": "Painel de rolagem lateral", + "text.rei.config.menu.display.side_search_field": "Campo de busca lateral", + "text.rei.config.menu.display.syntax_highlighting": "Destaque de sintaxe", "text.rei.config.menu.config": "Outras...", "category.rei.crafting": "Fabricáveis", "category.rei.smelting": "Fundíveis", @@ -52,23 +57,26 @@ "text.rei.composting.chance": "§e%d%% de chances", "text.rei.composting.page": "Pág. %d", "text.rei.config": "Definições", - "text.rei.config_tooltip": "Abrir menu de definições\n§7Shift+clique para alternar o modo trapaça", + "text.rei.config_tooltip": "Abrir menu de definições\n§7Shift + clique para alternar o modo trapaça", "text.rei.cheat_items": "{player_name} recebeu {item_count} unidade(s) de [{item_name}§f].", "text.rei.failed_cheat_items": "§cFalha ao obter itens.", "text.rei.too_long_nbt": "§cO NBT do item é longo demais para ser aplicado ao modo multijogador.", + "text.rei.tag_match": "Tag aceita: #%s", "text.rei.performance": "Análise de desempenho", "ordering.rei.ascending": "Crescente", "ordering.rei.descending": "Descrescente", "ordering.rei.registry": "Registro", "ordering.rei.name": "Nome", - "ordering.rei.item_groups": "Conjuntos de itens", + "ordering.rei.item_groups": "Grupos de itens", "text.auto_craft.move_items": "Mover itens", + "text.auto_craft.move_items.tooltip": "Ctrl + clique para mover itens", "text.auto_craft.move_items.yog": "Gerar NullPointerException!", "error.rei.transfer.too_small": "Não é possível mover os itens para uma grade %dx%d.", "error.rei.not.on.server": "O REI não está disponível no servidor.", - "error.rei.not.enough.materials": "Materiais insuficientes.", + "error.rei.not.enough.materials": "Matéria-prima insuficiente.", "error.rei.internal.error": "Erro interno: %s", "error.rei.recipe.not.unlocked": "Receita inacessível no livro de receitas.", + "error.rei.not.supported.move.items": "Não é possível mover itens com essa receita e contêiner.", "error.rei.no.handlers.applicable": "Processo indisponível.", "error.rei.multi.errors": "Vários erros:", "rei.rei.no.slot.in.inv": "Espaço insuficiente no inventário.", @@ -78,13 +86,13 @@ "text.rei.credits": "Créditos", "text.rei.left_arrow": "<", "text.rei.right_arrow": ">", - "text.rei.view_all_categories": "Ver todas as categorias", + "text.rei.view_all_categories": "Ver todas", "text.rei.go_back_first_page": "Voltar ao começo", "text.rei.choose_page": "Escolher página", "text.rei.shift_click_to": "Clique + Shift para %s", - "text.rei.gamemode_button.tooltip.dropdown": "Alterar modo de jogo: Dropdown", + "text.rei.gamemode_button.tooltip.dropdown": "Alterar modo de jogo: Lista", "text.rei.gamemode_button.tooltip.entry": "Mudar para %s", - "text.rei.weather_button.tooltip.dropdown": "Alterar tempo: Dropdown", + "text.rei.weather_button.tooltip.dropdown": "Alterar tempo: Lista", "text.rei.weather_button.tooltip.entry": "Mudar para %s", "text.rei.reload_config": "Recarregar plug-ins", "text.rei.config.is.reloading": "Recarregando plug-ins!", @@ -130,12 +138,12 @@ "msg.rei.recipe_id_details": "ID: %s", "msg.rei.exported_recipe": "Receita exportada", "msg.rei.exported_recipe.desc": "Verifique a pasta \"rei_exports\".", - "subsets.rei.roughlyenoughitems.all_entries": "Todas as entradas", + "subsets.rei.roughlyenoughitems.all_entries": "Todas", "subsets.rei.roughlyenoughitems.item_groups": "Guias do Criativo", "_comment": "Descrições de definições", "config.roughlyenoughitems.title": "Definições do Roughly Enough Items", "config.roughlyenoughitems.basics": "Básico", - "config.roughlyenoughitems.appearance": "Aparência", + "config.roughlyenoughitems.appearance": "Estilo", "config.roughlyenoughitems.functionality": "Funções", "config.roughlyenoughitems.advanced": "Avançado", "config.roughlyenoughitems.cheating": "Trapaças:", @@ -153,7 +161,7 @@ "config.roughlyenoughitems.keyBindings.previousScreenKeybind": "Tela anterior:", "config.roughlyenoughitems.cheatingStyle": "Estilo de trapaça:", "config.roughlyenoughitems.cheatingStyle.grab": "Pegar", - "config.roughlyenoughitems.cheatingStyle.give": "Give", + "config.roughlyenoughitems.cheatingStyle.give": "Dar", "config.roughlyenoughitems.motion": "Definições de animações", "config.roughlyenoughitems.motion.configScreenAnimation": "Animação da tela de def.:", "config.roughlyenoughitems.motion.creditsScreenAnimation": "Animação da tela de créditos:", @@ -193,19 +201,19 @@ "config.roughlyenoughitems.recipeBorder": "Canto da receita:", "config.roughlyenoughitems.recipeBorder.lighter": "Claro", "config.roughlyenough