mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-10-26 14:24:07 +00:00
Refactor recipe profiler (#911)
This commit is contained in:
1 parent
d25365942a
commit
8f949bc1d1
7 files changed
+226
-92
No files matched your search
@@ -73,6 +73,7 @@ public class IMCForNEI {
|
||||
|
||||
API.registerRecipeHandler(new ProfilerRecipeHandler(true));
|
||||
API.registerUsageHandler(new ProfilerRecipeHandler(false));
|
||||
sendProfilerRecipeHandler();
|
||||
}
|
||||
|
||||
private static void sendHandler(String aName, String aBlock) {
|
||||
@@ -136,6 +137,19 @@ public class IMCForNEI {
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
|
||||
}
|
||||
|
||||
private static void sendProfilerRecipeHandler() {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handler", "codechicken.nei.recipe.ProfilerRecipeHandler");
|
||||
aNBT.setString("modName", "Not Enough Items");
|
||||
aNBT.setString("modId", "nei");
|
||||
aNBT.setString("itemName", "minecraft:clock");
|
||||
aNBT.setInteger("handlerHeight", 16);
|
||||
aNBT.setInteger("handlerWidth", 166);
|
||||
aNBT.setBoolean("multipleWidgetsAllowed", true);
|
||||
aNBT.setInteger("yShift", 0);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
|
||||
}
|
||||
|
||||
private static void sendCatalyst(String aName, String aStack) {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handlerID", aName);
|
||||
|
||||
@@ -91,10 +91,6 @@ public class PositionedStack {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getCustomBadge() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getChance() {
|
||||
return this.chance;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ public class Badge {
|
||||
this.text = text;
|
||||
this.tooltip = Arrays.stream(tooltip).map(t -> EnumChatFormatting.GRAY + t).collect(Collectors.toList());
|
||||
this.badgeTextColor = getHexValue(
|
||||
NEIClientUtils.getTextColorOrDefault("recipe.badge.color", "0xFFAA00"),
|
||||
0xFFAA00);
|
||||
NEIClientUtils.getTextColorOrDefault("recipe.badge.color", "0xFDD835"),
|
||||
0xFDD835);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
|
||||
@@ -23,12 +23,12 @@ import net.minecraftforge.common.MinecraftForge;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.Widget;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.event.NEIRegisterHandlerInfosEvent;
|
||||
@@ -139,18 +139,16 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
|
||||
public void addTooltips(List<String> tooltip) {
|
||||
tooltip.add(handler.getRecipeTabName().trim());
|
||||
|
||||
String handlerMod = getHandlerMod(handlerName, handlerID);
|
||||
tooltip.add(EnumChatFormatting.BLUE + handlerMod);
|
||||
|
||||
boolean shiftHeld = Keyboard.getEventKeyState()
|
||||
&& (Keyboard.getEventKey() == Keyboard.KEY_LSHIFT || Keyboard.getEventKey() == Keyboard.KEY_RSHIFT);
|
||||
if (handlerMod.equals("Unknown") || shiftHeld) {
|
||||
if (handlerMod.equals("Unknown") || NEIClientUtils.shiftKey()) {
|
||||
tooltip.add("");
|
||||
tooltip.add("HandlerName: " + handlerName);
|
||||
tooltip.add("HandlerID: " + handlerID);
|
||||
tooltip.add("HandlerOrder: " + NEIClientConfig.getHandlerOrder(handler));
|
||||
tooltip.add(EnumChatFormatting.GRAY + "HandlerName: " + handlerName);
|
||||
tooltip.add(EnumChatFormatting.GRAY + "HandlerID: " + handlerID);
|
||||
tooltip.add(EnumChatFormatting.GRAY + "HandlerOrder: " + NEIClientConfig.getHandlerOrder(handler));
|
||||
}
|
||||
|
||||
tooltip.add(EnumChatFormatting.BLUE + handlerMod);
|
||||
}
|
||||
|
||||
public abstract boolean onButtonPress(boolean rightclick);
|
||||
|
||||
@@ -263,12 +263,6 @@ public class NEIRecipeWidget extends Widget {
|
||||
final List<Badge> badges = k.getBadges();
|
||||
|
||||
if (badges == null) {
|
||||
final String customBadge = k.getCustomBadge();
|
||||
|
||||
if (customBadge != null) {
|
||||
return customBadge.isEmpty() ? Collections.emptyList()
|
||||
: Collections.singletonList(new Badge(customBadge));
|
||||
}
|
||||
|
||||
if (input) {
|
||||
if (StackInfo.getAmount(pStack.item) == 0) {
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawString;
|
||||
import static codechicken.lib.gui.GuiDraw.getStringWidth;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import codechicken.core.TaskProfiler.ProfilerResult;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
@@ -20,12 +28,104 @@ import codechicken.nei.util.AsyncTaskProfiler;
|
||||
|
||||
public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
|
||||
|
||||
private static final AsyncTaskProfiler profiler = new AsyncTaskProfiler();
|
||||
public static class RecipeProfiler {
|
||||
|
||||
private final AsyncTaskProfiler profiler = new AsyncTaskProfiler();
|
||||
private final Map<String, IRecipeHandler> handlerMap = new ConcurrentHashMap<>();
|
||||
private final AtomicInteger idCounter = new AtomicInteger(0);
|
||||
private boolean isProfiling = false;
|
||||
|
||||
public <T extends IRecipeHandler> ArrayList<T> start(String profilerSection, Supplier<ArrayList<T>> callback) {
|
||||
profilerInfos.clear();
|
||||
this.handlerMap.clear();
|
||||
this.idCounter.set(0);
|
||||
|
||||
if (NEIClientConfig.isProfileRecipeEnabled()) {
|
||||
this.profiler.clear();
|
||||
this.profiler.start(EnumChatFormatting.getTextWithoutFormattingCodes(profilerSection));
|
||||
this.isProfiling = true;
|
||||
|
||||
try {
|
||||
return callback.get();
|
||||
} finally {
|
||||
this.profiler.end();
|
||||
this.isProfiling = false;
|
||||
|
||||
final List<ProfilerResult> results = this.profiler.getResults();
|
||||
|
||||
results.sort(
|
||||
Comparator.comparingLong((ProfilerResult profilerResult) -> profilerResult.time)
|
||||
.reversed());
|
||||
|
||||
for (ProfilerResult profilerResult : results) {
|
||||
profilerInfos.add(new ProfilerInfo(handlerMap.get(profilerResult.name), profilerResult));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return callback.get();
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends IRecipeHandler> T profile(T handler, Supplier<T> callback) {
|
||||
if (this.isProfiling && !(handler instanceof ProfilerRecipeHandler)) {
|
||||
final String id = String.valueOf(idCounter.incrementAndGet());
|
||||
this.handlerMap.put(id, handler);
|
||||
this.profiler.clearCurrent();
|
||||
this.profiler.start(id);
|
||||
|
||||
try {
|
||||
T result = callback.get();
|
||||
|
||||
if (result != null) {
|
||||
this.handlerMap.put(id, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
this.profiler.end();
|
||||
}
|
||||
} else {
|
||||
return callback.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static AsyncTaskProfiler getProfiler() {
|
||||
return profiler;
|
||||
}
|
||||
|
||||
protected static class ProfilerInfo {
|
||||
|
||||
public final String modName;
|
||||
public final IRecipeHandler handler;
|
||||
public final List<String> tooltip = new ArrayList<>();
|
||||
public final String title;
|
||||
public final String time;
|
||||
|
||||
public ProfilerInfo(IRecipeHandler handler, ProfilerResult result) {
|
||||
this.handler = handler;
|
||||
this.time = (result.time < 1_000_000 ? (result.time / 1_000) + "us" : (result.time / 1_000_000) + "ms");
|
||||
|
||||
if (handler == null) {
|
||||
this.title = result.name;
|
||||
this.modName = "Unknown";
|
||||
} else {
|
||||
final HandlerInfo handlerInfo = GuiRecipeTab.getHandlerInfo(handler);
|
||||
final String handlerName = handlerInfo != null ? handlerInfo.getHandlerName() : "Unknown";
|
||||
|
||||
this.title = EnumChatFormatting.getTextWithoutFormattingCodes(handler.getRecipeName());
|
||||
this.modName = handlerInfo != null ? handlerInfo.getModName() : "Unknown";
|
||||
|
||||
this.tooltip.add(EnumChatFormatting.GRAY + "HandlerName: " + handlerName);
|
||||
this.tooltip.add(EnumChatFormatting.GRAY + "HandlerID: " + handler.getOverlayIdentifier());
|
||||
this.tooltip.add(EnumChatFormatting.GRAY + "HandlerOrder: " + NEIClientConfig.getHandlerOrder(handler));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final RecipeProfiler recipeProfiler = new RecipeProfiler();
|
||||
protected static final List<ProfilerInfo> profilerInfos = new ArrayList<>();
|
||||
private static final int WIDTH = 166;
|
||||
private final boolean crafting;
|
||||
|
||||
public ProfilerRecipeHandler(boolean crafting) {
|
||||
@@ -39,11 +139,7 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
|
||||
|
||||
@Override
|
||||
public int numRecipes() {
|
||||
if (!NEIClientConfig.isProfileRecipeEnabled()) return 0;
|
||||
|
||||
return (int) Math.ceil(
|
||||
((crafting ? GuiCraftingRecipe.craftinghandlers.size() : GuiUsageRecipe.usagehandlers.size()) - 1)
|
||||
/ 6D);
|
||||
return NEIClientConfig.isProfileRecipeEnabled() ? Math.max(1, profilerInfos.size()) : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,21 +147,32 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
|
||||
|
||||
@Override
|
||||
public void drawForeground(int recipe) {
|
||||
List<ProfilerResult> results = profiler.getResults();
|
||||
results.removeIf(profilerResult -> getRecipeName().equals(profilerResult.name));
|
||||
if (recipe >= profilerInfos.size()) return;
|
||||
|
||||
results.sort((o1, o2) -> o1.time < o2.time ? 1 : -1);
|
||||
final ProfilerInfo info = profilerInfos.get(recipe);
|
||||
final int valueWidth = getStringWidth(info.time);
|
||||
final IRecipeHandler handler = info.handler;
|
||||
final boolean hovered = handler != null && handler.numRecipes() > 0
|
||||
&& isHandlerTitleHovered(recipe, GuiDraw.getMousePosition());
|
||||
|
||||
for (int i = recipe * 6; i < results.size() && i < (recipe + 1) * 6; i++) {
|
||||
ProfilerResult r = results.get(i);
|
||||
int y = (i % 6) * 20 + 6;
|
||||
drawString(r.name, 8, y, 0xFF808080, false);
|
||||
GuiDraw.drawString(
|
||||
NEIClientUtils.cropText(GuiDraw.fontRenderer, info.title, WIDTH - valueWidth - 2),
|
||||
0,
|
||||
3,
|
||||
hovered ? 0xFFFFDD00 : 0xFF808080,
|
||||
false);
|
||||
GuiDraw.drawString(info.time, WIDTH - valueWidth, 3, 0xFF404040, false);
|
||||
}
|
||||
|
||||
String s;
|
||||
if (r.time < 1000000L) s = (r.time / 1000) + "us";
|
||||
else s = (r.time / 1000000) + "ms";
|
||||
private boolean isHandlerTitleHovered(int recipe, Point mouse) {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
|
||||
drawString(s, 156 - getStringWidth(s), y + 10, 0xFF404040, false);
|
||||
if (guiContainer instanceof GuiRecipe guiRecipe) {
|
||||
final Point recipePosition = guiRecipe.getRecipePosition(recipe);
|
||||
return new Rectangle(recipePosition.x, recipePosition.y, WIDTH, 16)
|
||||
.contains(mouse.x - guiContainer.guiLeft, mouse.y - guiContainer.guiTop);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +211,22 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip, int recipe) {
|
||||
if (recipe >= profilerInfos.size()) return currenttip;
|
||||
|
||||
final ProfilerInfo r = profilerInfos.get(recipe);
|
||||
|
||||
currenttip.add(r.title + ": " + r.time);
|
||||
|
||||
if (r.handler != null) {
|
||||
currenttip.add(EnumChatFormatting.GRAY + "Recipes: " + r.handler.numRecipes() + GuiDraw.TOOLTIP_LINESPACE);
|
||||
|
||||
if (NEIClientUtils.shiftKey()) {
|
||||
currenttip.addAll(r.tooltip);
|
||||
}
|
||||
|
||||
currenttip.add(EnumChatFormatting.BLUE + r.modName);
|
||||
}
|
||||
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@@ -119,6 +242,23 @@ public class ProfilerRecipeHandler implements ICraftingHandler, IUsageHandler {
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiRecipe<?> gui, int button, int recipe) {
|
||||
if (recipe >= profilerInfos.size()) return false;
|
||||
|
||||
final ProfilerInfo r = profilerInfos.get(recipe);
|
||||
|
||||
if (r.handler != null) {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
|
||||
if (guiContainer instanceof GuiRecipe guiRecipe) {
|
||||
int index = guiRecipe.currenthandlers.indexOf(r.handler);
|
||||
|
||||
if (index != -1) {
|
||||
guiRecipe.setRecipePage(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,8 @@ import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
|
||||
import codechicken.core.TaskProfiler;
|
||||
import codechicken.nei.ItemList;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.util.AsyncTaskProfiler;
|
||||
|
||||
public class RecipeHandlerQuery<T extends IRecipeHandler> {
|
||||
|
||||
@@ -34,30 +32,22 @@ public class RecipeHandlerQuery<T extends IRecipeHandler> {
|
||||
}
|
||||
|
||||
public ArrayList<T> runWithProfiling(String profilerSection) {
|
||||
TaskProfiler profiler = ProfilerRecipeHandler.getProfiler();
|
||||
return ProfilerRecipeHandler.recipeProfiler.start(profilerSection, () -> {
|
||||
|
||||
// Save the current config state here, as it may be altered
|
||||
// if getRecipeHandlesParallel took so long and player accidentally changed config.
|
||||
boolean profileRecipes = NEIClientConfig.isProfileRecipeEnabled();
|
||||
if (profileRecipes) {
|
||||
profiler.clear();
|
||||
profiler.start(profilerSection);
|
||||
}
|
||||
try {
|
||||
ArrayList<T> handlers = getRecipeHandlersParallel();
|
||||
|
||||
try {
|
||||
ArrayList<T> handlers = getRecipeHandlersParallel();
|
||||
|
||||
if (error) {
|
||||
if (error) {
|
||||
displayRecipeLookupError();
|
||||
}
|
||||
return handlers;
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
printLog(e);
|
||||
displayRecipeLookupError();
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
return handlers;
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
printLog(e);
|
||||
displayRecipeLookupError();
|
||||
return new ArrayList<>(0);
|
||||
} finally {
|
||||
if (profileRecipes) profiler.end();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private ArrayList<T> getRecipeHandlersParallel() throws InterruptedException, ExecutionException {
|
||||
@@ -77,40 +67,42 @@ public class RecipeHandlerQuery<T extends IRecipeHandler> {
|
||||
|
||||
private ArrayList<T> getSerialHandlersWithRecipes() {
|
||||
|
||||
return serialRecipeHandlers.stream().map(handler -> {
|
||||
AsyncTaskProfiler profiler = ProfilerRecipeHandler.getProfiler();
|
||||
profiler.clearCurrent();
|
||||
profiler.start(handler.getRecipeName());
|
||||
try {
|
||||
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
|
||||
} catch (Throwable t) {
|
||||
printLog(t);
|
||||
error = true;
|
||||
return null;
|
||||
} finally {
|
||||
profiler.end();
|
||||
}
|
||||
}).filter(h -> h != null && h.numRecipes() > 0 && SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
|
||||
return serialRecipeHandlers.stream()
|
||||
.map(handler -> ProfilerRecipeHandler.recipeProfiler.profile(handler, () -> {
|
||||
|
||||
try {
|
||||
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
|
||||
} catch (Throwable t) {
|
||||
printLog(t);
|
||||
error = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
}))
|
||||
.filter(
|
||||
h -> h != null && h.numRecipes() > 0
|
||||
&& SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
private ArrayList<T> getHandlersWithRecipes() throws InterruptedException, ExecutionException {
|
||||
|
||||
return ItemList.forkJoinPool.submit(() -> recipeHandlers.parallelStream().map(handler -> {
|
||||
AsyncTaskProfiler profiler = ProfilerRecipeHandler.getProfiler();
|
||||
profiler.clearCurrent();
|
||||
profiler.start(handler.getRecipeName());
|
||||
try {
|
||||
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
|
||||
} catch (Throwable t) {
|
||||
printLog(t);
|
||||
error = true;
|
||||
return null;
|
||||
} finally {
|
||||
profiler.end();
|
||||
}
|
||||
}).filter(h -> h != null && h.numRecipes() > 0 && SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
|
||||
.collect(Collectors.toCollection(ArrayList::new))).get();
|
||||
return ItemList.forkJoinPool.submit(
|
||||
() -> recipeHandlers.parallelStream()
|
||||
.map(handler -> ProfilerRecipeHandler.recipeProfiler.profile(handler, () -> {
|
||||
try {
|
||||
return isHidden(handler) ? null : recipeHandlerFunction.apply(handler);
|
||||
} catch (Throwable t) {
|
||||
printLog(t);
|
||||
error = true;
|
||||
return null;
|
||||
}
|
||||
}))
|
||||
.filter(
|
||||
h -> h != null && h.numRecipes() > 0
|
||||
&& SearchRecipeHandler.findFirst(h, (recipeIndex) -> true) != -1)
|
||||
.collect(Collectors.toCollection(ArrayList::new)))
|
||||
.get();
|
||||
}
|
||||
|
||||
private boolean isHidden(T handler) {
|
||||
|
||||
Reference in new issue
Block a user