From 92264d510b0e4f66719c970b2dbf21b495cfded1 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 6 Nov 2021 13:34:57 +0800 Subject: Fix #647 --- .../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 +++++ 6 files changed, 57 insertions(+), 38 deletions(-) (limited to 'runtime/src') 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 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(-) (limited to 'runtime/src') 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 --- .../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 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'runtime/src') 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(-) (limited to 'runtime/src') 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 --- .../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 +- 12 files changed, 869 insertions(+), 574 deletions(-) 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 (limited to 'runtime/src') 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, stack); + if (regionEntry == null) return Optional.empty(); + RealRegionEntry entry = new RealRegionEntry<>(this, regionEntry, entrySize()); + entry.size.setAs(entrySize() * 100); + return Optional.of(entry); + } catch (Throwable ignored) { + } + } + return Optional.empty(); + } + + public void setEntries(List newEntries) { + newEntries = Lists.newArrayList(newEntries); + newEntries.removeIf(entry -> entry == null || entry.isEntryInvalid()); + + int entrySize = entrySize(); + IntSet newFavoritesHash = new IntOpenHashSet(CollectionUtils.mapToInt(newEntries, T::hashCode)); + List> removedEntries = Lists.newArrayList(this.entries.values()); + removedEntries.removeIf(entry -> newFavoritesHash.contains(entry.hashIgnoreAmount())); + + for (RealRegionEntry removedEntry : removedEntries) { + removedEntry.remove(); + this.removedEntries.put(removedEntry.hashIgnoreAmount(), removedEntry); + } + + Int2ObjectMap> prevEntries = new Int2ObjectOpenHashMap<>(entries); + this.entries.clear(); + + for (T regionEntry : newEntries) { + RealRegionEntry realEntry = prevEntries.get(regionEntry.hashCode()); + + if (realEntry == null) { + realEntry = new RealRegionEntry<>(this, regionEntry, entrySize); + } + + if (!ConfigObject.getInstance().isFavoritesAnimated()) realEntry.size.setAs(entrySize * 100); + else realEntry.size.setTo(entrySize * 100, 300); + entries.put(realEntry.hashIgnoreAmount(), realEntry); + } + + applyNewEntriesList(); + updateEntriesPosition(entry -> prevEntries.containsKey(entry.hashIgnoreAmount())); + } + + public void applyNewEntriesList() { + this.entriesList = Stream.concat(entries.values().stream().map(RealRegionEntry::getWidget), removedEntries.values().stream().map(RealRegionEntry::getWidget)).collect(Collectors.toList()); + this.children = Stream.>of( + entries.values().stream().map(RealRegionEntry::getWidget), + removedEntries.values().stream().map(RealRegionEntry::getWidget) + ).flatMap(Function.identity()).collect(Collectors.toList()); + } + + public void updateEntriesPosition(Predicate> animated) { + int entrySize = entrySize(); + this.blockedCount = 0; + this.innerBounds = updateInnerBounds(bounds); + int width = innerBounds.width / entrySize; + int currentX = 0; + int currentY = 0; + int releaseIndex = getReleaseIndex(); + + int slotIndex = 0; + for (RealRegionEntry entry : this.entries.values()) { + while (true) { + int xPos = currentX * entrySize + innerBounds.x; + int yPos = currentY * entrySize + innerBounds.y; + + currentX++; + if (currentX >= width) { + currentX = 0; + currentY++; + } + + if (notSteppingOnExclusionZones(xPos, yPos - (int) scrolling.scrollAmount, entrySize, entrySize, innerBounds)) { + if (slotIndex++ == releaseIndex) { + continue; + } + + entry.moveTo(animated.test(entry), xPos, yPos); + break; + } else { + blockedCount++; + } + } + } + } + + private int getReleaseIndex() { + DraggingContext context = DraggingContext.getInstance(); + Point position = context.getCurrentPosition(); + if (context.isDraggingStack() && bounds.contains(position) && checkDraggedStacks(context.cast(), context.getCurrentStack()).isPresent()) { + int entrySize = entrySize(); + int width = innerBounds.width / entrySize; + int currentX = 0; + int currentY = 0; + List, Point>> entriesPoints = Lists.newArrayList(); + for (RealRegionEntry entry : this.entries.values()) { + while (true) { + int xPos = currentX * entrySize + innerBounds.x; + int yPos = currentY * entrySize + innerBounds.y; + + currentX++; + if (currentX >= width) { + currentX = 0; + currentY++; + } + + if (notSteppingOnExclusionZones(xPos, yPos - (int) scrolling.scrollAmount, entrySize, entrySize, innerBounds)) { + entriesPoints.add(new Tuple<>(entry, new Point(xPos, yPos))); + break; + } else { + blockedCount++; + } + } + } + + int maxSize = entriesPoints.size(); + if (currentX != 0) { + int xPos = currentX * entrySize + innerBounds.x; + int yPos = currentY * entrySize + innerBounds.y; + + if (notSteppingOnExclusionZones(xPos, yPos - (int) scrolling.scrollAmount, entrySize, entrySize, innerBounds)) { + entriesPoints.add(new Tuple<>(null, new Point(xPos, yPos))); + } + } + + double x = position.x - 8; + double y = position.y + scrolling.scrollAmount - 8; + + return Mth.clamp(entriesPoints.stream() + .filter(value -> { + double otherY = value.getB().y; + + return otherY <= y + entrySize / 2 && otherY + entrySize > y + entrySize / 2; + }) + .min(Comparator.comparingDouble(value -> { + double otherX = value.getB().x; + double otherY = value.getB().y; + + return (x - otherX) * (x - otherX) + (y - otherY) * (y - otherY); + })) + .map(entriesPoints::indexOf) + .orElse(maxSize), + 0, entriesPoints.size()); + } + + return -2; + } + + private static Rectangle updateInnerBounds(Rectangle bounds) { + int entrySize = entrySize(); + int width = Math.max(Mth.floor((bounds.width - 2 - 6) / (float) entrySize), 1); + if (!ConfigObject.getInstance().isLeftHandSidePanel()) + return new Rectangle((int) (bounds.getCenterX() - width * (entrySize / 2f) + 3), bounds.y, width * entrySize, bounds.height); + return new Rectangle((int) (bounds.getCenterX() - width * (entrySize / 2f) - 3), bounds.y, width * entrySize, bounds.height); + } + + public void drop(RealRegionEntry entry) { + DraggingContext context = DraggingContext.getInstance(); + double x = context.getCurrentPosition().x; + double y = context.getCurrentPosition().y + scrolling.scrollAmount; + entry.startedDraggingPosition = null; + + entry.x.setAs(x - 8); + entry.y.setAs(y - 8); + + boolean contains = bounds.contains(PointHelper.ofMouse()); + int newIndex = contains ? getReleaseIndex() : Math.max(0, Iterables.indexOf(entries.values(), e -> e == entry)); + + if (entries.size() - 1 <= newIndex) { + RealRegionEntry remove = this.entries.remove(entry.hashIgnoreAmount()); + if (remove != null) { + remove.remove(); + this.removedEntries.put(remove.hashIgnoreAmount(), remove); + } + this.entries.put(entry.hashIgnoreAmount(), entry); + } else { + Int2ObjectMap> prevEntries = new Int2ObjectLinkedOpenHashMap<>(entries); + this.entries.clear(); + + int index = 0; + for (Int2ObjectMap.Entry> entryEntry : prevEntries.int2ObjectEntrySet()) { + if (index == newIndex) { + this.entries.put(entry.hashIgnoreAmount(), entry); + } + if (entryEntry.getIntKey() != entry.hashIgnoreAmount()) { + this.entries.put(entryEntry.getIntKey(), entryEntry.getValue()); + index++; + } + } + } + + applyNewEntriesList(); + + listener.onDrop(this.entries.values().stream() + .map(RealRegionEntry::getEntry)); + + setEntries(this.entries.values().stream() + .map(RealRegionEntry::getEntry) + .collect(Collectors.toList())); + } + + public void remove(RealRegionEntry entry) { + entries.remove(entry.hashIgnoreAmount()); + setEntries(CollectionUtils.map(entries.values(), RealRegionEntry::getEntry)); + } + + public double getScrollAmount() { + return scrolling.scrollAmount; + } + + public boolean has(RealRegionEntry entry) { + int hash = entry.hashIgnoreAmount(); + return entries.containsKey(hash) && !removedEntries.containsKey(hash); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java index 5041887a4..c98d689b3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/FavoritesListWidget.java @@ -23,18 +23,13 @@ package me.shedaniel.rei.impl.client.gui.widget; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.math.Vector4f; -import it.unimi.dsi.fastutil.ints.*; -import it.unimi.dsi.fastutil.objects.ObjectIterator; import me.shedaniel.clothconfig2.ClothConfigInitializer; import me.shedaniel.clothconfig2.api.LazyResettable; 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; @@ -43,26 +38,25 @@ import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; -import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.client.gui.AbstractContainerEventHandler; -import me.shedaniel.rei.api.client.gui.drag.*; +import me.shedaniel.rei.api.client.gui.drag.DraggableStack; +import me.shedaniel.rei.api.client.gui.drag.DraggableStackProviderWidget; +import me.shedaniel.rei.api.client.gui.drag.DraggingContext; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.overlay.OverlayListWidget; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; -import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; import me.shedaniel.rei.api.client.util.ClientEntryStacks; -import me.shedaniel.rei.api.common.entry.EntrySerializer; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.Animator; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.modules.Menu; -import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; +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.RegionListener; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; @@ -70,81 +64,42 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.util.Mth; -import net.minecraft.util.Tuple; -import net.minecraft.util.Unit; -import net.minecraft.world.phys.shapes.BooleanOp; -import net.minecraft.world.phys.shapes.Shapes; -import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.*; -import java.util.function.Function; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.function.Predicate; -import java.util.function.Supplier; -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; @ApiStatus.Internal -public class FavoritesListWidget extends WidgetWithBounds implements DraggableStackProviderWidget, DraggableStackVisitorWidget, OverlayListWidget { - protected final ScrollingContainer scrolling = new ScrollingContainer() { - @Override - public Rectangle getBounds() { - return currentBounds; - } - - @Override - public int getMaxScrollHeight() { - return Mth.ceil((entries.size() + blockedCount) / (innerBounds.width / (float) entrySize())) * entrySize(); - } - - @Override - public int getScrollBarX() { - if (!ConfigObject.getInstance().isLeftHandSidePanel()) - return fullBounds.x + 1; - return fullBounds.getMaxX() - 7; - } - }; - protected int blockedCount; - private Rectangle fullBounds, currentBounds = new Rectangle(), innerBounds; - private final Int2ObjectMap entries = new Int2ObjectLinkedOpenHashMap<>(); - private final Int2ObjectMap removedEntries = new Int2ObjectLinkedOpenHashMap<>(); - private List entriesList = Lists.newArrayList(); - private List children = Lists.newArrayList(); +public class FavoritesListWidget extends WidgetWithBounds implements DraggableStackProviderWidget, OverlayListWidget, RegionListener { + private Rectangle fullBounds; + private EntryStacksRegionWidget region = new EntryStacksRegionWidget<>(this); public final AddFavoritePanel favoritePanel = new AddFavoritePanel(this); public final ToggleAddFavoritePanelButton favoritePanelButton = new ToggleAddFavoritePanelButton(this); - - private static Rectangle updateInnerBounds(Rectangle bounds) { - int entrySize = entrySize(); - int width = Math.max(Mth.floor((bounds.width - 2 - 6) / (float) entrySize), 1); - if (!ConfigObject.getInstance().isLeftHandSidePanel()) - return new Rectangle((int) (bounds.getCenterX() - width * (entrySize / 2f) + 3), bounds.y, width * entrySize, bounds.hei