diff options
Diffstat (limited to 'runtime/src/main/java')
26 files changed, 1076 insertions, 539 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index 01e4fc1fd..16558a54e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -24,6 +24,8 @@ package me.shedaniel.rei; import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.serialization.DataResult; import dev.architectury.event.Event; import dev.architectury.event.EventFactory; @@ -88,6 +90,7 @@ import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.ImageButton; +import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.CraftingScreen; @@ -385,23 +388,64 @@ public class RoughlyEnoughItemsCoreClient { ClientScreenInputEvent.CHAR_TYPED_PRE.register((minecraftClient, screen, character, keyCode) -> { if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); - if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) - if (!REIRuntimeImpl.getSearchField().isFocused()) - return EventResult.pass(); + if (!REIRuntimeImpl.getSearchField().isFocused()) { + GuiEventListener focused = screen.getFocused(); + if (focused != null) { + if (focused instanceof EditBox editBox && editBox.isFocused()) return EventResult.pass(); + if (focused instanceof RecipeBookComponent book && book.searchBox != null && book.searchBox.isFocused()) return EventResult.pass(); + } + } resetFocused(screen); if (getOverlay().charTyped(character, keyCode) && resetFocused(screen)) return EventResult.interruptFalse(); return EventResult.pass(); }); - ClientGuiEvent.RENDER_POST.register((screen, matrices, mouseX, mouseY, delta) -> { + int[] rendered = {0}; + ClientGuiEvent.RENDER_PRE.register((screen, matrices, mouseX, mouseY, delta) -> { + if (shouldReturn(screen)) + return EventResult.pass(); + rendered[0] = 0; + return EventResult.pass(); + }); + ClientGuiEvent.RENDER_CONTAINER_BACKGROUND.register((screen, matrices, mouseX, mouseY, delta) -> { if (shouldReturn(screen)) return; + rendered[0] = 1; resetFocused(screen); if (!(screen instanceof DisplayScreen)) { getOverlay().render(matrices, mouseX, mouseY, delta); } + resetFocused(screen); + }); + ClientGuiEvent.RENDER_CONTAINER_FOREGROUND.register((screen, matrices, mouseX, mouseY, delta) -> { + if (shouldReturn(screen)) + return; + rendered[0] = 2; + resetFocused(screen); + PoseStack poseStack = RenderSystem.getModelViewStack(); + poseStack.pushPose(); + poseStack.translate(-screen.leftPos, -screen.topPos, 0.0); + RenderSystem.applyModelViewMatrix(); ((ScreenOverlayImpl) getOverlay()).lateRender(matrices, mouseX, mouseY, delta); + poseStack.popPose(); + RenderSystem.applyModelViewMatrix(); + resetFocused(screen); + }); + ClientGuiEvent.RENDER_POST.register((screen, matrices, mouseX, mouseY, delta) -> { + if (shouldReturn(screen) || rendered[0] == 2) + return; + if (screen instanceof AbstractContainerScreen) { + InternalLogger.getInstance().warn("Screen " + screen.getClass().getName() + " did not render background and foreground! This might cause rendering issues!"); + } + resetFocused(screen); + if (rendered[0] == 0 && !(screen instanceof DisplayScreen)) { + getOverlay().render(matrices, mouseX, mouseY, delta); + } + rendered[0] = 1; + if (rendered[0] == 1) { + ((ScreenOverlayImpl) getOverlay()).lateRender(matrices, mouseX, mouseY, delta); + } resetFocused(screen); }); ClientScreenInputEvent.MOUSE_DRAGGED_PRE.register((minecraftClient, screen, mouseX1, mouseY1, button, mouseX2, mouseY2) -> { @@ -422,9 +466,13 @@ public class RoughlyEnoughItemsCoreClient { return EventResult.interruptFalse(); } } - if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) - if (!REIRuntimeImpl.getSearchField().isFocused()) - return EventResult.pass(); + if (!REIRuntimeImpl.getSearchField().isFocused()) { + GuiEventListener focused = screen.getFocused(); + if (focused != null) { + if (focused instanceof EditBox editBox && editBox.isFocused()) return EventResult.pass(); + if (focused instanceof RecipeBookComponent book && book.searchBox != null && book.searchBox.isFocused()) return EventResult.pass(); + } + } resetFocused(screen); if (getOverlay().keyPressed(i, i1, i2) && resetFocused(screen)) @@ -434,9 +482,13 @@ public class RoughlyEnoughItemsCoreClient { ClientScreenInputEvent.KEY_RELEASED_PRE.register((minecraftClient, screen, i, i1, i2) -> { if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); - if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) - if (!REIRuntimeImpl.getSearchField().isFocused()) - return EventResult.pass(); + if (!REIRuntimeImpl.getSearchField().isFocused()) { + GuiEventListener focused = screen.getFocused(); + if (focused != null) { + if (focused instanceof EditBox editBox && editBox.isFocused()) return EventResult.pass(); + if (focused instanceof RecipeBookComponent book && book.searchBox != null && book.searchBox.isFocused()) return EventResult.pass(); + } + } resetFocused(screen); if (getOverlay().keyReleased(i, i1, i2) && resetFocused(screen)) 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 d59ece66c..a18d7aeab 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 @@ -684,7 +684,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @Comment("Declares how the scrollbar in composite screen should act.") private boolean compositeScrollBarPermanent = false; private boolean toastDisplayedOnCopyIdentifier = true; @Comment("Declares whether REI should use compact tabs for categories.") private boolean useCompactTabs = true; - @Comment("Declares whether REI should use compact tab buttons for categories.") @ConfigEntry.Gui.Excluded private boolean useCompactTabButtons = false; + @Comment("Declares whether REI should use compact tab buttons for categories.") private boolean useCompactTabButtons = false; } public static class Search { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java index 14636c4c2..803802ea8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java @@ -23,13 +23,23 @@ package me.shedaniel.rei.impl.client.config.entries; +import com.google.common.base.Suppliers; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; +import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextType; import me.shedaniel.rei.impl.client.entry.filtering.rules.ManualFilteringRule; +import me.shedaniel.rei.impl.client.entry.filtering.rules.SearchFilteringRuleType; import me.shedaniel.rei.impl.client.gui.InternalTextures; +import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; +import me.shedaniel.rei.impl.common.entry.type.FilteringLogic; +import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -42,11 +52,11 @@ import net.minecraft.network.chat.FormattedText; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; public class FilteringRulesScreen extends Screen { private final FilteringEntry entry; @@ -184,7 +194,7 @@ public class FilteringRulesScreen extends Screen { public DefaultRuleEntry(FilteringRule<?> rule, FilteringEntry entry, Function<Screen, Screen> screenFunction) { super(rule); - this.screenFunction = (screenFunction == null ? ((FilteringRuleType<FilteringRule<?>>) rule.getType()).createEntryScreen(rule) : screenFunction); + this.screenFunction = Objects.requireNonNullElseGet(screenFunction == null ? ((FilteringRuleType<FilteringRule<?>>) rule.getType()).createEntryScreen(rule) : screenFunction, () -> placeholderScreen(rule)); configureButton = new Button(0, 0, 20, 20, Component.nullToEmpty(null), button -> { entry.edited = true; Minecraft.getInstance().setScreen(this.screenFunction.apply(Minecraft.getInstance().screen)); @@ -250,4 +260,36 @@ public class FilteringRulesScreen extends Screen { return Arrays.asList(configureButton, deleteButton); } } + + private static <Cache> Function<Screen, Screen> placeholderScreen(FilteringRule<Cache> r) { + class PlaceholderScreen extends FilteringRuleOptionsScreen<FilteringRule<Cache>> { + public PlaceholderScreen(Screen parent) { + super(r, parent); + } + + @Override + public void addEntries(Consumer<RuleEntry> entryConsumer) { + addEmpty(entryConsumer, 10); + Function<Boolean, Component> function = bool -> { + return Component.translatable("rule.roughlyenoughitems.filtering.search.show." + bool); + }; + Map<FilteringContextType, Set<HashedEntryStackWrapper>> stacks = FilteringLogic.hidden(FilteringLogic.getRules(), false, false, EntryRegistry.getInstance().getEntryStacks().collect(Collectors.toList())); + + entryConsumer.accept(new SubRulesEntry(rule, () -> function.apply(true), + Collections.singletonList(new SearchFilteringRuleType.EntryStacksRuleEntry(rule, + Suppliers.ofInstance(CollectionUtils.map(stacks.get(FilteringContextType.SHOWN), + stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.unwrap().normalize()))))))); + addEmpty(entryConsumer, 10); + entryConsumer.accept(new SubRulesEntry(rule, () -> function.apply(false), + Collections.singletonList(new SearchFilteringRuleType.EntryStacksRuleEntry(rule, + Suppliers.ofInstance(CollectionUtils.map(stacks.get(FilteringContextType.HIDDEN), + stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.unwrap().normalize()))))))); + } + + @Override + public void save() { + } + } + return PlaceholderScreen::new; + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java index d0e26a9fc..697bcde63 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java @@ -27,6 +27,7 @@ import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import it.unimi.dsi.fastutil.longs.*; import me.shedaniel.rei.api.client.entry.filtering.FilteringContext; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; @@ -69,20 +70,35 @@ public class FilteringContextImpl implements FilteringContext { @Override public Collection<EntryStack<?>> getHiddenStacks() { - return getPublicFacing(FilteringContextType.HIDDEN); + return getStacksFacing(FilteringContextType.HIDDEN); } @Override public Collection<EntryStack<?>> getShownStacks() { - return getPublicFacing(FilteringContextType.SHOWN); + return getStacksFacing(FilteringContextType.SHOWN); } @Override public Collection<EntryStack<?>> getUnsetStacks() { - return getPublicFacing(FilteringContextType.DEFAULT); + return getStacksFacing(FilteringContextType.DEFAULT); } - private Collection<EntryStack<?>> getPublicFacing(FilteringContextType type) { + @Override + public LongCollection getHiddenExactHashes() { + return getHashesFacing(FilteringContextType.HIDDEN); + } + + @Override + public LongCollection getShownExactHashes() { + return getHashesFacing(FilteringContextType.SHOWN); + } + + @Override + public LongCollection getUnsetExactHashes() { + return getHashesFacing(FilteringContextType.DEFAULT); + } + + private Collection<EntryStack<?>> getStacksFacing(FilteringContextType type) { Set<HashedEntryStackWrapper> wrappers = this.stacks.get(type); if (wrappers == null || wrappers.isEmpty()) return List.of(); return new AbstractSet<>() { @@ -98,6 +114,33 @@ public class FilteringContextImpl implements FilteringContext { }; } + private LongCollection getHashesFacing(FilteringContextType type) { + Set<HashedEntryStackWrapper> wrappers = this.stacks.get(type); + if (wrappers == null || wrappers.isEmpty()) return LongSets.emptySet(); + return new AbstractLongSet() { + @Override + public LongIterator iterator() { + Iterator<HashedEntryStackWrapper> iterator = wrappers.iterator(); + return new AbstractLongIterator() { + @Override + public long nextLong() { + return iterator.next().hashExact(); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + }; + } + + @Override + public int size() { + return wrappers.size(); + } + }; + } + public void handleResult(FilteringResultImpl result) { Collection<HashedEntryStackWrapper> hiddenStacks = result.hiddenStacks; Collection<HashedEntryStackWrapper> shownStacks = result.shownStacks; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java index 1d51eb0f2..81aa7b3ab 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java @@ -23,133 +23,212 @@ package me.shedaniel.rei.impl.client.entry.filtering.rules; -import com.google.common.collect.Lists; import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; +import it.unimi.dsi.fastutil.longs.LongCollection; +import it.unimi.dsi.fastutil.longs.LongIterator; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; +import me.shedaniel.clothconfig2.api.LazyResettable; import me.shedaniel.rei.api.client.entry.filtering.*; import me.shedaniel.rei.api.client.entry.filtering.base.BasicFilteringRule; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.registry.ReloadStage; -import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.util.ThreadCreator; -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.ExecutorService; +import java.util.function.Supplier; import java.util.stream.Collectors; -public enum BasicFilteringRuleImpl implements BasicFilteringRule<Pair<LongSet, LongSet>> { +public enum BasicFilteringRuleImpl implements BasicFilteringRule<Unit> { INSTANCE; private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-BasicFiltering").asService(); - private final List<EntryStack<?>> hidden = new ArrayList<>(), shown = new ArrayList<>(); + private final LongSet hiddenHashes = new LongOpenHashSet(), shownHashes = new LongOpenHashSet(); + private final List<CachedProvider> hiddenProviders = new ArrayList<>(), shownProviders = new ArrayList<>(); @Override - public FilteringRuleType<? extends FilteringRule<Pair<LongSet, LongSet>>> getType() { + public FilteringRuleType<? extends FilteringRule<Unit>> getType() { return BasicFilteringRuleType.INSTANCE; } @Override - public Pair<LongSet, LongSet> prepareCache(boolean async) { - return new Pair<>(prepareCacheFor(hidden, async), prepareCacheFor(shown, async)); - } - - @NotNull - private static LongSet prepareCacheFor(List<EntryStack<?>> stacks, boolean async) { - if (async) { - LongSet all = new LongOpenHashSet(); - List<CompletableFuture<LongSet>> completableFutures = Lists.newArrayList(); - for (Iterable<EntryStack<?>> partitionStacks : CollectionUtils.partition(stacks, 100)) { - completableFutures.add(CompletableFuture.supplyAsync(() -> { - LongSet output = new LongOpenHashSet(); - for (EntryStack<?> stack : partitionStacks) { - if (stack != null && !stack.isEmpty()) { - output.add(EntryStacks.hashExact(stack)); - } - } - return output; - }, EXECUTOR_SERVICE)); - } - try { - CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).get(5, TimeUnit.MINUTES); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - e.printStackTrace(); - } - for (CompletableFuture<LongSet> future : completableFutures) { - LongSet now = future.getNow(null); - if (now != null) { - all.addAll(now); - } - } - return all; - } else { - return stacks.stream().map(EntryStacks::hashExact).collect(Collectors.toCollection(LongOpenHashSet::new)); + public Unit prepareCache(boolean async) { + for (CachedProvider provider : hiddenProviders) { + provider.get(); + } + for (CachedProvider provider : shownProviders) { + provider.get(); } + return Unit.INSTANCE; } @Override - public FilteringResult processFilteredStacks(FilteringContext context, FilteringResultFactory resultFactory, Pair<LongSet, LongSet> cache, boolean async) { + public FilteringResult processFilteredStacks(FilteringContext context, FilteringResultFactory resultFactory, Unit cache, boolean async) { FilteringResult result = resultFactory.create(); - hideList(context.getShownStacks(), result, async, cache.getFirst()); - hideList(context.getUnsetStacks(), result, async, cache.getFirst()); - showList(context.getHiddenStacks(), result, async, cache.getSecond()); - showList(context.getUnsetStacks(), result, async, cache.getSecond()); + hideList(context.getShownStacks(), context.getShownExactHashes(), result, async, hiddenHashes); + hideList(context.getUnsetStacks(), context.getUnsetExactHashes(), result, async, hiddenHashes); + + for (CachedProvider provider : hiddenProviders) { + hideList(context.getShownStacks(), context.getShownExactHashes(), result, async, provider.getExactHashes()); + hideList(context.getUnsetStacks(), context.getUnsetExactHashes(), result, async, provider.getExactHashes()); + } + + showList(context.getHiddenStacks(), context.getHiddenExactHashes(), result, async, shownHashes); + showList(context.getUnsetStacks(), context.getUnsetExactHashes(), result, async, shownHashes); + + for (CachedProvider provider : shownProviders) { + showList(context.getHiddenStacks(), context.getHiddenExactHashes(), result, async, provider.getExactHashes()); + showList(context.getUnsetStacks(), context.getUnsetExactHashes(), result, async, provider.getExactHashes()); + } + return result; } - private void hideList(Collection<EntryStack<?>> stacks, FilteringResult result, boolean async, LongSet filteredStacks) { - result.hide((async ? stacks.parallelStream() : stacks.stream()).filter(stack -> filteredStacks.contains(EntryStacks.hashExact(stack))).collect(Collectors.toList())); + private void hideList(Collection<EntryStack<?>> stacks, LongCollection hashes, FilteringResult result, boolean async, LongSet filteredStacks) { + LongIterator iterator = hashes.iterator(); + result.hide(stacks.stream() + .filter(stack -> filteredStacks.contains(iterator.nextLong())) + .collect(Collectors.toList())); } - private void showList(Collection<EntryStack<?>> stacks, FilteringResult result, boolean async, LongSet filteredStacks) { - result.show((async ? stacks.parallelStream() : stacks.stream()).filter(stack -> filteredStacks.contains(EntryStacks.hashExact(stack))).collect(Collectors.toList())); + private void showList(Collection<EntryStack<?>> stacks, LongCollection hashes, FilteringResult result, boolean async, LongSet filteredStacks) { + LongIterator iterator = hashes.iterator(); + result.show(stacks.stream() + .filter(stack -> filteredStacks.contains(iterator.nextLong())) + .collect(Collectors.toList())); } @Override public FilteringResult hide(EntryStack<?> stack) { - hidden.add(stack); - shown.remove(stack); + long hashExact = EntryStacks.hashExact(stack); + hiddenHashes.add(hashExact); + shownHashes.remove(hashExact); + + if (!isReloading()) { + markDirty(List.of(stack), null); + } + return this; } @Override public FilteringResult hide(Collection<? extends EntryStack<?>> stacks) { - hidden.addAll(stacks); - shown.removeAll(stacks); + for (EntryStack<?> stack : stacks) { + long hashExact = EntryStacks.hashExact(stack); + hiddenHashes.add(hashExact); + shownHashes.remove(hashExact); + } + + if (!isReloading()) { + markDirty((Collection<EntryStack<?>>) stacks, null); + } + return this; } @Override public FilteringResult show(EntryStack<?> stack) { - shown.add(stack); - hidden.remove(stack); + long hashExact = EntryStacks.hashExact(stack); + shownHashes.add(hashExact); + hiddenHashes.remove(hashExact); + + if (!isReloading()) { + markDirty(List.of(stack), null); + } + return this; } @Override public FilteringResult show(Collection<? extends EntryStack<?>> stacks) { - shown.addAll(stacks); - hidden.removeAll(stacks); + for (EntryStack<?> stack : stacks) { + long hashExact = EntryStacks.hashExact(stack); + shownHashes.add(hashExact); + hiddenHashes.remove(hashExact); + } + + if (!isReloading()) { + markDirty((Collection<EntryStack<?>>) stacks, null); + } + return this; } @Override + public MarkDirty hide(Supplier<Collection<EntryStack<?>>> provider) { + CachedProvider cachedProvider = new CachedProvider(provider); + shownProviders.remove(cachedProvider); + hiddenProviders.add(cachedProvider); + + cachedProvider.markDirty(); + return cachedProvider; + } + + @Override + public MarkDirty show(Supplier<Collection<EntryStack<?>>> provider) { + CachedProvider cachedProvider = new CachedProvider(provider); + hiddenProviders.remove(cachedProvider); + shownProviders.add(cachedProvider); + + cachedProvider.markDirty(); + return cachedProvider; + } + + @Override public ReloadStage getStage() { return ReloadStage.START; } @Override public void startReload() { - hidden.clear(); - shown.clear(); + hiddenHashes.clear(); + shownHashes.clear(); + hiddenProviders.clear(); + shownProviders.clear(); } @Override public void acceptPlugin(REIClientPlugin plugin) { plugin.registerBasicEntryFiltering(this); } + + private class CachedProvider implements MarkDirty { + private final Supplier<Collection<EntryStack<?>>> provider; + private final LazyResettable<Pair<Collection<EntryStack<?>>, LongSet>> cache = new LazyResettable<>(this::compose); + + private CachedProvider(Supplier<Collection<EntryStack<?>>> provider) { + this.provider = provider; + } + + @Override + public void markDirty() { + Pair<Collection<EntryStack<?>>, LongSet> prev = this.cache.get(); + this.cache.reset(); + Pair<Collection<EntryStack<?>>, LongSet> next = this.cache.get(); + BasicFilteringRuleImpl.this.markDirty(prev.getFirst(), prev.getSecond()); + BasicFilteringRuleImpl.this.markDirty(next.getFirst(), next.getSecond()); + } + + public Collection<EntryStack<?>> get() { |
