aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/me/shedaniel/rei/impl
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2020-07-08 22:49:27 +0800
committershedaniel <daniel@shedaniel.me>2020-07-08 22:49:27 +0800
commitddbedf6a7dc89176ab7797e5aaa10d6ea563f9a9 (patch)
tree3ecdb75f9c34c5cba27c15ee84d845aaa654eb2e /src/main/java/me/shedaniel/rei/impl
parent1189bcf3a46777239462da0dc45aa088697fec40 (diff)
downloadRoughlyEnoughItems-ddbedf6a7dc89176ab7797e5aaa10d6ea563f9a9.tar.gz
RoughlyEnoughItems-ddbedf6a7dc89176ab7797e5aaa10d6ea563f9a9.tar.bz2
RoughlyEnoughItems-ddbedf6a7dc89176ab7797e5aaa10d6ea563f9a9.zip
Custom Filtering Rules
Signed-off-by: shedaniel <daniel@shedaniel.me>
Diffstat (limited to 'src/main/java/me/shedaniel/rei/impl')
-rw-r--r--src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java19
-rw-r--r--src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java11
-rw-r--r--src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java14
-rw-r--r--src/main/java/me/shedaniel/rei/impl/SearchArgument.java11
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/AbstractFilteringRule.java40
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java52
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java63
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextType.java34
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/FilteringResult.java67
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/FilteringResultImpl.java52
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/FilteringRule.java92
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java92
-rw-r--r--src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java172
-rw-r--r--src/main/java/me/shedaniel/rei/impl/search/Argument.java2
-rw-r--r--src/main/java/me/shedaniel/rei/impl/search/ArgumentsRegistry.java22
15 files changed, 728 insertions, 15 deletions
diff --git a/src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java b/src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java
index 6ffe07b06..79b4ccfd2 100644
--- a/src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java
+++ b/src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java
@@ -23,6 +23,7 @@
package me.shedaniel.rei.impl;
+import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
@@ -49,6 +50,8 @@ import me.shedaniel.rei.gui.config.entry.NoFilteringEntry;
import me.shedaniel.rei.gui.config.entry.RecipeScreenTypeEntry;
import me.shedaniel.rei.gui.config.entry.ReloadPluginsEntry;
import me.shedaniel.rei.gui.credits.CreditsScreen;
+import me.shedaniel.rei.impl.filtering.FilteringRule;
+import me.shedaniel.rei.impl.filtering.rules.ManualFilteringRule;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
@@ -58,6 +61,8 @@ import net.minecraft.client.gui.screen.ScreenTexts;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.StringNbtReader;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
@@ -97,6 +102,15 @@ public class ConfigManagerImpl implements ConfigManager {
return new JsonPrimitive(gson.toJson(stack.toJson()));
}).registerPrimitiveTypeAdapter(EntryStack.class, it -> {
return it instanceof String ? EntryStack.readFromJson(gson.fromJson((String) it, JsonElement.class)) : null;
+ }).registerSerializer(FilteringRule.class, (rule, marshaller) -> {
+ return new JsonPrimitive(FilteringRule.toTag(rule, new CompoundTag()).toString());
+ }).registerPrimitiveTypeAdapter(FilteringRule.class, it -> {
+ try {
+ return it instanceof String ? FilteringRule.fromTag(StringNbtReader.parse((String) it)) : null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
}).build()));
GuiRegistry guiRegistry = AutoConfig.getGuiRegistry(ConfigObjectImpl.class);
guiRegistry.registerPredicateProvider((i13n, field, config, defaults, guiProvider) -> {
@@ -120,7 +134,7 @@ public class ConfigManagerImpl implements ConfigManager {
REIHelper.getInstance().getPreviousContainerScreen() == null || MinecraftClient.getInstance().getNetworkHandler() == null || MinecraftClient.getInstance().getNetworkHandler().getRecipeManager() == null ?
Collections.singletonList(new NoFilteringEntry(220, getUnsafely(field, config, new ArrayList<>()), getUnsafely(field, defaults), list -> setUnsafely(field, config, list)))
:
- Collections.singletonList(new FilteringEntry(220, getUnsafely(field, config, new ArrayList<>()), getUnsafely(field, defaults), list -> setUnsafely(field, config, list)))
+ Collections.singletonList(new FilteringEntry(220, getUnsafely(field, config, new ArrayList<>()), ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules, getUnsafely(field, defaults), list -> setUnsafely(field, config, list), list -> ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules = Lists.newArrayList(list)))
, (field) -> field.getType() == List.class, ConfigObjectImpl.UseFilteringScreen.class);
saveConfig();
RoughlyEnoughItemsCore.LOGGER.info("Config loaded.");
@@ -136,6 +150,9 @@ public class ConfigManagerImpl implements ConfigManager {
stack.setting(EntryStack.Settings.CHECK_AMOUNT, EntryStack.Settings.FALSE).setting(EntryStack.Settings.RENDER_COUNTS, EntryStack.Settings.FALSE).setting(EntryStack.Settings.CHECK_TAGS, EntryStack.Settings.TRUE);
}
}
+ if (getConfig().getFilteringRules().stream().noneMatch(filteringRule -> filteringRule instanceof ManualFilteringRule)) {
+ getConfig().getFilteringRules().add(new ManualFilteringRule());
+ }
((me.sargunvohra.mcmods.autoconfig1u.ConfigManager<ConfigObjectImpl>) AutoConfig.getConfigHolder(ConfigObjectImpl.class)).save();
}
diff --git a/src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java b/src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java
index df030349a..0945283dd 100644
--- a/src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java
+++ b/src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java
@@ -32,6 +32,7 @@ import me.shedaniel.clothconfig2.api.ModifierKeyCode;
import me.shedaniel.rei.api.ConfigObject;
import me.shedaniel.rei.api.EntryStack;
import me.shedaniel.rei.gui.config.*;
+import me.shedaniel.rei.impl.filtering.FilteringRule;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.util.InputUtil;
@@ -56,7 +57,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
@ConfigEntry.Category("functionality") @ConfigEntry.Gui.TransitiveObject @DontApplyFieldName
private Functionality functionality = new Functionality();
@ConfigEntry.Category("advanced") @ConfigEntry.Gui.TransitiveObject @DontApplyFieldName
- private Advanced advanced = new Advanced();
+ public Advanced advanced = new Advanced();
@Override
public boolean isOverlayVisible() {
@@ -304,6 +305,11 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
}
@Override
+ public List<FilteringRule<?>> getFilteringRules() {
+ return advanced.filtering.filteringRules;
+ }
+
+ @Override
@ApiStatus.Experimental
public boolean shouldAsyncSearch() {
return advanced.search.asyncSearch;
@@ -414,7 +420,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
@ConfigEntry.Gui.CollapsibleObject
private Miscellaneous miscellaneous = new Miscellaneous();
@ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
- private Filtering filtering = new Filtering();
+ public Filtering filtering = new Filtering();
public static class Tooltips {
@Comment("Declares whether REI should append mod names to entries.") private boolean appendModNames = true;
@@ -465,6 +471,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
public static class Filtering {
@UseFilteringScreen private List<EntryStack> filteredStacks = new ArrayList<>();
+ @ConfigEntry.Gui.Excluded public List<FilteringRule<?>> filteringRules = new ArrayList<>();
}
}
}
diff --git a/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java b/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java
index 5dfa05331..b3274ae94 100644
--- a/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java
+++ b/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java
@@ -31,6 +31,10 @@ import me.shedaniel.rei.api.ConfigObject;
import me.shedaniel.rei.api.EntryRegistry;
import me.shedaniel.rei.api.EntryStack;
import me.shedaniel.rei.api.RecipeHelper;
+import me.shedaniel.rei.impl.filtering.FilteringContextImpl;
+import me.shedaniel.rei.impl.filtering.FilteringRule;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Pair;
@@ -42,6 +46,7 @@ import java.util.*;
import java.util.stream.Collectors;
@ApiStatus.Internal
+@Environment(EnvType.CLIENT)
public class EntryRegistryImpl implements EntryRegistry {
private final List<EntryStack> preFilteredList = Lists.newCopyOnWriteArrayList();
@@ -117,14 +122,19 @@ public class EntryRegistryImpl implements EntryRegistry {
public void refilter() {
long started = System.currentTimeMillis();
- Collection<EntryStack> filteredStacks = ConfigObject.getInstance().getFilteredStacks();
+ FilteringContextImpl context = new FilteringContextImpl(getStacksList());
+ List<FilteringRule<?>> rules = ConfigObject.getInstance().getFilteringRules();
+ for (int i = rules.size() - 1; i >= 0; i--) {
+ context.handleResult(rules.get(i).processFilteredStacks(context));
+ }
preFilteredList.clear();
+ Collection<EntryStack> filteredStacks = context.getHiddenStacks();
for (EntryStack stack : getStacksList()) {
if (findFirstOrNullEqualsEntryIgnoreAmount(filteredStacks, stack) == null)
preFilteredList.add(stack);
}
long time = System.currentTimeMillis() - started;
- RoughlyEnoughItemsCore.LOGGER.info("Refiltered %d entries in %dms.", filteredStacks.size(), time);
+ RoughlyEnoughItemsCore.LOGGER.info("Refiltered %d entries with %d rules in %dms.", filteredStacks.size(), rules.size(), time);
}
public void reset() {
diff --git a/src/main/java/me/shedaniel/rei/impl/SearchArgument.java b/src/main/java/me/shedaniel/rei/impl/SearchArgument.java
index 52696a2b8..ffeb1f439 100644
--- a/src/main/java/me/shedaniel/rei/impl/SearchArgument.java
+++ b/src/main/java/me/shedaniel/rei/impl/SearchArgument.java
@@ -33,6 +33,8 @@ import me.shedaniel.rei.impl.search.Argument;
import me.shedaniel.rei.impl.search.ArgumentsRegistry;
import me.shedaniel.rei.impl.search.MatchStatus;
import me.shedaniel.rei.utils.CollectionUtils;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text;
import org.apache.commons.lang3.StringUtils;
@@ -44,6 +46,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ApiStatus.Internal
+@Environment(EnvType.CLIENT)
public class SearchArgument {
public static final String SPACE = " ", EMPTY = "";
private static final SearchArgument ALWAYS = new SearchArgument(AlwaysMatchingArgument.INSTANCE, EMPTY, true);
@@ -72,7 +75,7 @@ public class SearchArgument {
List<SearchArgument> arguments = Lists.newArrayList();
while (terms.find()) {
String term = MoreObjects.firstNonNull(terms.group(1), terms.group(2));
- for (Argument argument : ArgumentsRegistry.ARGUMENTS) {
+ for (Argument argument : ArgumentsRegistry.ARGUMENT_LIST) {
MatchStatus status = argument.matchesArgumentPrefix(term);
if (status.isMatched()) {
arguments.add(new SearchArgument(argument, status.getText(), !status.isInverted(), !status.shouldPreserveCasing()));
@@ -99,7 +102,7 @@ public class SearchArgument {
if (searchArguments.isEmpty())
return true;
MinecraftClient minecraft = MinecraftClient.getInstance();
- Object[] data = new Object[ArgumentsRegistry.ARGUMENTS.size()];
+ Object[] data = new Object[ArgumentsRegistry.ARGUMENT_LIST.size()];
for (SearchArgument.SearchArguments arguments : searchArguments) {
boolean applicable = true;
for (SearchArgument argument : arguments.getArguments()) {
@@ -149,6 +152,10 @@ public class SearchArgument {
public SearchArgument[] getArguments() {
return arguments;
}
+
+ public final boolean isAlways() {
+ return this == ALWAYS;
+ }
}
}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/AbstractFilteringRule.java b/src/main/java/me/shedaniel/rei/impl/filtering/AbstractFilteringRule.java
new file mode 100644
index 000000000..0cd4b523d
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/AbstractFilteringRule.java
@@ -0,0 +1,40 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.filtering;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+
+@Environment(EnvType.CLIENT)
+public abstract class AbstractFilteringRule<T extends AbstractFilteringRule<?>> implements FilteringRule<T> {
+ @Override
+ public boolean equals(Object obj) {
+ return getClass() == obj.getClass();
+ }
+
+ @Override
+ public int hashCode() {
+ return getClass().hashCode();
+ }
+}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java
new file mode 100644
index 000000000..f6066597b
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java
@@ -0,0 +1,52 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.filtering;
+
+import me.shedaniel.rei.api.EntryStack;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.Map;
+import java.util.Set;
+
+@ApiStatus.Internal
+@ApiStatus.Experimental
+public interface FilteringContext {
+ Map<FilteringContextType, Set<EntryStack>> getStacks();
+
+ default Set<EntryStack> getStacks(FilteringContextType type) {
+ return getStacks().get(type);
+ }
+
+ default Set<EntryStack> getShownStacks() {
+ return getStacks(FilteringContextType.SHOWN);
+ }
+
+ default Set<EntryStack> getUnsetStacks() {
+ return getStacks(FilteringContextType.DEFAULT);
+ }
+
+ default Set<EntryStack> getHiddenStacks() {
+ return getStacks(FilteringContextType.HIDDEN);
+ }
+}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java
new file mode 100644
index 000000000..830593d62
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java
@@ -0,0 +1,63 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.filtering;
+
+import com.google.common.collect.Maps;
+import me.shedaniel.rei.api.EntryStack;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+
+import java.util.*;
+
+@Environment(EnvType.CLIENT)
+public class FilteringContextImpl implements FilteringContext {
+ private final Map<FilteringContextType, Set<EntryStack>> stacks;
+
+ public FilteringContextImpl(List<EntryStack> allStacks) {
+ this(Maps.newHashMap());
+ getUnsetStacks().addAll(allStacks);
+ }
+
+ public FilteringContextImpl(Map<FilteringContextType, Set<EntryStack>> stacks) {
+ this.stacks = stacks;
+ for (FilteringContextType type : FilteringContextType.values()) {
+ this.stacks.computeIfAbsent(type, t -> new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount)));
+ }
+ }
+
+ @Override
+ public Map<FilteringContextType, Set<EntryStack>> getStacks() {
+ return stacks;
+ }
+
+ public void handleResult(FilteringResult result) {
+ getUnsetStacks().removeAll(result.getHiddenStacks());
+ getShownStacks().removeAll(result.getHiddenStacks());
+ getHiddenStacks().addAll(result.getHiddenStacks());
+
+ getHiddenStacks().removeAll(result.getShownStacks());
+ getUnsetStacks().removeAll(result.getShownStacks());
+ getShownStacks().addAll(result.getShownStacks());
+ }
+}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextType.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextType.java
new file mode 100644
index 000000000..72954da6e
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextType.java
@@ -0,0 +1,34 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.filtering;
+
+public enum FilteringContextType {
+ SHOWN,
+ DEFAULT,
+ HIDDEN;
+
+ public boolean isHidden() {
+ return this == HIDDEN;
+ }
+}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResult.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResult.java
new file mode 100644
index 000000000..e0d0df1bc
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResult.java
@@ -0,0 +1,67 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.filtering;
+
+import com.google.common.collect.Lists;
+import me.shedaniel.rei.api.EntryStack;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+@ApiStatus.Internal
+@ApiStatus.Experimental
+public interface FilteringResult {
+ static FilteringResult create() {
+ return create(Lists.newArrayList(), Lists.newArrayList());
+ }
+
+ static FilteringResult create(List<EntryStack> hiddenStacks, List<EntryStack> shownStacks) {
+ return new FilteringResultImpl(hiddenStacks, shownStacks);
+ }
+
+ Set<EntryStack> getHiddenStacks();
+
+ Set<EntryStack> getShownStacks();
+
+ default FilteringResult hide(EntryStack stack) {
+ return hide(Collections.singletonList(stack));
+ }
+
+ default FilteringResult hide(Collection<EntryStack> stacks) {
+ getHiddenStacks().addAll(stacks);
+ return this;
+ }
+
+ default FilteringResult show(EntryStack stack) {
+ return show(Collections.singletonList(stack));
+ }
+
+ default FilteringResult show(Collection<EntryStack> stacks) {
+ getShownStacks().addAll(stacks);
+ return this;
+ }
+}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResultImpl.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResultImpl.java
new file mode 100644
index 000000000..a848fcd7d
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResultImpl.java
@@ -0,0 +1,52 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.filtering;
+
+import me.shedaniel.rei.api.EntryStack;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class FilteringResultImpl implements FilteringResult {
+ private final Set<EntryStack> hiddenStacks, shownStacks;
+
+ public FilteringResultImpl(List<EntryStack> hiddenStacks, List<EntryStack> shownStacks) {
+ this.hiddenStacks = new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount));
+ this.shownStacks = new TreeSet<>(Comparator.comparing(EntryStack::hashIgnoreAmount));
+ this.hiddenStacks.addAll(hiddenStacks);
+ this.shownStacks.addAll(shownStacks);
+ }
+
+ @Override
+ public Set<EntryStack> getHiddenStacks() {
+ return hiddenStacks;
+ }
+
+ @Override
+ public Set<EntryStack> getShownStacks() {
+ return shownStacks;
+ }
+}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/FilteringRule.java b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringRule.java
new file mode 100644
index 000000000..315c49d58
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/FilteringRule.java
@@ -0,0 +1,92 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.filtering;
+
+import com.mojang.serialization.Lifecycle;
+import me.shedaniel.rei.gui.config.entry.FilteringEntry;
+import me.shedaniel.rei.impl.filtering.rules.ManualFilteringRule;
+import me.shedaniel.rei.impl.filtering.rules.SearchFilteringRule;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.registry.Registry;
+import net.minecraft.util.registry.RegistryKey;
+import net.minecraft.util.registry.SimpleRegistry;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+@ApiStatus.Internal
+@ApiStatus.Experimental
+@Environment(EnvType.CLIENT)
+public interface FilteringRule<T extends FilteringRule<?>> {
+ RegistryKey<Registry<FilteringRule<?>>> REGISTRY_KEY = RegistryKey.ofRegistry(new Identifier("roughlyenoughitems", "filtering_rule"));
+ Registry<FilteringRule<?>> REGISTRY = createRegistry();
+
+ @ApiStatus.Internal
+ static Registry<FilteringRule<?>> createRegistry() {
+ SimpleRegistry<FilteringRule<?>> registry = new SimpleRegistry<>(REGISTRY_KEY, Lifecycle.stable());
+ Registry.register(registry, new Identifier("roughlyenoughitems", "search"), new SearchFilteringRule());
+ Registry.register(registry, new Identifier("roughlyenoughitems", "manual"), new ManualFilteringRule());
+ return registry;
+ }
+
+ static CompoundTag toTag(FilteringRule<?> rule, CompoundTag tag) {
+ tag.putString("id", REGISTRY.getId(rule).toString());
+ tag.put("rule", rule.toTag(new CompoundTag()));
+ return tag;
+ }
+
+ static FilteringRule<?> fromTag(CompoundTag tag) {
+ return REGISTRY.get(Identifier.tryParse(tag.getString("id"))).createFromTag(tag.getCompound("rule"));
+ }
+
+ CompoundTag toTag(CompoundTag tag);
+
+ T createFromTag(CompoundTag tag);
+
+ @NotNull
+ FilteringResult processFilteredStacks(@NotNull FilteringContext context);
+
+ @ApiStatus.Internal
+ default Optional<BiFunction<FilteringEntry, Screen, Screen>> createEntryScreen() {
+ return Optional.empty();
+ }
+
+ default Text getTitle() {
+ return Text.method_30163(FilteringRule.REGISTRY.getId(this).toString());
+ }
+
+ default Text getSubtitle() {
+ return Text.method_30163(null);
+ }
+
+ T createNew();
+}
diff --git a/src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java b/src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java
new file mode 100644
index 000000000..a3b176168
--- /dev/null
+++ b/src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java
@@ -0,0 +1,92 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY K