aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/main/java/me/shedaniel/rei/impl/client
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2024-09-17 21:34:04 +0800
committershedaniel <daniel@shedaniel.me>2024-09-17 21:34:04 +0800
commit3febdc4e1d6927f19d0de6fc8430765336d34d7e (patch)
treee8cc88c46ce9b2ebf0954f94dcb56189f2fa5a1b /runtime/src/main/java/me/shedaniel/rei/impl/client
parentbc039e2d0a45409396c9156307d70529ccb28a3e (diff)
parentccf3dcd60aa6c1d079dd57c59d9a89c2ca60b1e7 (diff)
downloadRoughlyEnoughItems-3febdc4e1d6927f19d0de6fc8430765336d34d7e.tar.gz
RoughlyEnoughItems-3febdc4e1d6927f19d0de6fc8430765336d34d7e.tar.bz2
RoughlyEnoughItems-3febdc4e1d6927f19d0de6fc8430765336d34d7e.zip
Merge remote-tracking branch 'origin/12.x-1.20' into 13.x-1.20.2
# Conflicts: # default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/DefaultSmithingDisplay.java # fabric/src/main/resources/roughlyenoughitems.accessWidener # runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java # runtime/src/main/java/me/shedaniel/rei/impl/common/registry/RecipeManagerContextImpl.java
Diffstat (limited to 'runtime/src/main/java/me/shedaniel/rei/impl/client')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java3
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java6
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/DisplayRegistryInfoScreen.java176
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java37
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ScreenWithMenu.java89
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java7
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCache.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCacheImpl.java16
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java78
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/util/OriginalRetainingCyclingList.java42
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java8
12 files changed, 429 insertions, 41 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java
index 28b83e639..b206fd6e5 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java
@@ -116,7 +116,8 @@ public interface AllREIConfigGroups {
OptionGroup DEBUG_PERFORMANCE = make("debug.performance")
.add(PLUGINS_PERFORMANCE)
.add(SEARCH_PERFORMANCE)
- .add(ENTRY_LIST_PERFORMANCE);
+ .add(ENTRY_LIST_PERFORMANCE)
+ .add(DISPLAY_REGISTRY_ANALYSIS);
OptionGroup RESET_RELOAD = make("reset.reload")
.add(RELOAD_PLUGINS)
.add(RELOAD_SEARCH);
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java
index 30340bfba..97119df2e 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java
@@ -24,7 +24,6 @@
package me.shedaniel.rei.impl.client.gui.config.options;
import me.shedaniel.clothconfig2.api.ModifierKeyCode;
-import me.shedaniel.rei.RoughlyEnoughItemsCore;
import me.shedaniel.rei.RoughlyEnoughItemsCoreClient;
import me.shedaniel.rei.api.client.config.entry.EntryStackProvider;
import me.shedaniel.rei.api.client.gui.config.*;
@@ -37,6 +36,7 @@ import me.shedaniel.rei.impl.client.config.entries.ConfigureCategoriesScreen;
import me.shedaniel.rei.impl.client.config.entries.FilteringEntry;
import me.shedaniel.rei.impl.client.gui.config.REIConfigScreen;
import me.shedaniel.rei.impl.client.gui.config.options.configure.PanelBoundariesConfiguration;
+import me.shedaniel.rei.impl.client.gui.performance.DisplayRegistryInfoScreen;
import me.shedaniel.rei.impl.client.gui.performance.PerformanceScreen;
import me.shedaniel.rei.impl.client.gui.screen.ConfigReloadingScreen;
import me.shedaniel.rei.impl.client.gui.screen.collapsible.CollapsibleEntriesScreen;
@@ -246,9 +246,11 @@ public interface AllREIConfigOptions {
.enabledDisabled();
CompositeOption<Boolean> ENTRY_LIST_PERFORMANCE = make("debug.entry_list_performance", i -> i.advanced.layout.debugRenderTimeRequired, (i, v) -> i.advanced.layout.debugRenderTimeRequired = v)
.enabledDisabled();
+ CompositeOption<Object> DISPLAY_REGISTRY_ANALYSIS = make("debug.display_registry_analysis", i -> null, (i, v) -> new Object())
+ .details((access, option, onClose) -> Minecraft.getInstance().setScreen(new DisplayRegistryInfoScreen(onClose)))
+ .requiresLevel();
CompositeOption<Object> RELOAD_PLUGINS = make("reset.reload_plugins", i -> null, (i, v) -> new Object())
.reload((access, option, onClose) -> {
- RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear();
RoughlyEnoughItemsCoreClient.reloadPlugins(null, null);
while (!PluginManager.areAnyReloading()) {
try {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/DisplayRegistryInfoScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/DisplayRegistryInfoScreen.java
new file mode 100644
index 000000000..f0cb9de14
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/DisplayRegistryInfoScreen.java
@@ -0,0 +1,176 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.performance;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.registry.display.DisplayRegistry;
+import me.shedaniel.rei.api.common.category.CategoryIdentifier;
+import me.shedaniel.rei.api.common.display.Display;
+import me.shedaniel.rei.api.common.util.CollectionUtils;
+import me.shedaniel.rei.impl.client.gui.modules.Menu;
+import me.shedaniel.rei.impl.client.gui.modules.entries.ToggleMenuEntry;
+import me.shedaniel.rei.impl.client.gui.screen.ScreenWithMenu;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.components.Button;
+import net.minecraft.client.gui.components.events.GuiEventListener;
+import net.minecraft.client.gui.narration.NarratableEntry;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+import net.minecraft.util.FormattedCharSequence;
+
+import java.util.*;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+@Environment(EnvType.CLIENT)
+public class DisplayRegistryInfoScreen extends ScreenWithMenu {
+ private Runnable onClose;
+
+ public DisplayRegistryInfoScreen(Runnable onClose) {
+ super(Component.translatable("text.rei.display_registry_analysis"));
+ this.onClose = onClose;
+ }
+
+ private ListWidget list;
+ private SortType sortType = SortType.ID;
+
+ @Override
+ public void init() {
+ {
+ Component backText = Component.literal("↩ ").append(Component.translatable("gui.back"));
+ addRenderableWidget(new Button(4, 4, Minecraft.getInstance().font.width(backText) + 10, 20, backText, button -> {
+ this.onClose.run();
+ this.onClose = null;
+ }, Supplier::get) {
+ });
+ }
+ {
+ Component text = Component.translatable("text.rei.sort");
+ Rectangle bounds = new Rectangle(this.width - 4 - Minecraft.getInstance().font.width(text) - 10, 4, Minecraft.getInstance().font.width(text) + 10, 20);
+ addRenderableWidget(new Button(bounds.x, bounds.y, bounds.width, bounds.height, text, button -> {
+ this.setMenu(new Menu(bounds, CollectionUtils.map(SortType.values(), type -> {
+ return ToggleMenuEntry.of(Component.translatable("text.rei.sort.by", type.name().toLowerCase(Locale.ROOT)), () -> false, o -> {
+ this.closeMenu();
+ this.sortType = type;
+ this.init(this.minecraft, this.width, this.height);
+ });
+ }), false));
+ }, Supplier::get) {
+ });
+ }
+ list = new ListWidget();
+ list.addItem(new EntryImpl(Component.literal("Total Displays"), DisplayRegistry.getInstance().displaySize()));
+ sort(DisplayRegistry.getInstance().getAll().entrySet().stream())
+ .forEach(entry -> {
+ list.addItem(new EntryImpl(entry.getKey(), entry.getValue().size()));
+ });
+ addWidget(list);
+ }
+
+ private Stream<Map.Entry<CategoryIdentifier<?>, List<Display>>> sort(Stream<Map.Entry<CategoryIdentifier<?>, List<Display>>> stream) {
+ return switch (sortType) {
+ case COUNT -> stream.sorted(Comparator.<Map.Entry<CategoryIdentifier<?>, List<Display>>>comparingInt(value -> value.getValue().size()).reversed());
+ case ID -> stream.sorted(Comparator.comparing(value -> value.getKey().toString()));
+ };
+ }
+
+ @Override
+ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+ renderDirtBackground(graphics);
+ list.render(graphics, mouseX, mouseY, delta);
+ graphics.drawString(this.font, this.title.getVisualOrderText(), (int) (this.width / 2.0F - this.font.width(this.title) / 2.0F), 12, -1);
+ super.render(graphics, mouseX, mouseY, delta);
+ }
+
+ public static abstract class ListEntry extends DynamicElementListWidget.ElementEntry<ListEntry> {
+ }
+
+ private class ListWidget extends DynamicElementListWidget<ListEntry> {
+ public ListWidget() {
+ super(DisplayRegistryInfoScreen.this.minecraft, DisplayRegistryInfoScreen.this.width, DisplayRegistryInfoScreen.this.height, 30, DisplayRegistryInfoScreen.this.height, Screen.BACKGROUND_LOCATION);
+ }
+
+ @Override
+ public int getItemWidth() {
+ return width;
+ }
+
+ @Override
+ public int addItem(ListEntry item) {
+ return super.addItem(item);
+ }
+
+ @Override
+ protected int getScrollbarPosition() {
+ return width - 6;
+ }
+ }
+
+ public static class EntryImpl extends ListEntry {
+ private final Component component;
+ public final int count;
+
+ public EntryImpl(CategoryIdentifier<?> identifier, int count) {
+ this(Component.literal(identifier.getIdentifier().toString()), count);
+ }
+
+ public EntryImpl(Component component, int count) {
+ this.component = component;
+ this.count = count;
+ }
+
+ @Override
+ public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) {
+ RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
+ graphics.drawString(Minecraft.getInstance().font, this.component.getVisualOrderText(), x + 4, y + 6, -1);
+ FormattedCharSequence rightText = Component.translatable("text.rei.display_registry_analysis.displays", count).getVisualOrderText();
+ graphics.drawString(Minecraft.getInstance().font, rightText, x + entryWidth - 6 - 8 - Minecraft.getInstance().font.width(rightText), y + 6, -1);
+ }
+
+ @Override
+ public int getItemHeight() {
+ return 24;
+ }
+
+ @Override
+ public List<? extends GuiEventListener> children() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<? extends NarratableEntry> narratables() {
+ return Collections.emptyList();
+ }
+ }
+
+ private enum SortType {
+ COUNT,
+ ID
+ }
+}
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 21c8c20c9..f96f7bc5f 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
@@ -25,11 +25,16 @@ package me.shedaniel.rei.impl.client.gui.performance;
import com.mojang.datafixers.util.Pair;
import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget;
+import me.shedaniel.math.Rectangle;
import me.shedaniel.rei.RoughlyEnoughItemsCore;
import me.shedaniel.rei.api.common.plugins.REIPlugin;
import me.shedaniel.rei.api.common.plugins.REIPluginProvider;
+import me.shedaniel.rei.api.common.util.CollectionUtils;
+import me.shedaniel.rei.impl.client.gui.modules.Menu;
+import me.shedaniel.rei.impl.client.gui.modules.entries.ToggleMenuEntry;
import me.shedaniel.rei.impl.client.gui.performance.entry.PerformanceEntryImpl;
import me.shedaniel.rei.impl.client.gui.performance.entry.SubCategoryListEntry;
+import me.shedaniel.rei.impl.client.gui.screen.ScreenWithMenu;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
@@ -48,7 +53,7 @@ import java.util.stream.Collectors;
import static java.util.concurrent.TimeUnit.*;
@Environment(EnvType.CLIENT)
-public class PerformanceScreen extends Screen {
+public class PerformanceScreen extends ScreenWithMenu {
private Runnable onClose;
public PerformanceScreen(Runnable onClose) {
@@ -57,6 +62,7 @@ public class PerformanceScreen extends Screen {
}
private PerformanceEntryListWidget list;
+ private SortType sortType = SortType.ORDER;
/*
* Copyright (C) 2008 The Guava Authors
@@ -142,8 +148,22 @@ public class PerformanceScreen extends Screen {
this.onClose = null;
}, Supplier::get) {});
}
+ {
+ Component text = Component.translatable("text.rei.sort");
+ Rectangle bounds = new Rectangle(this.width - 4 - Minecraft.getInstance().font.width(text) - 10, 4, Minecraft.getInstance().font.width(text) + 10, 20);
+ addRenderableWidget(new Button(bounds.x, bounds.y, bounds.width, bounds.height, text, button -> {
+ this.setMenu(new Menu(bounds, CollectionUtils.map(SortType.values(), type -> {
+ return ToggleMenuEntry.of(Component.translatable("text.rei.sort.by", type.name().toLowerCase(Locale.ROOT)), () -> false, o -> {
+ this.closeMenu();
+ this.sortType = type;
+ this.init(this.minecraft, this.width, this.height);
+ });
+ }), false));
+ }, Supplier::get) {});
+ }
list = new PerformanceEntryListWidget();
long[] totalTime = {0};
+ List<SubCategoryListEntry> subCategories = new ArrayList<>();
RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.getStages().forEach((stage, inner) -> {
List<PerformanceEntryImpl> entries = new ArrayList<>();
inner.times().forEach((obj, time) -> {
@@ -158,9 +178,15 @@ public class PerformanceScreen extends Screen {
entries.add(new PerformanceEntryImpl(Component.literal("Miscellaneous Operations"), inner.totalNano() - separateTime));
}
totalTime[0] += Math.max(inner.totalNano(), separateTime);
- entries.sort(Comparator.<PerformanceEntryImpl>comparingLong(value -> value.time).reversed());
- list.addItem(new SubCategoryListEntry(Component.literal(stage), (List<PerformanceScreen.PerformanceEntry>) (List<? extends PerformanceScreen.PerformanceEntry>) entries, Math.max(inner.totalNano(), separateTime), false));
+ if (this.sortType == SortType.DURATION) {
+ entries.sort(Comparator.<PerformanceEntryImpl>comparingLong(value -> value.time).reversed());
+ }
+ subCategories.add(new SubCategoryListEntry(Component.literal(stage), (List<PerformanceScreen.PerformanceEntry>) (List<? extends PerformanceScreen.PerformanceEntry>) entries, Math.max(inner.totalNano(), separateTime), false));
});
+ if (this.sortType == SortType.DURATION) {
+ subCategories.sort(Comparator.comparingLong(SubCategoryListEntry::getTotalTime).reversed());
+ }
+ subCategories.forEach(list::addItem);
list.children().add(0, new PerformanceEntryImpl(Component.literal("Total Load Time"), totalTime[0]));
addWidget(list);
}
@@ -212,4 +238,9 @@ public class PerformanceScreen extends Screen {
return width - 6;
}
}
+
+ private enum SortType {
+ ORDER,
+ DURATION
+ }
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java
index 322c6cf5a..191192692 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java
@@ -156,6 +156,10 @@ public class SubCategoryListEntry extends PerformanceScreen.PerformanceEntry imp
return Collections.emptyList();
}
+ public long getTotalTime() {
+ return totalTime;
+ }
+
public class CategoryLabelWidget implements GuiEventListener {
private final Rectangle rectangle = new Rectangle();
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ScreenWithMenu.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ScreenWithMenu.java
new file mode 100644
index 000000000..c117f70e4
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ScreenWithMenu.java
@@ -0,0 +1,89 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.screen;
+
+import me.shedaniel.rei.impl.client.gui.modules.Menu;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+import org.jetbrains.annotations.Nullable;
+
+public class ScreenWithMenu extends Screen {
+ @Nullable
+ private Menu menu;
+
+ protected ScreenWithMenu(Component component) {
+ super(component);
+ }
+
+ @Override
+ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+ super.render(graphics, mouseX, mouseY, delta);
+ if (this.menu != null) {
+ graphics.pose().pushPose();
+ graphics.pose().translate(0, 0, 400);
+ this.menu.render(graphics, mouseX, mouseY, delta);
+ graphics.pose().popPose();
+ }
+ }
+
+ protected void setMenu(@Nullable Menu menu) {
+ this.menu = menu;
+ }
+
+ protected void closeMenu() {
+ this.menu = null;
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (this.menu != null) {
+ if (!this.menu.mouseClicked(mouseX, mouseY, button))
+ this.menu = null;
+ return true;
+ }
+ return super.mouseClicked(mouseX, mouseY, button);
+ }
+
+ @Override
+ public boolean mouseReleased(double mouseX, double mouseY, int button) {
+ if (this.menu != null && this.menu.mouseReleased(mouseX, mouseY, button))
+ return true;
+ return super.mouseReleased(mouseX, mouseY, button);
+ }
+
+ @Override
+ public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
+ if (this.menu != null && this.menu.mouseScrolled(mouseX, mouseY, amount))
+ return true;
+ return super.mouseScrolled(mouseX, mouseY, amount);
+ }
+
+ @Override
+ public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
+ if (this.menu != null && this.menu.mouseDragged(mouseX, mouseY, button, deltaX, deltaY))
+ return true;
+ return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
+ }
+}
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 499084650..81ee351ba 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
@@ -84,6 +84,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.*;
+import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
@@ -271,6 +272,12 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget {
return this;
}
+ @Override
+ public Slot withEntriesListener(Consumer<Slot> listener) {
+ this.getCyclingEntries().addListener($ -> listener.accept(this));
+ return this;
+ }
+
public Slot entries(CyclingList<EntryStack<?>> stacks) {
this.getCyclingEntries().setBacking(stacks);
if (removeTagMatch) tagMatch = null;
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCache.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCache.java
index b65aba97c..9c725efc4 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCache.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCache.java
@@ -34,6 +34,10 @@ import java.util.List;
import java.util.Set;
public interface DisplayCache {
+ int cachedSize();
+
+ int notCachedSize();
+
boolean doesCache();
boolean isCached(Display display);
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCacheImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCacheImpl.java
index 80a73f82e..4c995c9b0 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCacheImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayCacheImpl.java
@@ -54,6 +54,16 @@ public class DisplayCacheImpl implements DisplayCache {
}
@Override
+ public int cachedSize() {
+ return this.displaysCached.size();
+ }
+
+ @Override
+ public int notCachedSize() {
+ return this.displaysNotCached.size();
+ }
+
+ @Override
public boolean doesCache() {
return this.cache;
}
@@ -66,7 +76,7 @@ public class DisplayCacheImpl implements DisplayCache {
@Override
public void add(Display display) {
if (this.cache) {
- if (!preprocessed) {
+ if (!this.preprocessed) {
this.displaysNotCached.add(display);
} else {
this.process(display);
@@ -80,7 +90,7 @@ public class DisplayCacheImpl implements DisplayCache {
@Override
public boolean remove(Display display) {
if (this.cache) {
- if (!preprocessed) {
+ if (!this.preprocessed) {
return this.displaysNotCached.remove(display);
} else {
boolean removed = this.displaysCached.remove(display);
@@ -106,7 +116,7 @@ public class DisplayCacheImpl implements DisplayCache {
@Override
public void endReload() {
if (this.cache) {
- if (preprocessed) {
+ if (this.preprocessed) {
InternalLogger.getInstance().error("DisplayCache#endReload called after preprocessed!");
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java
index 9d03a4450..6da05cbfb 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java
@@ -23,7 +23,9 @@
package me.shedaniel.rei.impl.client.registry.display;
-import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
import dev.architectury.event.EventResult;
import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
import me.shedaniel.rei.api.client.registry.category.CategoryRegistry;
@@ -36,6 +38,7 @@ import me.shedaniel.rei.api.client.registry.display.visibility.DisplayVisibility
import me.shedaniel.rei.api.common.category.CategoryIdentifier;
import me.shedaniel.rei.api.common.display.Display;
import me.shedaniel.rei.api.common.plugins.PluginManager;
+import me.shedaniel.rei.api.common.registry.ReloadStage;
import me.shedaniel.rei.impl.common.InternalLogger;
import me.shedaniel.rei.impl.common.registry.RecipeManagerContextImpl;
import net.minecraft.world.item.crafting.Recipe;
@@ -56,10 +59,6 @@ public class DisplayRegistryImpl extends RecipeManagerContextImpl<REIClientPlugi
private long lastAddWarning = -1;
private DisplaysHolder displaysHolder = new DisplaysHolderImpl(false);
- public DisplayRegistryImpl() {
- super(RecipeManagerContextImpl.supplier());
- }
-
@Override
public void acceptPlugin(REIClientPlugin plugin) {
plugin.registerDisplays(this);
@@ -123,7 +122,11 @@ public class DisplayRegistryImpl extends RecipeManagerContextImpl<REIClientPlugi
@Override
public boolean isDisplayVisible(Display display) {
DisplayCategory<Display> category = (DisplayCategory<Display>) CategoryRegistry.getInstance().get(display.getCategoryIdentifier()).getCategory();
- Preconditions.checkNotNull(category, "Failed to resolve category: " + display.getCategoryIdentifier());
+ return isDisplayVisible(category, display);
+ }
+
+ public boolean isDisplayVisible(DisplayCategory<?> category, Display display) {
+ if (category == null) throw new NullPointerException("Failed to resolve category: " + display.getCategoryIdentifier());
for (DisplayVisibilityPredicate predicate : visibilityPredicates) {
try {
EventResult result = predicate.handleDisplay(category, display);
@@ -188,13 +191,8 @@ public class DisplayRegistryImpl extends RecipeManagerContextImpl<REIClientPlugi
@Override
public void endReload() {
- if (!fillers.isEmpty()) {
- List<RecipeHolder<?>> allSortedRecipes = getAllSortedRecipes();
- for (int i = allSortedRecipes.size() - 1; i >= 0; i--) {
- RecipeHolder<?> recipe = allSortedRecipes.get(i);
- addWithReason(recipe, DisplayAdditionReason.RECIPE_MANAGER);
- }
- }
+ InternalLogger.getInstance().debug("Found preliminary %d displays", displaySize());
+ fillSortedRecipes();
for (CategoryIdentifier<?> identifier : getAll().keySet()) {
if (CategoryRegistry.getInstance().tryGet(identifier).isEmpty()) {
@@ -202,21 +200,59 @@ public class DisplayRegistryImpl extends RecipeManagerContextImpl<REIClientPlugi
}
}
- List<Display> failedDisplays = new ArrayList<>();
+ removeFailedDisplays();
+ this.displaysHolder.endReload();
+ InternalLogger.getInstance().debug("%d displays registration have completed", displaySize());
+ }
+
+ private void fillSortedRecipes() {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ int lastSize = displaySize();
+ if (!fillers.isEmpty()) {
+ List<RecipeHolder<?>> allSortedRecipes = getAllSortedRecipes();
+ for (int i = allSortedRecipes.size() - 1; i >= 0; i--) {
+ RecipeHolder<?> recipe = allSortedRecipes.get(i);
+ try {
+ addWithReason(recipe, DisplayAdditionReason.RECIPE_MANAGER);
+ } catch (Throwable e) {
+ InternalLogger.getInstance().error("Failed to fill display for recipe: %s [%s]", recipe, recipe.getId(), e);
+ }
+ }
+ }
+ InternalLogger.getInstance().debug("Filled %d displays from recipe manager in %s", displaySize() - lastSize, stopwatch.stop());
+ }
+
+ private void removeFailedDisplays() {
+ Multimap<CategoryIdentifier<?>, Display> failedDisplays = Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
for (List<Display> displays : getAll().values()) {
for (Display display : displays) {
if (!DisplayValidator.validate(display)) {
- failedDisplays.add(display);
+ failedDisplays.put(display.getCategoryIdentifier(), display);
}
}
}
- for (Display display : failedDisplays) {
- this.displaysHolder.remove(display);
- }
-
- this.displaysHolder.endReload();
- InternalLogger.getInstance().debug("Registered %d displays", displaySize());
+ InternalLogger.getInstance().debug("Removing %d failed displays" + (!failedDisplays.isEmpty() ? ":" : ""), failedDisplays.size());
+ failedDisplays.asMap().entrySet().stream()
+ .sorted(Comparator.comparing(entry -> entry.getKey().toString()))
+ .forEach(entry -> {
+ InternalLogger.getInstance().debug("- %s: %d failed display" + (entry.getValue().size() == 1 ? "" : "s"), entry.getKey(), entry.getValue().size());
+ for (Display display : entry.getVa