aboutsummaryrefslogtreecommitdiff
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
parent62045c9cc0416557e6b57b6f4101b98a0da02dde (diff)
downloadRoughlyEnoughItems-c8f1c10e6c661ecf949ab29e0e8efeaa13324670.tar.gz
RoughlyEnoughItems-c8f1c10e6c661ecf949ab29e0e8efeaa13324670.tar.bz2
RoughlyEnoughItems-c8f1c10e6c661ecf949ab29e0e8efeaa13324670.zip
Add Performance Analysis
-rw-r--r--fabric/build.gradle2
-rw-r--r--fabric/src/main/java/me/shedaniel/rei/fabric/PluginDetectorImpl.java13
-rw-r--r--forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java12
-rw-r--r--forge/src/main/java/me/shedaniel/rei/forge/RoughlyEnoughItemsForge.java20
-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
17 files changed, 801 insertions, 55 deletions
diff --git a/fabric/build.gradle b/fabric/build.gradle
index 6d42ecee2..f91ffc538 100644
--- a/fabric/build.gradle
+++ b/fabric/build.gradle
@@ -34,7 +34,7 @@ dependencies {
modApi("me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}") {
exclude(module: "fabric-api")
}
- modRuntime("com.terraformersmc:modmenu:${modmenu_version}") { transitive false }
+ //modRuntime("com.terraformersmc:modmenu:${modmenu_version}") { transitive false }
modApi("dev.architectury:architectury-fabric:${architectury_version}")
depProjects.forEach {
diff --git a/fabric/src/main/java/me/shedaniel/rei/fabric/PluginDetectorImpl.java b/fabric/src/main/java/me/shedaniel/rei/fabric/PluginDetectorImpl.java
index c44ae6a06..711437449 100644
--- a/fabric/src/main/java/me/shedaniel/rei/fabric/PluginDetectorImpl.java
+++ b/fabric/src/main/java/me/shedaniel/rei/fabric/PluginDetectorImpl.java
@@ -80,7 +80,8 @@ public class PluginDetectorImpl {
} catch (Throwable t) {
Throwable throwable = t;
while (throwable != null) {
- if (throwable.getMessage() != null && throwable.getMessage().contains("environment type SERVER") && !RoughlyEnoughItemsInitializer.isClient()) continue out;
+ if (throwable.getMessage() != null && throwable.getMessage().contains("environment type SERVER") && !RoughlyEnoughItemsInitializer.isClient())
+ continue out;
throwable = throwable.getCause();
}
String error = "Could not create REI Plugin [" + getSimpleName(pluginClass) + "] due to errors, provided by '" + container.getProvider().getMetadata().getId() + "'!";
@@ -98,12 +99,10 @@ public class PluginDetectorImpl {
public static void detectServerPlugins() {
loadPlugin(REIServerPlugin.class, ((PluginView<REIServerPlugin>) PluginManager.getServerInstance())::registerPlugin);
- if (FabricLoader.getInstance().isModLoaded("libblockattributes-fluids")) {
- try {
- PluginView.getServerInstance().registerPlugin((REIServerPlugin) Class.forName("me.shedaniel.rei.impl.common.compat.FabricFluidAPISupportPlugin").getConstructor().newInstance());
- } catch (Throwable throwable) {
- throwable.printStackTrace();
- }
+ try {
+ PluginView.getServerInstance().registerPlugin((REIServerPlugin) Class.forName("me.shedaniel.rei.impl.common.compat.FabricFluidAPISupportPlugin").getConstructor().newInstance());
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
}
}
diff --git a/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java b/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java
index cc7ea594d..aace5aa12 100644
--- a/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java
+++ b/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java
@@ -40,12 +40,12 @@ import me.shedaniel.rei.plugin.common.runtime.DefaultRuntimePlugin;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
+import org.apache.logging.log4j.util.TriConsumer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.function.BiConsumer;
import java.util.function.Supplier;
public class PluginDetectorImpl {
@@ -74,14 +74,14 @@ public class PluginDetectorImpl {
PluginView.getServerInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultPlugin()));
PluginView.getServerInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultRuntimePlugin()));
PluginView.getServerInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new JEIExtraPlugin()));
- RoughlyEnoughItemsForge.<REIPlugin, REIServerPlugin>scanAnnotation(REIPlugin.class, REIServerPlugin.class::isAssignableFrom, (modId, plugin) -> {
+ RoughlyEnoughItemsForge.<REIPlugin, REIServerPlugin>scanAnnotation(REIPlugin.class, REIServerPlugin.class::isAssignableFrom, (modId, plugin, clazz) -> {
((PluginView<REIServerPlugin>) PluginManager.getServerInstance()).registerPlugin(wrapPlugin(modId, plugin.get()));
});
}
public static void detectCommonPlugins() {
EventBuses.registerModEventBus("roughlyenoughitems", FMLJavaModLoadingContext.get().getModEventBus());
- RoughlyEnoughItemsForge.<REIPlugin, me.shedaniel.rei.api.common.plugins.REIPlugin<?>>scanAnnotation(REIPlugin.class, me.shedaniel.rei.api.common.plugins.REIPlugin.class::isAssignableFrom, (modId, plugin) -> {
+ RoughlyEnoughItemsForge.<REIPlugin, me.shedaniel.rei.api.common.plugins.REIPlugin<?>>scanAnnotation(REIPlugin.class, me.shedaniel.rei.api.common.plugins.REIPlugin.class::isAssignableFrom, (modId, plugin, clazz) -> {
((PluginView) PluginManager.getInstance()).registerPlugin(wrapPlugin(modId, plugin.get()));
});
}
@@ -91,7 +91,7 @@ public class PluginDetectorImpl {
PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultClientPlugin()));
PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultClientRuntimePlugin()));
PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new JEIExtraClientPlugin()));
- RoughlyEnoughItemsForge.<REIPlugin, REIClientPlugin>scanAnnotation(REIPlugin.class, REIClientPlugin.class::isAssignableFrom, (modId, plugin) -> {
+ RoughlyEnoughItemsForge.<REIPlugin, REIClientPlugin>scanAnnotation(REIPlugin.class, REIClientPlugin.class::isAssignableFrom, (modId, plugin, clazz) -> {
((PluginView<REIClientPlugin>) PluginManager.getClientInstance()).registerPlugin(wrapPlugin(modId, plugin.get()));
});
ClientInternals.attachInstance((Supplier<List<String>>) () -> {
@@ -103,7 +103,7 @@ public class PluginDetectorImpl {
}
return modIds;
}, "jeiCompatMods");
- JEIPluginDetector.detect((aClass, consumer) -> RoughlyEnoughItemsForge.scanAnnotation((Class<Object>) aClass, clazz -> true,
- (BiConsumer<List<String>, Supplier<Object>>) (BiConsumer) consumer), PluginView.getClientInstance()::registerPlugin);
+ JEIPluginDetector.detect((aClass, consumer) -> RoughlyEnoughItemsForge.scanAnnotation((Class<Object>) aClass, c -> true,
+ (TriConsumer<List<String>, Supplier<Object>, Class<Object>>) (TriConsumer) consumer), PluginView.getClientInstance()::registerPlugin);
}
}
diff --git a/forge/src/main/java/me/shedaniel/rei/forge/RoughlyEnoughItemsForge.java b/forge/src/main/java/me/shedaniel/rei/forge/RoughlyEnoughItemsForge.java
index dc9dc0175..dd5824c70 100644
--- a/forge/src/main/java/me/shedaniel/rei/forge/RoughlyEnoughItemsForge.java
+++ b/forge/src/main/java/me/shedaniel/rei/forge/RoughlyEnoughItemsForge.java
@@ -31,15 +31,15 @@ import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.ModFileScanData;
-import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.ImmutableTriple;
+import org.apache.commons.lang3.tuple.Triple;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.util.TriConsumer;
import org.jetbrains.annotations.ApiStatus;
import org.objectweb.asm.Type;
import java.util.List;
-import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -54,12 +54,12 @@ public class RoughlyEnoughItemsForge {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> RoughlyEnoughItemsInitializer::onInitializeClient);
}
- public static <A, T> void scanAnnotation(Class<A> clazz, Predicate<Class<T>> predicate, BiConsumer<List<String>, Supplier<T>> consumer) {
+ public static <A, T> void scanAnnotation(Class<A> clazz, Predicate<Class<T>> predicate, TriConsumer<List<String>, Supplier<T>, Class<T>> consumer) {
scanAnnotation(Type.getType(clazz), predicate, consumer);
}
- public static <T> void scanAnnotation(Type annotationType, Predicate<Class<T>> predicate, BiConsumer<List<String>, Supplier<T>> consumer) {
- List<Pair<List<String>, Supplier<T>>> instances = Lists.newArrayList();
+ public static <T> void scanAnnotation(Type annotationType, Predicate<Class<T>> predicate, TriConsumer<List<String>, Supplier<T>, Class<T>> consumer) {
+ List<Triple<List<String>, Supplier<T>, Class<T>>> instances = Lists.newArrayList();
for (ModFileScanData data : ModList.get().getAllScanData()) {
List<String> modIds = data.getIModInfoData().stream()
.flatMap(info -> info.getMods().stream())
@@ -70,14 +70,14 @@ public class RoughlyEnoughItemsForge {
try {
Class<T> clazz = (Class<T>) Class.forName(annotation.memberName());
if (predicate.test(clazz)) {
- instances.add(new ImmutablePair<>(modIds, () -> {
+ instances.add(new ImmutableTriple<>(modIds, () -> {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Throwable throwable) {
LOGGER.error("Failed to load plugin: " + annotation.memberName(), throwable);
return null;
}
- }));
+ }, clazz));
}
} catch (Throwable throwable) {
LOGGER.error("Failed to load plugin: " + annotation.memberName(), throwable);
@@ -86,8 +86,8 @@ public class RoughlyEnoughItemsForge {
}
}
- for (Pair<List<String>, Supplier<T>> pair : instances) {
- consumer.accept(pair.getLeft(), pair.getRight());
+ for (Triple<List<String>, Supplier<T>, Class<T>> pair : instances) {
+ consumer.accept(pair.getLeft(), pair.getMiddle(), pair.getRight());
}
}
}
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) {
+