aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2021-10-22 01:40:06 +0800
committershedaniel <daniel@shedaniel.me>2021-10-22 01:55:30 +0800
commitc8f1c10e6c661ecf949ab29e0e8efeaa13324670 (patch)
tree4628eb7559a385d00f62e2f6eee9b2a9d8c59f00 /runtime
parent62045c9cc0416557e6b57b6f4101b98a0da02dde (diff)
downloadRoughlyEnoughItems-c8f1c10e6c661ecf949ab29e0e8efeaa13324670.tar.gz
RoughlyEnoughItems-c8f1c10e6c661ecf949ab29e0e8efeaa13324670.tar.bz2
RoughlyEnoughItems-c8f1c10e6c661ecf949ab29e0e8efeaa13324670.zip
Add Performance Analysis
Diffstat (limited to 'runtime')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java8
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java10
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java5
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java193
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/EntryListEntry.java71
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java93
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java177
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLogger.java56
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java96
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java95
-rwxr-xr-xruntime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json1
13 files changed, 778 insertions, 31 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java
index 119841487..654552028 100644
--- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java
+++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java
@@ -55,6 +55,8 @@ import me.shedaniel.rei.impl.common.logging.FileLogger;
import me.shedaniel.rei.impl.common.logging.Log4JLogger;
import me.shedaniel.rei.impl.common.logging.Logger;
import me.shedaniel.rei.impl.common.logging.MultiLogger;
+import me.shedaniel.rei.impl.common.logging.performance.PerformanceLogger;
+import me.shedaniel.rei.impl.common.logging.performance.PerformanceLoggerImpl;
import me.shedaniel.rei.impl.common.plugins.PluginManagerImpl;
import me.shedaniel.rei.impl.common.registry.RecipeManagerContextImpl;
import me.shedaniel.rei.impl.common.transfer.MenuInfoRegistryImpl;
@@ -75,6 +77,7 @@ public class RoughlyEnoughItemsCore {
new FileLogger(Platform.getGameFolder().resolve("logs/rei.log")),
new Log4JLogger(LogManager.getFormatterLogger("REI"))
));
+ public static final PerformanceLogger PERFORMANCE_LOGGER = new PerformanceLoggerImpl();
static {
attachCommonInternals();
@@ -151,7 +154,10 @@ public class RoughlyEnoughItemsCore {
if (Platform.getEnvironment() == Env.SERVER) {
MutableLong lastReload = new MutableLong(-1);
ReloadListenerRegistry.register(PackType.SERVER_DATA, (preparationBarrier, resourceManager, profilerFiller, profilerFiller2, executor, executor2) -> {
- return preparationBarrier.wait(Unit.INSTANCE).thenRunAsync(() -> RoughlyEnoughItemsCore._reloadPlugins(null), executor2);
+ return preparationBarrier.wait(Unit.INSTANCE).thenRunAsync(() -> {
+ PERFORMANCE_LOGGER.clear();
+ RoughlyEnoughItemsCore._reloadPlugins(null);
+ }, executor2);
});
}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
index 9f0b4552f..131592218 100644
--- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
+++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
@@ -272,8 +272,14 @@ public class RoughlyEnoughItemsCoreClient {
final ResourceLocation recipeButtonTex = new ResourceLocation("textures/gui/recipe_button.png");
MutableLong startReload = new MutableLong(-1);
MutableLong endReload = new MutableLong(-1);
- PRE_UPDATE_RECIPES.register(recipeManager -> reloadPlugins(startReload, ReloadStage.START));
- ClientRecipeUpdateEvent.EVENT.register(recipeManager -> reloadPlugins(endReload, Platform.isFabric() ? ReloadStage.END : null));
+ PRE_UPDATE_RECIPES.register(recipeManager -> {
+ RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear();
+ reloadPlugins(startReload, ReloadStage.START);
+ });
+ ClientRecipeUpdateEvent.EVENT.register(recipeManager -> {
+ if (!Platform.isFabric()) RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear();
+ reloadPlugins(endReload, Platform.isFabric() ? ReloadStage.END : null);
+ });
ClientGuiEvent.INIT_POST.register((screen, access) -> {
REIRuntimeImpl.getInstance().setPreviousScreen(screen);
if (ConfigObject.getInstance().doesDisableRecipeBook() && screen instanceof AbstractContainerScreen) {
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 f582734e2..e6eefa6b6 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
@@ -63,6 +63,7 @@ import me.shedaniel.rei.impl.client.entry.filtering.FilteringRule;
import me.shedaniel.rei.impl.client.entry.filtering.rules.ManualFilteringRule;
import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl;
import me.shedaniel.rei.impl.client.gui.credits.CreditsScreen;
+import me.shedaniel.rei.impl.client.gui.performance.entry.PerformanceEntry;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.ChatFormatting;
@@ -340,6 +341,7 @@ public class ConfigManagerImpl implements ConfigManager {
builder.setGlobalizedExpanded(false);
if (Minecraft.getInstance().getConnection() != null && Minecraft.getInstance().getConnection().getRecipeManager() != null) {
builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.advanced")).getEntries().add(0, new ReloadPluginsEntry(220));
+ builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.advanced")).getEntries().add(0, new PerformanceEntry(220));
}
return builder.setAfterInitConsumer(screen -> {
TextListEntry feedbackEntry = ConfigEntryBuilder.create().startTextDescription(
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java
index a96680983..6452e883c 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java
@@ -48,7 +48,10 @@ import java.util.Optional;
@ApiStatus.Internal
public class ReloadPluginsEntry extends AbstractConfigListEntry<Unit> {
private int width;
- private AbstractWidget buttonWidget = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> RoughlyEnoughItemsCoreClient.reloadPlugins(null, null)) {
+ private AbstractWidget buttonWidget = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> {
+ RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear();
+ RoughlyEnoughItemsCoreClient.reloadPlugins(null, null);
+ }) {
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
if (PluginManager.areAnyReloading()) {
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
new file mode 100644
index 000000000..92bfb78be
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java
@@ -0,0 +1,193 @@
+/*
+ * 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.performance;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.datafixers.util.Pair;
+import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget;
+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.impl.client.gui.performance.entry.EntryListEntry;
+import me.shedaniel.rei.impl.client.gui.performance.entry.SubCategoryListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiComponent;
+import net.minecraft.client.gui.components.Button;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TextColor;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.network.chat.TranslatableComponent;
+import net.minecraft.util.FormattedCharSequence;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static java.util.concurrent.TimeUnit.*;
+
+@Environment(EnvType.CLIENT)
+public class PerformanceScreen extends Screen {
+ private Screen parent;
+
+ public PerformanceScreen(Screen parent) {
+ super(new TranslatableComponent("text.rei.performance"));
+ this.parent = parent;
+ }
+
+ private PerformanceEntryListWidget list;
+
+ /*
+ * Copyright (C) 2008 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+ public static FormattedCharSequence formatTime(long time, boolean total) {
+ TimeUnit unit = chooseUnit(time);
+ double value = (double) time / NANOSECONDS.convert(1, unit);
+ return new TextComponent(String.format(Locale.ROOT, "%.4g", value) + " " + abbreviate(unit))
+ .withStyle(style -> style.withColor(TextColor.fromRgb(chooseColor(MILLISECONDS.convert(time, NANOSECONDS), total))))
+ .getVisualOrderText();
+ }
+
+ private static int chooseColor(long time, boolean total) {
+ if (time > (total ? 2500 : 1000)) {
+ return 0xff5555;
+ } else if (time > (total ? 700 : 300)) {
+ return 0xffa600;
+ } else if (time > (total ? 200 : 100)) {
+ return 0xfff017;
+ }
+ return 0x12ff22;
+ }
+
+ private static TimeUnit chooseUnit(long nanos) {
+ if (DAYS.convert(nanos, NANOSECONDS) > 0) {
+ return DAYS;
+ }
+ if (HOURS.convert(nanos, NANOSECONDS) > 0) {
+ return HOURS;
+ }
+ if (MINUTES.convert(nanos, NANOSECONDS) > 0) {
+ return MINUTES;
+ }
+ if (SECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return SECONDS;
+ }
+ if (MILLISECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return MILLISECONDS;
+ }
+ if (MICROSECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return MICROSECONDS;
+ }
+ return NANOSECONDS;
+ }
+
+ private static String abbreviate(TimeUnit unit) {
+ switch (unit) {
+ case NANOSECONDS:
+ return "ns";
+ case MICROSECONDS:
+ return "\u03bcs"; // μs
+ case MILLISECONDS:
+ return "ms";
+ case SECONDS:
+ return "s";
+ case MINUTES:
+ return "min";
+ case HOURS:
+ return "h";
+ case DAYS:
+ return "d";
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @Override
+ public void init() {
+ {
+ Component backText = new TextComponent("↩ ").append(new TranslatableComponent("gui.back"));
+ addRenderableWidget(new Button(4, 4, Minecraft.getInstance().font.width(backText) + 10, 20, backText, button -> {
+ minecraft.setScreen(parent);
+ this.parent = null;
+ }));
+ }
+ list = new PerformanceEntryListWidget();
+ RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.getStages().forEach((stage, inner) -> {
+ List<EntryListEntry> entries = new ArrayList<>();
+ inner.times().forEach((obj, time) -> {
+ entries.add(new EntryListEntry(new TextComponent(obj instanceof Pair ? ((Pair<REIPluginProvider<?>, REIPlugin<?>>) obj).getFirst().getPluginProviderName() : Objects.toString(obj)), time));
+ });
+ long separateTime = inner.times().values().stream().collect(Collectors.summarizingLong(value -> value)).getSum();
+ if ((inner.totalNano() - separateTime) > 1000000) {
+ entries.add(new EntryListEntry(new TextComponent("Miscellaneous Operations"), inner.totalNano() - separateTime));
+ }
+ entries.sort(Comparator.<EntryListEntry>comparingLong(value -> value.time).reversed());
+ list.addItem(new SubCategoryListEntry(new TextComponent(stage), (List<PerformanceScreen.PerformanceEntry>) (List<? extends PerformanceScreen.PerformanceEntry>) entries, inner.totalNano(), false));
+ });
+ addWidget(list);
+ }
+
+ @Override
+ public void render(PoseStack poses, int mouseX, int mouseY, float delta) {
+ renderDirtBackground(0);
+ list.render(poses, mouseX, mouseY, delta);
+ this.font.drawShadow(poses, this.title.getVisualOrderText(), this.width / 2.0F - this.font.width(this.title) / 2.0F, 12.0F, -1);
+ super.render(poses, mouseX, mouseY, delta);
+ }
+
+ public static abstract class PerformanceEntry extends DynamicElementListWidget.ElementEntry<PerformanceEntry> {
+
+ }
+
+ private class PerformanceEntryListWidget extends DynamicElementListWidget<PerformanceEntry> {
+ public PerformanceEntryListWidget() {super(PerformanceScreen.this.minecraft, PerformanceScreen.this.width, PerformanceScreen.this.height, 30, PerformanceScreen.this.height, GuiComponent.BACKGROUND_LOCATION);}
+
+ @Override
+ public int getItemWidth() {
+ return width;
+ }
+
+ @Override
+ public int addItem(PerformanceEntry item) {
+ return super.addItem(item);
+ }
+
+ @Override
+ protected int getScrollbarPosition() {
+ return width - 6;
+ }
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/EntryListEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/EntryListEntry.java
new file mode 100644
index 000000000..5c2db0471
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/EntryListEntry.java
@@ -0,0 +1,71 @@
+/*
+ * 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.performance.entry;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.rei.impl.client.gui.performance.PerformanceScreen;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.components.events.GuiEventListener;
+import net.minecraft.client.gui.narration.NarratableEntry;
+import net.minecraft.network.chat.Component;
+import net.minecraft.util.FormattedCharSequence;
+
+import java.util.Collections;
+import java.util.List;
+
+@Environment(EnvType.CLIENT)
+public class EntryListEntry extends PerformanceScreen.PerformanceEntry {
+ private final Component name;
+ public final long time;
+
+ public EntryListEntry(Component name, long time) {
+ this.name = name;
+ this.time = time;
+ }
+
+ public void render(PoseStack matrices, 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);
+ Minecraft.getInstance().font.drawShadow(matrices, this.name.getVisualOrderText(), (float) x, (float) (y + 6), -1);
+ FormattedCharSequence timeText = PerformanceScreen.formatTime(time, false);
+ Minecraft.getInstance().font.drawShadow(matrices, timeText, (float) x + entryWidth - 6 - 4 - Minecraft.getInstance().font.width(timeText), (float) (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();
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java
new file mode 100644
index 000000000..99b84ef5d
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java
@@ -0,0 +1,93 @@
+/*
+ * 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.performance.entry;
+
+import com.google.common.collect.ImmutableList;
+import com.mojang.blaze3d.platform.Window;
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import me.shedaniel.rei.impl.client.gui.performance.PerformanceScreen;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.chat.NarratorChatListener;
+import net.minecraft.client.gui.components.AbstractWidget;
+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.network.chat.TranslatableComponent;
+import net.minecraft.util.Unit;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.List;
+import java.util.Optional;
+
+@ApiStatus.Internal
+public class PerformanceEntry extends AbstractConfigListEntry<Unit> {
+ private int width;
+ private AbstractWidget buttonWidget = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> {
+ Minecraft.getInstance().setScreen(new PerformanceScreen(Minecraft.getInstance().screen));
+ });
+ private List<AbstractWidget> children = ImmutableList.of(buttonWidget);
+
+ public PerformanceEntry(int width) {
+ super(NarratorChatListener.NO_TITLE, false);
+ this.width = width;
+ buttonWidget.setMessage(new TranslatableComponent("text.rei.performance"));
+ }
+
+ @Override
+ public Unit getValue() {
+ return Unit.INSTANCE;
+ }
+
+ @Override
+ public Optional<Unit> getDefaultValue() {
+ return Optional.of(Unit.INSTANCE);
+ }
+
+ @Override
+ public void save() {
+
+ }
+
+ @Override
+ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
+ super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta);
+ Window window = Minecraft.getInstance().getWindow();
+ this.buttonWidget.active = this.isEditable();
+ this.buttonWidget.y = y;
+ this.buttonWidget.x = x + entryWidth / 2 - width / 2;
+ this.buttonWidget.setWidth(width);
+ this.buttonWidget.render(matrices, mouseX, mouseY, delta);
+ }
+
+ @Override
+ public List<? extends GuiEventListener> children() {
+ return children;
+ }
+
+ @Override
+ public List<? extends NarratableEntry> narratables() {
+ return children;
+ }
+}
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
new file mode 100644
index 000000000..dfb63d959
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java
@@ -0,0 +1,177 @@
+/*
+ * 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.performance.entry;
+
+import com.google.common.collect.Lists;
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.api.Expandable;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.impl.client.gui.performance.PerformanceScreen;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.components.events.GuiEventListener;
+import net.minecraft.client.gui.narration.NarratableEntry;
+import net.minecraft.client.resources.sounds.SimpleSoundInstance;
+import net.minecraft.network.chat.Component;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.sounds.SoundEvents;
+import net.minecraft.util.FormattedCharSequence;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+@Environment(EnvType.CLIENT)
+public class SubCategoryListEntry extends PerformanceScreen.PerformanceEntry implements Expandable {
+ private static final ResourceLocation CONFIG_TEX = new ResourceLocation("cloth-config2", "textures/gui/cloth_config.png");
+ private final List<PerformanceScreen.PerformanceEntry> entries;
+ private final CategoryLabelWidget widget;
+ private final List<GuiEventListener> children;
+ private final Component name;
+ private final long totalTime;
+ private boolean expanded;
+
+ public SubCategoryListEntry(Component name, List<PerformanceScreen.PerformanceEntry> entries, long totalTime, boolean defaultExpanded) {
+ this.name = name;
+ this.entries = entries;
+ this.totalTime = totalTime;
+ this.expanded = defaultExpanded;
+ this.widget = new CategoryLabelWidget();
+ this.children = Lists.newArrayList(new GuiEventListener[]{this.widget});
+ this.children.addAll(entries);
+ }
+
+ @Override
+ public boolean isExpanded() {
+ return this.expanded;
+ }
+
+ @Override
+ public void setExpanded(boolean expanded) {
+ this.expanded = expanded;
+ }
+
+ @Override
+ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) {
+ RenderSystem.setShaderTexture(0, CONFIG_TEX);
+ RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
+ this.widget.rectangle.x = x + 3;
+ this.widget.rectangle.y = y;
+ this.widget.rectangle.width = entryWidth - 6;
+ this.widget.rectangle.height = 24;
+ this.blit(matrices, x + 3, y + 5, 24, (this.widget.rectangle.contains(mouseX, mouseY) ? 18 : 0) + (this.expanded ? 9 : 0), 9, 9);
+ Minecraft.getInstance().font.drawShadow(matrices, this.name.getVisualOrderText(), (float) x + 3 + 15, (float) (y + 6), this.widget.rectangle.contains(mouseX, mouseY) ? -1638890 : -1);
+
+ for (PerformanceScreen.PerformanceEntry performanceEntry : this.entries) {
+ performanceEntry.setParent(this.getParent());
+ }
+
+ if (this.expanded) {
+ int yy = y + 24;
+
+ PerformanceScreen.PerformanceEntry entry;
+ for (Iterator<PerformanceScreen.PerformanceEntry> iterator = this.entries.iterator(); iterator.hasNext(); yy += entry.getItemHeight()) {
+ entry = iterator.next();
+ entry.render(matrices, -1, yy, x + 3 + 15, entryWidth - 15 - 3, entry.getItemHeight(), mouseX, mouseY, isHovered && this.getFocused() == entry, delta);
+ }
+ }
+ FormattedCharSequence timeText = PerformanceScreen.formatTime(totalTime, true);
+ Minecraft.getInstance().font.drawShadow(matrices, timeText, (float) x + entryWidth - 6 - 4 - Minecraft.getInstance().font.width(timeText), (float) (y + 6), -1);
+ }
+
+ @Override
+ public int getMorePossibleHeight() {
+ if (!this.expanded) {
+ return -1;
+ } else {
+ List<Integer> list = new ArrayList();
+ int i = 24;
+
+ for (PerformanceScreen.PerformanceEntry entry : this.entries) {
+ i += entry.getItemHeight();
+ if (entry.getMorePossibleHeight() >= 0) {
+ list.add(i + entry.getMorePossibleHeight());
+ }
+ }
+
+ list.add(i);
+ return list.stream().max(Integer::compare).orElse(0) - this.getItemHeight();
+ }
+ }
+
+ public Rectangle getEntryArea(int x, int y, int entryWidth, int entryHeight) {
+ this.widget.rectangle.x = x;
+ this.widget.rectangle.y = y;
+ this.widget.rectangle.width = entryWidth;
+ this.widget.rectangle.height = 24;
+ return new Rectangle(this.getParent().left, y, this.getParent().right - this.getParent().left, 20);
+ }
+
+ @Override
+ public int getItemHeight() {
+ if (!this.expanded) {
+ return 24;
+ } else {
+ int i = 24;
+
+ PerformanceScreen.PerformanceEntry entry;
+ for (Iterator<PerformanceScreen.PerformanceEntry> iterator = this.entries.iterator(); iterator.hasNext(); i += entry.getItemHeight()) {
+ entry = iterator.next();
+ }
+
+ return i;
+ }
+ }
+
+ @Override
+ public List<? extends GuiEventListener> children() {
+ return this.expanded ? this.children : Collections.singletonList(this.widget);
+ }
+
+ @Override
+ public List<? extends NarratableEntry> narratables() {
+ return Collections.emptyList();
+ }
+
+ public class CategoryLabelWidget implements GuiEventListener {
+ private final Rectangle rectangle = new Rectangle();
+
+ public CategoryLabelWidget() {
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (this.rectangle.contains(mouseX, mouseY)) {
+ SubCategoryListEntry.this.expanded = !SubCategoryListEntry.this.expanded;
+ Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java
index 1ec5aa3f5..5f98de662 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java
@@ -34,6 +34,7 @@ import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWi
import me.shedaniel.clothconfig2.impl.EasingMethod;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.RoughlyEnoughItemsCore;
import me.shedaniel.rei.RoughlyEnoughItemsCoreClient;
import me.shedaniel.rei.api.client.ClientHelper;
import me.shedaniel.rei.api.client.REIRuntime;
@@ -146,6 +147,7 @@ public class UncertainDisplayViewingScreen extends Screen {
} else if (allModsUsingJEI != null && jeiEnabled) {
ConfigManagerImpl.getInstance().getConfig().setJEICompatibilityLayerEnabled(jeiEnabled);
ConfigManager.getInstance().saveConfig();
+ RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear();
RoughlyEnoughItemsCoreClient.reloadPlugins(null, null);
Minecraft.getInstance().setScreen(new ConfigReloadingScreen(() -> callback.accept(original)));
} else {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLogger.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLogger.java
new file mode 100644
index 000000000..7dca73ca7
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLogger.java
@@ -0,0 +1,56 @@