diff --git a/src/main/java/codechicken/nei/IMCForNEI.java b/src/main/java/codechicken/nei/IMCForNEI.java index 7ad96a31..848a2f0d 100644 --- a/src/main/java/codechicken/nei/IMCForNEI.java +++ b/src/main/java/codechicken/nei/IMCForNEI.java @@ -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); diff --git a/src/main/java/codechicken/nei/PositionedStack.java b/src/main/java/codechicken/nei/PositionedStack.java index b6a0269a..a5155571 100644 --- a/src/main/java/codechicken/nei/PositionedStack.java +++ b/src/main/java/codechicken/nei/PositionedStack.java @@ -91,10 +91,6 @@ public class PositionedStack { return null; } - public String getCustomBadge() { - return null; - } - public int getChance() { return this.chance; } diff --git a/src/main/java/codechicken/nei/recipe/Badge.java b/src/main/java/codechicken/nei/recipe/Badge.java index 01711c90..1be9860c 100644 --- a/src/main/java/codechicken/nei/recipe/Badge.java +++ b/src/main/java/codechicken/nei/recipe/Badge.java @@ -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() { diff --git a/src/main/java/codechicken/nei/recipe/GuiRecipeTab.java b/src/main/java/codechicken/nei/recipe/GuiRecipeTab.java index ab7ac590..76161f26 100644 --- a/src/main/java/codechicken/nei/recipe/GuiRecipeTab.java +++ b/src/main/java/codechicken/nei/recipe/GuiRecipeTab.java @@ -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 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); diff --git a/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java b/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java index 47d7a471..94304b8a 100644 --- a/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java +++ b/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java @@ -263,12 +263,6 @@ public class NEIRecipeWidget extends Widget { final List 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) { diff --git a/src/main/java/codechicken/nei/recipe/ProfilerRecipeHandler.java b/src/main/java/codechicken/nei/recipe/ProfilerRecipeHandler.java index e8cba0e6..d6e58c34 100644 --- a/src/main/java/codechicken/nei/recipe/ProfilerRecipeHandler.java +++ b/src/main/java/codechicken/nei/recipe/ProfilerRecipeHandler.java @@ -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 handlerMap = new ConcurrentHashMap<>(); + private final AtomicInteger idCounter = new AtomicInteger(0); + private boolean isProfiling = false; + + public ArrayList start(String profilerSection, Supplier> 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 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 profile(T handler, Supplier 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 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 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 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 handleTooltip(GuiRecipe gui, List 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; } diff --git a/src/main/java/codechicken/nei/recipe/RecipeHandlerQuery.java b/src/main/java/codechicken/nei/recipe/RecipeHandlerQuery.java index 1918762e..bf94e2e4 100644 --- a/src/main/java/codechicken/nei/recipe/RecipeHandlerQuery.java +++ b/src/main/java/codechicken/nei/recipe/RecipeHandlerQuery.java @@ -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 { @@ -34,30 +32,22 @@ public class RecipeHandlerQuery { } public ArrayList 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 handlers = getRecipeHandlersParallel(); - try { - ArrayList 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 getRecipeHandlersParallel() throws InterruptedException, ExecutionException { @@ -77,40 +67,42 @@ public class RecipeHandlerQuery { private ArrayList 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 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) {