From 92264d510b0e4f66719c970b2dbf21b495cfded1 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 6 Nov 2021 13:34:57 +0800 Subject: Fix #647 --- .../rei/api/client/config/ConfigObject.java | 5 + .../client/config/entry/EntryStackProvider.java | 120 +++++++++++++++++++++ .../rei/api/client/gui/SimpleDisplayRenderer.java | 1 - .../rei/api/common/util/CollectionUtils.java | 4 + .../rei/impl/client/config/ConfigManagerImpl.java | 45 ++++---- .../rei/impl/client/config/ConfigObjectImpl.java | 10 +- .../entry/filtering/rules/ManualFilteringRule.java | 3 +- .../entries/EntryStackSubsetsMenuEntry.java | 16 +-- .../gui/modules/entries/SubSubsetsMenuEntry.java | 12 +-- .../impl/common/entry/type/EntryRegistryImpl.java | 9 ++ 10 files changed, 186 insertions(+), 39 deletions(-) create mode 100644 api/src/main/java/me/shedaniel/rei/api/client/config/entry/EntryStackProvider.java diff --git a/api/src/main/java/me/shedaniel/rei/api/client/config/ConfigObject.java b/api/src/main/java/me/shedaniel/rei/api/client/config/ConfigObject.java index 20165ffc1..040704236 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/config/ConfigObject.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/config/ConfigObject.java @@ -24,6 +24,7 @@ package me.shedaniel.rei.api.client.config; import me.shedaniel.clothconfig2.api.ModifierKeyCode; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.config.*; import me.shedaniel.rei.api.common.entry.EntryStack; @@ -142,8 +143,12 @@ public interface ConfigObject { @ApiStatus.Experimental List getFavoriteEntries(); + @ApiStatus.ScheduledForRemoval + @Deprecated List> getFilteredStacks(); + List> getFilteredStackProviders(); + @ApiStatus.Experimental boolean shouldAsyncSearch(); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/config/entry/EntryStackProvider.java b/api/src/main/java/me/shedaniel/rei/api/client/config/entry/EntryStackProvider.java new file mode 100644 index 000000000..3f784b798 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/config/entry/EntryStackProvider.java @@ -0,0 +1,120 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021 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.api.client.config.entry; + +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import net.minecraft.nbt.CompoundTag; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Objects; + +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface EntryStackProvider { + EntryStack provide(); + + CompoundTag save(); + + boolean isValid(); + + static EntryStackProvider defer(CompoundTag tag) { + return new EntryStackProvider() { + private EntryStack stack; + + @Override + public EntryStack provide() { + if (stack == null) { + try { + stack = (EntryStack) EntryStack.read(tag); + } catch (Exception e) { + e.printStackTrace(); + return (EntryStack) EntryStack.empty(); + } + + stack = stack.normalize(); + } + + return stack; + } + + @Override + public CompoundTag save() { + return tag.copy(); + } + + @Override + public boolean isValid() { + return !provide().isEmpty(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof EntryStackProvider)) return false; + EntryStackProvider that = (EntryStackProvider) o; + return Objects.equals(provide(), that.provide()); + } + + @Override + public int hashCode() { + return Long.hashCode(EntryStacks.hashExact(provide())); + } + }; + } + + static EntryStackProvider ofStack(EntryStack stack) { + stack = stack.normalize(); + EntryStack finalStack = stack; + return new EntryStackProvider() { + @Override + public EntryStack provide() { + return finalStack; + } + + @Override + public CompoundTag save() { + return finalStack.save(); + } + + @Override + public boolean isValid() { + return !finalStack.isEmpty(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof EntryStackProvider)) return false; + EntryStackProvider that = (EntryStackProvider) o; + return Objects.equals(provide(), that.provide()); + } + + @Override + public int hashCode() { + return Long.hashCode(EntryStacks.hashExact(provide())); + } + }; + } +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java index 246a32979..ee8ecdbc6 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java @@ -45,7 +45,6 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; diff --git a/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java b/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java index 09511ac6f..4288ba4e5 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java @@ -162,6 +162,10 @@ public class CollectionUtils { return list.parallelStream().map(function).collect(Collectors.toCollection(supplier)); } + public static > C filterAndMapParallel(Collection list, Predicate filter, Function function, Supplier supplier) { + return list.parallelStream().filter(filter).map(function).collect(Collectors.toCollection(supplier)); + } + public static List map(T[] list, Function function) { List l = new ArrayList<>(list.length + 1); for (T t : list) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java index e6eefa6b6..231709cf0 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java @@ -49,6 +49,7 @@ import me.shedaniel.clothconfig2.gui.entries.TextListEntry; import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.config.DisplayScreenType; import me.shedaniel.rei.api.client.gui.config.SyntaxHighlightingMode; @@ -82,6 +83,7 @@ import org.apache.commons.lang3.mutable.MutableLong; import org.jetbrains.annotations.ApiStatus; import java.util.*; +import java.util.function.Consumer; import static me.shedaniel.autoconfig.util.Utils.getUnsafely; import static me.shedaniel.autoconfig.util.Utils.setUnsafely; @@ -116,11 +118,17 @@ public class ConfigManagerImpl implements ConfigManager { guiRegistry.registerAnnotationProvider((i13n, field, config, defaults, guiProvider) -> Collections.singletonList(new SearchFilterSyntaxHighlightingEntry(new TranslatableComponent(i13n), getUnsafely(field, config, SyntaxHighlightingMode.COLORFUL), getUnsafely(field, defaults), type -> setUnsafely(field, config, type))) , (field) -> field.getType() == SyntaxHighlightingMode.class, ConfigObjectImpl.UseSpecialSearchFilterSyntaxHighlightingScreen.class); - guiRegistry.registerAnnotationProvider((i13n, field, config, defaults, guiProvider) -> - REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().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<>()), ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules, getUnsafely(field, defaults), list -> setUnsafely(field, config, list), list -> ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules = Lists.newArrayList(list))) + guiRegistry.registerAnnotationProvider((i13n, field, config, defaults, guiProvider) -> { + List> value = CollectionUtils.map(Utils.>>getUnsafely(field, config, new ArrayList<>()), EntryStackProvider::provide); + List> defaultValue = CollectionUtils.map(Utils.>>getUnsafely(field, defaults), EntryStackProvider::provide); + Consumer>> saveConsumer = (newValue) -> { + setUnsafely(field, config, CollectionUtils.map(newValue, EntryStackProvider::ofStack)); + }; + return REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null ? + Collections.singletonList(new NoFilteringEntry(220, value, defaultValue, saveConsumer)) + : + Collections.singletonList(new FilteringEntry(220, value, ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules, defaultValue, saveConsumer, list -> ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules = Lists.newArrayList(list))); + } , (field) -> field.getType() == List.class, ConfigObjectImpl.UseFilteringScreen.class); saveConfig(); RoughlyEnoughItemsCore.LOGGER.info("Config loaded."); @@ -165,8 +173,8 @@ public class ConfigManagerImpl implements ConfigManager { } }); - // EntryStack - builder.registerSerializer(EntryStack.class, (stack, marshaller) -> { + // EntryStackProvider + builder.registerSerializer(EntryStackProvider.class, (stack, marshaller) -> { try { return marshaller.serialize(stack.save()); } catch (Exception e) { @@ -174,20 +182,15 @@ public class ConfigManagerImpl implements ConfigManager { return JsonNull.INSTANCE; } }); - builder.registerDeserializer(Tag.class, EntryStack.class, (value, marshaller) -> { - try { - return EntryStack.read((CompoundTag) value); - } catch (Exception e) { - e.printStackTrace(); - return EntryStack.empty(); - } + builder.registerDeserializer(Tag.class, EntryStackProvider.class, (value, marshaller) -> { + return EntryStackProvider.defer((CompoundTag) value); }); - builder.registerDeserializer(String.class, EntryStack.class, (value, marshaller) -> { + builder.registerDeserializer(String.class, EntryStackProvider.class, (value, marshaller) -> { try { - return EntryStack.read(TagParser.parseTag(value)); - } catch (Exception e) { + return EntryStackProvider.defer(TagParser.parseTag(value)); + } catch (CommandSyntaxException e) { e.printStackTrace(); - return EntryStack.empty(); + return EntryStackProvider.ofStack(EntryStack.empty()); } }); @@ -255,12 +258,6 @@ public class ConfigManagerImpl implements ConfigManager { if (getConfig().getFavoriteEntries() != null) { getConfig().getFavoriteEntries().removeIf(Objects::isNull); } - if (getConfig().getFilteredStacks() != null) { - getConfig().getFilteredStacks().removeIf(EntryStack::isEmpty); - List> normalizedFilteredStacks = CollectionUtils.map(getConfig().getFilteredStacks(), EntryStack::normalize); - getConfig().getFilteredStacks().clear(); - getConfig().getFilteredStacks().addAll(normalizedFilteredStacks); - } if (getConfig().getFilteringRules().stream().noneMatch(filteringRule -> filteringRule instanceof ManualFilteringRule)) { getConfig().getFilteringRules().add(new ManualFilteringRule()); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java index 3895bc4fc..096a49e8b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java @@ -32,9 +32,11 @@ import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; import me.shedaniel.clothconfig2.api.Modifier; import me.shedaniel.clothconfig2.api.ModifierKeyCode; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.config.*; import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.entry.filtering.FilteringRule; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -46,6 +48,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @ApiStatus.Internal @@ -303,6 +306,11 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @Override public List> getFilteredStacks() { + return Collections.unmodifiableList(CollectionUtils.map(advanced.filtering.filteredStacks, EntryStackProvider::provide)); + } + + @Override + public List> getFilteredStackProviders() { return advanced.filtering.filteredStacks; } @@ -541,7 +549,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { } public static class Filtering { - @UseFilteringScreen private List> filteredStacks = new ArrayList<>(); + @UseFilteringScreen private List> filteredStacks = new ArrayList<>(); @ConfigEntry.Gui.Excluded public List> filteringRules = new ArrayList<>(); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java index 480235778..c8fb61998 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java @@ -26,6 +26,7 @@ package me.shedaniel.rei.impl.client.entry.filtering.rules; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; @@ -59,7 +60,7 @@ public class ManualFilteringRule extends AbstractFilteringRule> stacks, FilteringResult result) { - LongSet filteredStacks = CollectionUtils.mapParallel(ConfigObject.getInstance().getFilteredStacks(), EntryStacks::hashExact, LongOpenHashSet::new); + LongSet filteredStacks = CollectionUtils.filterAndMapParallel(ConfigObject.getInstance().getFilteredStackProviders(), EntryStackProvider::isValid, provider -> EntryStacks.hashExact(provider.provide()), LongOpenHashSet::new); result.hide(stacks.parallelStream().filter(stack -> filteredStacks.contains(EntryStacks.hashExact(stack))).collect(Collectors.toList())); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java index cb34786bf..7ec5bd243 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EntryStackSubsetsMenuEntry.java @@ -30,9 +30,9 @@ import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; 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.REIRuntimeImpl; import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; @@ -96,11 +96,11 @@ public class EntryStackSubsetsMenuEntry extends MenuEntry { clickedLast = true; if (!getParent().scrolling.draggingScrollBar) { minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - List> filteredStacks = ConfigObject.getInstance().getFilteredStacks(); + List> filteredStacks = ConfigObject.getInstance().getFilteredStackProviders(); if (isFiltered()) { - filteredStacks.removeIf(next -> EntryStacks.equalsExact(next, stack)); + filteredStacks.removeIf(next -> EntryStacks.equalsExact(next.provide(), stack)); } else { - filteredStacks.add(stack.normalize()); + filteredStacks.add(EntryStackProvider.ofStack(stack.normalize())); } Menu menu = ((ScreenOverlayImpl) REIRuntime.getInstance().getOverlay().get()).getOverlayMenu(); if (menu != null) @@ -138,8 +138,12 @@ public class EntryStackSubsetsMenuEntry extends MenuEntry { public boolean isFiltered() { if (isFiltered == null) { - List> filteredStacks = ConfigObject.getInstance().getFilteredStacks(); - isFiltered = CollectionUtils.findFirstOrNullEqualsExact(filteredStacks, stack) != null; + isFiltered = false; + List> filteredStacks = ConfigObject.getInstance().getFilteredStackProviders(); + for (EntryStackProvider provider : filteredStacks) { + if (EntryStacks.equalsExact(provider.provide(), stack)) + return isFiltered = true; + } } return isFiltered; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java index 4ff812960..4481e3e28 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubSubsetsMenuEntry.java @@ -32,9 +32,9 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; -import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.REIRuntimeImpl; import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; @@ -152,7 +152,7 @@ public class SubSubsetsMenuEntry extends MenuEntry { if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12 && !entries.isEmpty()) { if (clickedBefore) { clickedBefore = false; - List> filteredStacks = ConfigObject.getInstance().getFilteredStacks(); + List> filteredStacks = ConfigObject.getInstance().getFilteredStackProviders(); Menu overlay = ((ScreenOverlayImpl) REIRuntime.getInstance().getOverlay().get()).getOverlayMenu(); setFiltered(filteredStacks, overlay, this, !(getFilteredRatio() > 0)); ConfigManager.getInstance().saveConfig(); @@ -169,14 +169,14 @@ public class SubSubsetsMenuEntry extends MenuEntry { return super.mouseClicked(mouseX, mouseY, button); } - private void setFiltered(List> filteredStacks, Menu subsetsMenu, SubSubsetsMenuEntry subSubsetsMenuEntry, boolean filtered) { + private void setFiltered(List> filteredStacks, Menu subsetsMenu, SubSubsetsMenuEntry subSubsetsMenuEntry, boolean filtered) { for (MenuEntry entry : subSubsetsMenuEntry.entries) { if (entry instanceof EntryStackSubsetsMenuEntry menuEntry) { if (menuEntry.isFiltered() != filtered) { if (!filtered) { - filteredStacks.removeIf(next -> EntryStacks.equalsExact(next, menuEntry.stack)); + filteredStacks.removeIf(next -> EntryStacks.equalsExact(next.provide(), menuEntry.stack)); } else { - filteredStacks.add(menuEntry.stack.normalize()); + filteredStacks.add(EntryStackProvider.ofStack(menuEntry.stack.normalize())); } } if (subsetsMenu != null) @@ -193,7 +193,7 @@ public class SubSubsetsMenuEntry extends MenuEntry { } public Tuple getFilteredRatioPair() { - List> filteredStacks = ConfigObject.getInstance().getFilteredStacks(); + List> filteredStacks = ConfigObject.getInstance().getFilteredStackProviders(); if (lastListHash != filteredStacks.hashCode()) { int size = 0; int filtered = 0; 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 272bd1944..1c6e9d67f 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 @@ -29,6 +29,7 @@ import com.google.common.collect.Lists; import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; @@ -119,6 +120,14 @@ public class EntryRegistryImpl implements EntryRegistry { @Override public void refilter() { + ConfigObject config = ConfigObject.getInstance(); + if (config.getFilteredStackProviders() != null) { + List> normalizedFilteredStacks = CollectionUtils.map(config.getFilteredStackProviders(), EntryStackProvider::provide); + normalizedFilteredStacks.removeIf(EntryStack::isEmpty); + config.getFilteredStackProviders().clear(); + config.getFilteredStackProviders().addAll(CollectionUtils.map(normalizedFilteredStacks, EntryStackProvider::ofStack)); + } + Stopwatch stopwatch = Stopwatch.createStarted(); FilteringContextImpl context = new FilteringContextImpl(entries); -- cgit From 7320342f4a5d499adfc0c50d2f19c69cbab3b1c6 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 6 Nov 2021 13:36:25 +0800 Subject: Remove -alpha properly --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1b8fa08a5..7da686f93 100755 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ import java.text.SimpleDateFormat archivesBaseName = "RoughlyEnoughItems" def runNumber = System.getenv("GITHUB_RUN_NUMBER") ?: "9999" -version = rootProject.base_version + "." + runNumber + (rootProject.unstable ? "-alpha" : "") +version = rootProject.base_version + "." + runNumber + (rootProject.unstable.toBoolean() ? "-alpha" : "") group = "me.shedaniel" -- cgit From ddab152ed614b14168373911aa239dd917c9621b Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 6 Nov 2021 19:08:47 +0800 Subject: Fix weird text for recipe ids --- .../java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java index 27e9e79a5..ca8b15437 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java @@ -183,7 +183,7 @@ public final class InternalWidgets { if (!locations.isEmpty()) { str.add(new TextComponent(" ")); for (ResourceLocation location : locations) { - String t = I18n.get("text.rei.recipe_id", "", new TextComponent(location.toString()).withStyle(ChatFormatting.GRAY)); + String t = I18n.get("text.rei.recipe_id", "", location.toString()); if (t.startsWith("\n")) { t = t.substring("\n".length()); } -- cgit From d1e91e2e2ffa317a52e659f2ca2b76800108f427 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 6 Nov 2021 19:14:30 +0800 Subject: Fix JEI slot overlay, normalize dragging stacks and fix #651 --- .../main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java | 2 +- .../rei/impl/client/entry/filtering/rules/SearchFilteringRule.java | 2 +- .../java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java | 4 +++- .../java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java b/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java index 4288ba4e5..aa4ac5037 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java @@ -315,7 +315,7 @@ public class CollectionUtils { @Override public T get(int index) { if (index < 0 || index >= realSize) - throw new IndexOutOfBoundsException(String.format("Index %s out of bounds for length %s", index, realSize)); + return null; return list.get(cursor + index); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java index 6a17af517..9e00dec60 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java @@ -113,7 +113,7 @@ public class SearchFilteringRule extends AbstractFilteringRule { List> output = Lists.newArrayList(); for (EntryStack stack : partitionStacks) { - if (filter.test(stack)) { + if (stack != null && filter.test(stack)) { output.add(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 f1693459b..69adad877 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 @@ -473,7 +473,9 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget { public DraggableStack getHoveredStack(DraggingContext context, double mouseX, double mouseY) { if (!getCurrentEntry().isEmpty() && containsMouse(mouseX, mouseY)) { return new DraggableStack() { - EntryStack stack = getCurrentEntry().copy(); + EntryStack stack = getCurrentEntry().copy() + .removeSetting(EntryStack.Settings.RENDERER) + .removeSetting(EntryStack.Settings.FLUID_RENDER_RATIO); @Override public EntryStack getStack() { 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 2d0929f03..2a431e8ee 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 @@ -103,7 +103,7 @@ public class AsyncSearchManager { futures.add(CompletableFuture.supplyAsync(() -> { List> filtered = Lists.newArrayList(); for (EntryStack stack : partitionStacks) { - if (matches(stack) && additionalPredicate.test(stack)) { + if (stack != null && matches(stack) && additionalPredicate.test(stack)) { filtered.add(transformer.apply(stack)); } } -- cgit From f8fc41207ca444c0a90ae10d78a821831b245bc2 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 7 Nov 2021 16:21:34 +0800 Subject: Fix #654 --- .../me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java | 2 +- .../impl/client/gui/performance/PerformanceScreen.java | 6 +++++- .../logging/performance/PerformanceLoggerImpl.java | 6 ++++-- .../rei/impl/common/plugins/PluginManagerImpl.java | 4 ++++ .../client/runtime/PluginStageExecutionWatcher.java | 18 +++++++++++------- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index 094bbe4ea..98f5aab24 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -380,7 +380,7 @@ public class RoughlyEnoughItemsCoreClient { public static void reloadPlugins(MutableLong lastReload, @Nullable ReloadStage start) { if (lastReload != null) { if (lastReload.getValue() > 0 && System.currentTimeMillis() - lastReload.getValue() <= 5000) { - RoughlyEnoughItemsCore.LOGGER.warn("Suppressing Reload Plugins!"); + RoughlyEnoughItemsCore.LOGGER.warn("Suppressing Reload Plugins of stage " + start); return; } lastReload.setValue(System.currentTimeMillis()); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java index 92bfb78be..b6e5b5f92 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java @@ -150,7 +150,11 @@ public class PerformanceScreen extends Screen { inner.times().forEach((obj, time) -> { entries.add(new EntryListEntry(new TextComponent(obj instanceof Pair ? ((Pair, REIPlugin>) obj).getFirst().getPluginProviderName() : Objects.toString(obj)), time)); }); - long separateTime = inner.times().values().stream().collect(Collectors.summarizingLong(value -> value)).getSum(); + Collection values = inner.times().values(); + long separateTime; + synchronized (inner.times()) { + separateTime = values.stream().collect(Collectors.summarizingLong(value -> value)).getSum(); + } if ((inner.totalNano() - separateTime) > 1000000) { entries.add(new EntryListEntry(new TextComponent("Miscellaneous Operations"), inner.totalNano() - separateTime)); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java index 934bf494e..227d067c7 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java @@ -28,14 +28,16 @@ import com.google.common.collect.Maps; import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.Object2LongLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2LongMap; +import it.unimi.dsi.fastutil.objects.Object2LongMaps; import me.shedaniel.rei.api.common.plugins.REIPlugin; import me.shedaniel.rei.api.common.plugins.REIPluginProvider; +import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; public class PerformanceLoggerImpl implements PerformanceLogger { - private final Map stages = Maps.newLinkedHashMap(); + private final Map stages = Collections.synchronizedMap(Maps.newLinkedHashMap()); @Override public Plugin stage(String stage) { @@ -52,7 +54,7 @@ public class PerformanceLoggerImpl implements PerformanceLogger { private static class PluginImpl implements Plugin { private final Stopwatch stopwatch = Stopwatch.createUnstarted(); private long totalTime = 0; - private Object2LongMap times = new Object2LongLinkedOpenHashMap<>(); + private Object2LongMap times = Object2LongMaps.synchronize(new Object2LongLinkedOpenHashMap<>()); @Override public Inner stage(String stage) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java index 71b1cb716..bda591fb1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java @@ -213,6 +213,8 @@ public class PluginManagerImpl

> implements PluginManager< ((REIPlugin

) plugin.plugin).preStage(this, stage); } }); + } catch (Throwable throwable) { + new RuntimeException("Failed to run pre registration").printStackTrace(); } } @@ -229,6 +231,8 @@ public class PluginManagerImpl

> implements PluginManager< ((REIPlugin

) plugin.plugin).postStage(this, stage); } }); + } catch (Throwable throwable) { + new RuntimeException("Failed to run post registration").printStackTrace(); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java index 10326394c..86eddd5c0 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java @@ -40,7 +40,7 @@ import java.util.*; import java.util.stream.Collectors; public class PluginStageExecutionWatcher implements HintProvider { - private Map, Set> allStages = new HashMap<>(); + private final Map, Set> allStages = new HashMap<>(); public > Reloadable reloadable(PluginManager manager) { return new Reloadable<>() { @@ -53,17 +53,21 @@ public class PluginStageExecutionWatcher implements HintProvider { @Override public void startReload(ReloadStage stage) { - Set stages = allStages.computeIfAbsent(manager, $ -> new HashSet<>()); - if (stage.ordinal() == 0) stages.clear(); - stages.add(stage); + synchronized (allStages) { + Set stages = allStages.computeIfAbsent(manager, $ -> new HashSet<>()); + if (stage.ordinal() == 0) stages.clear(); + stages.add(stage); + } } }; } public Set notVisited() { - Set notVisited = new HashSet<>(Arrays.asList(ReloadStage.values())); - notVisited.removeIf(stage -> allStages.values().stream().allMatch(stages -> stages.contains(stage))); - return notVisited; + synchronized (allStages) { + Set notVisited = new HashSet<>(Arrays.asList(ReloadStage.values())); + notVisited.removeIf(stage -> allStages.values().stream().allMatch(stages -> stages.contains(stage))); + return notVisited; + } } @Override -- cgit From 7879ac1cc61876bfa0578e34a96239830530a00b Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 7 Nov 2021 18:01:38 +0800 Subject: Modularize region rendering --- .../me/shedaniel/rei/api/client/REIRuntime.java | 8 +- .../rei/api/client/entry/region/RegionEntry.java | 61 ++ .../rei/api/client/favorites/FavoriteEntry.java | 26 +- .../rei/RoughlyEnoughItemsCoreClient.java | 1 + .../shedaniel/rei/impl/client/REIRuntimeImpl.java | 6 +- .../impl/client/gui/craftable/CraftableFilter.java | 2 +- .../impl/client/gui/widget/EntryListWidget.java | 2 +- .../client/gui/widget/EntryStacksRegionWidget.java | 451 +++++++++++++++ .../client/gui/widget/FavoritesListWidget.java | 624 ++------------------- .../client/gui/widget/region/RealRegionEntry.java | 93 +++ .../gui/widget/region/RegionDraggableStack.java | 71 +++ .../gui/widget/region/RegionEntryListEntry.java | 143 +++++ .../client/gui/widget/region/RegionListener.java | 41 ++ .../client/registry/screen/ScreenRegistryImpl.java | 1 + .../comparison/EntryComparatorRegistryImpl.java | 8 +- 15 files changed, 961 insertions(+), 577 deletions(-) create mode 100644 api/src/main/java/me/shedaniel/rei/api/client/entry/region/RegionEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryStacksRegionWidget.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionEntryListEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java diff --git a/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java b/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java index 354c1ce19..adc1cb968 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java @@ -54,10 +54,14 @@ public interface REIRuntime extends Reloadable { void toggleOverlayVisible(); default Optional getOverlay() { - return getOverlay(false); + return getOverlay(false, false); } - Optional getOverlay(boolean reset); + default Optional getOverlay(boolean reset) { + return getOverlay(reset, true); + } + + Optional getOverlay(boolean reset, boolean init); @Nullable AbstractContainerScreen getPreviousContainerScreen(); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/entry/region/RegionEntry.java b/api/src/main/java/me/shedaniel/rei/api/client/entry/region/RegionEntry.java new file mode 100644 index 000000000..c36a9444b --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/entry/region/RegionEntry.java @@ -0,0 +1,61 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021 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.api.client.entry.region; + +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.common.entry.EntryStack; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Supplier; + +@ApiStatus.Experimental +@ApiStatus.Internal +public interface RegionEntry> { + EntryStack toStack(); + + T copy(); + + default FavoriteEntry asFavorite() { + FavoriteEntry entry = FavoriteEntry.fromEntryStack(copy().toStack().normalize()); + return entry.isInvalid() ? null : entry; + } + + default boolean isEntryInvalid() { + return false; + } + + default Optional>> getMenuEntries() { + return Optional.empty(); + } + + UUID getUuid(); + + default boolean doAction(int button) { + return false; + } +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java index 856cea841..493f2ddd3 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java @@ -25,13 +25,16 @@ package me.shedaniel.rei.api.client.favorites; import com.mojang.serialization.DataResult; import com.mojang.serialization.Lifecycle; +import me.shedaniel.rei.api.client.entry.region.RegionEntry; import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.util.ClientEntryStacks; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.impl.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -41,7 +44,7 @@ import java.util.UUID; import java.util.function.Supplier; @Environment(EnvType.CLIENT) -public abstract class FavoriteEntry { +public abstract class FavoriteEntry implements RegionEntry { public static final String TYPE_KEY = "type"; private final UUID uuid = UUID.randomUUID(); @@ -71,15 +74,23 @@ public abstract class FavoriteEntry { return delegateResult(() -> FavoriteEntryType.registry().get(FavoriteEntryType.ENTRY_STACK).fromArgsResult(stack), null); } + @ApiStatus.ScheduledForRemoval + @Deprecated public static boolean isEntryInvalid(@Nullable FavoriteEntry entry) { return entry == null || entry.isInvalid(); } + @Override + public boolean isEntryInvalid() { + return isInvalid(); + } + public CompoundTag save(CompoundTag tag) { tag.putString(TYPE_KEY, getType().toString()); return Objects.requireNonNull(Objects.requireNonNull(FavoriteEntryType.registry().get(getType())).save(this, tag)); } + @Override public UUID getUuid() { return uuid; } @@ -88,14 +99,17 @@ public abstract class FavoriteEntry { public abstract Renderer getRenderer(boolean showcase); + @Override public abstract boolean doAction(int button); + @Override public Optional>> getMenuEntries() { return Optional.empty(); } public abstract long hashIgnoreAmount(); + @Override public abstract FavoriteEntry copy(); public abstract ResourceLocation getType(); @@ -127,4 +141,14 @@ public abstract class FavoriteEntry { public FavoriteEntry getUnwrapped() { return this; } + + @Override + public EntryStack toStack() { + return ClientEntryStacks.of(getRenderer(false)); + } + + @Override + public FavoriteEntry asFavorite() { + return copy(); + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index 98f5aab24..2069d8139 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -283,6 +283,7 @@ public class RoughlyEnoughItemsCoreClient { reloadPlugins(endReload, Platform.isFabric() ? ReloadStage.END : null); }); ClientGuiEvent.INIT_POST.register((screen, access) -> { + REIRuntime.getInstance().getOverlay(false, true); REIRuntimeImpl.getInstance().setPreviousScreen(screen); if (ConfigObject.getInstance().doesDisableRecipeBook() && screen instanceof AbstractContainerScreen) { access.getRenderables().removeIf(widget -> widget instanceof ImageButton button && button.resourceLocation.equals(recipeButtonTex)); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java index e80e5f572..b674d0099 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java @@ -137,8 +137,8 @@ public class REIRuntimeImpl implements REIRuntime { } @Override - public Optional getOverlay(boolean reset) { - if (overlay == null || reset) { + public Optional getOverlay(boolean reset, boolean init) { + if ((overlay == null && init) || reset) { overlay = new ScreenOverlayImpl(); overlay.init(); getSearchField().setFocused(false); @@ -240,7 +240,7 @@ public class REIRuntimeImpl implements REIRuntime { return EventResult.pass(); }); ClientTickEvent.CLIENT_POST.register(minecraft -> { - if (isOverlayVisible()) { + if (isOverlayVisible() && REIRuntime.getInstance().getOverlay().isPresent()) { ScreenOverlayImpl.getInstance().tick(); } }); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java index 0bd0765d8..f0f8a47c1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java @@ -48,7 +48,7 @@ public class CraftableFilter { return true; } - return Minecraft.getInstance().player.containerMenu != null; + return false; } public void tick() { 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 0bc72e96f..f992145bc 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 @@ -420,7 +420,7 @@ public class EntryListWidget extends WidgetWithBounds implements OverlayListWidg } FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); if (favoritesListWidget != null) { - favoritesListWidget.updateEntriesPosition(entry -> true); + favoritesListWidget.getRegion().updateEntriesPosition(entry -> true); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryStacksRegionWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryStacksRegionWidget.java new file mode 100644 index 000000000..f403ef6fe --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryStacksRegionWidget.java @@ -0,0 +1,451 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021 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.client.gui.widget; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import me.shedaniel.clothconfig2.ClothConfigInitializer; +import me.shedaniel.clothconfig2.api.ScissorsHandler; +import me.shedaniel.clothconfig2.api.ScrollingContainer; +import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.math.impl.PointHelper; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.entry.region.RegionEntry; +import me.shedaniel.rei.api.client.gui.drag.DraggableStack; +import me.shedaniel.rei.api.client.gui.drag.DraggableStackVisitorWidget; +import me.shedaniel.rei.api.client.gui.drag.DraggingContext; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.common.entry.EntrySerializer; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; +import me.shedaniel.rei.impl.client.gui.widget.region.RegionDraggableStack; +import me.shedaniel.rei.impl.client.gui.widget.region.RegionEntryListEntry; +import me.shedaniel.rei.impl.client.gui.widget.region.RegionListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.util.Mth; +import net.minecraft.util.Tuple; +import net.minecraft.util.Unit; +import org.jetbrains.annotations.Nullable; + +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static me.shedaniel.rei.impl.client.gui.widget.EntryListWidget.entrySize; +import static me.shedaniel.rei.impl.client.gui.widget.EntryListWidget.notSteppingOnExclusionZones; + +public class EntryStacksRegionWidget> extends WidgetWithBounds implements DraggableStackVisitorWidget { + private final RegionListener listener; + protected int blockedCount; + private Rectangle bounds = new Rectangle(), innerBounds; + protected final ScrollingContainer scrolling = new ScrollingContainer() { + @Override + public Rectangle getBounds() { + return EntryStacksRegionWidget.this.getBounds(); + } + + @Override + public int getMaxScrollHeight() { + return Mth.ceil((entries.size() + blockedCount) / (innerBounds.width / (float) entrySize())) * entrySize(); + } + + @Override + public int getScrollBarX() { + if (!ConfigObject.getInstance().isLeftHandSidePanel()) + return bounds.x + 1; + return bounds.getMaxX() - 7; + } + }; + private final Int2ObjectMap> entries = new Int2ObjectLinkedOpenHashMap<>(); + private final Int2ObjectMap> removedEntries = new Int2ObjectLinkedOpenHashMap<>(); + private List> entriesList = Lists.newArrayList(); + private List children = Lists.newArrayList(); + + public EntryStacksRegionWidget(RegionListener listener) { + this.listener = listener; + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + if (bounds.isEmpty()) return; + + int entrySize = entrySize(); + boolean fastEntryRendering = ConfigObject.getInstance().doesFastEntryRendering(); + updateEntriesPosition(entry -> true); + for (RealRegionEntry entry : entries.values()) { + entry.update(delta); + } + ObjectIterator> removedEntriesIterator = removedEntries.values().iterator(); + while (removedEntriesIterator.hasNext()) { + RealRegionEntry removedEntry = removedEntriesIterator.next(); + removedEntry.update(delta); + + if (removedEntry.size.doubleValue() <= 300) { + removedEntriesIterator.remove(); + this.entriesList.remove(removedEntry.getWidget()); + this.children.remove(removedEntry.getWidget()); + } + } + + ScissorsHandler.INSTANCE.scissor(bounds); + + Stream> entryStream = this.entriesList.stream() + .filter(entry -> entry.getBounds().getMaxY() >= this.bounds.getY() && entry.getBounds().y <= this.bounds.getMaxY()); + + new BatchedEntryRendererManager(entryStream.collect(Collectors.toList())) + .render(poses, mouseX, mouseY, delta); + + updatePosition(delta); + scrolling.renderScrollBar(0, 1, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); + ScissorsHandler.INSTANCE.removeLastScissor(); + } + + @Override + public List children() { + return children; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (scrolling.updateDraggingState(mouseX, mouseY, button)) { + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + if (containsMouse(mouseX, mouseY)) { + scrolling.offset(ClothConfigInitializer.getScrollStep() * -amount, true); + return true; + } + return super.mouseScrolled(mouseX, mouseY, amount); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (scrolling.mouseDragged(mouseX, mouseY, button, deltaX, deltaY, ConfigObject.getInstance().doesSnapToRows(), entrySize())) + return true; + return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + private void updatePosition(float delta) { + if (ConfigObject.getInstance().doesSnapToRows() && scrolling.scrollTarget >= 0 && scrolling.scrollTarget <= scrolling.getMaxScroll()) { + double nearestRow = Math.round(scrolling.scrollTarget / (double) entrySize()) * (double) entrySize(); + if (!DynamicNewSmoothScrollingEntryListWidget.Precision.almostEquals(scrolling.scrollTarget, nearestRow, DynamicNewSmoothScrollingEntryListWidget.Precision.FLOAT_EPSILON)) + scrolling.scrollTarget += (nearestRow - scrolling.scrollTarget) * Math.min(delta / 2.0, 1.0); + else + scrolling.scrollTarget = nearestRow; + } + scrolling.updatePosition(delta); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (containsMouse(PointHelper.ofMouse())) + for (Widget widget : children()) + if (widget.keyPressed(keyCode, scanCode, modifiers)) + return true; + return false; + } + + @Nullable + public DraggableStack getHoveredStack(DraggingContext context, double mouseX, double mouseY) { + if (innerBounds.contains(mouseX, mouseY)) { + for (RealRegionEntry entry : entries.values()) { + if (entry.getWidget().containsMouse(mouseX, mouseY)) { + return new RegionDraggableStack<>(entry, null); + } + } + } + return null; + } + + public EntryStack getFocusedStack() { + Point mouse = PointHelper.ofMouse(); + if (innerBounds.contains(mouse)) { + for (RealRegionEntry entry : entries.values()) { + if (entry.getWidget().containsMouse(mouse)) { + return entry.getWidget().getCurrentEntry().copy(); + } + } + } + return EntryStack.empty(); + } + + public Stream> getEntries() { + return (Stream>) (Stream>) entriesList.stream() + .filter(entry -> entry.getBounds().getMaxY() >= this.bounds.getY() && entry.getBounds().y <= this.bounds.getMaxY()) + .map(EntryWidget::getCurrentEntry) + .filter(entry -> !entry.isEmpty()); + } + + @Override + public boolean acceptDraggedStack(DraggingContext context, DraggableStack stack) { + return checkDraggedStacks(context, stack) + .filter(entry -> innerBounds.contains(context.getCurrentPosition())) + .map(entry -> { + drop(entry); + return Unit.INSTANCE; + }).isPresent(); + } + + public Optional> checkDraggedStacks(DraggingContext context, DraggableStack stack) { + EntrySerializer serializer = stack.getStack().getDefinition().getSerializer(); + if (stack instanceof RegionDraggableStack || (serializer.supportReading() && serializer.supportSaving())) { + try { + T regionEntry = stack instanceof RegionDraggableStack ? ((RegionDraggableStack) stack).getEntry().getEntry().copy() + : listener.convertDraggableStack(context, st