Compare commits

...
Author SHA1 Message Date
Martin Robertz 8870f095e1 Merge remote-tracking branch 'origin/recipe-tooltip' into dev
# Conflicts:
#	src/main/java/codechicken/nei/recipe/GuiRecipe.java
2023-07-08 21:20:10 +02:00
Martin Robertz c91f8ff386 Merge remote-tracking branch 'origin/legacy-handler-compatibility-improvements' into dev 2023-07-08 21:18:31 +02:00
Wilhelm Schuster cd1823712d Fix Thermal Expansion recipe handlers
These handlers expect only two recipes to be displayed at a time. This can only be fixed through asm AFAICT.
2023-07-08 17:21:08 +02:00
Wilhelm Schuster e294abd0a7 Fix Ex Nihilo recipe handlers 2023-07-08 17:21:08 +02:00
Wilhelm Schuster 69c8a653e3 Fix Immersive Engineering recipe handlers 2023-07-08 17:20:30 +02:00
Wilhelm Schuster f7c5b73728 Extend the height hack to also cover guiTop and getRecipePosition
Certain legacy recipe handlers hardcode even more of the NEI recipe
screen layout, requiring only the singular recipe handler switcher
widget at the top, whereas this improved NEI moves the recipe pager to
the top as well expecting recipe handler to move down another 16px. One
such mod that breaks is Immersive Engineering. To fix it we move the top
edge of the gui (guiTop) down by 16px so that the old gap calculation
works correctly. This required special handling in getRecipePosition()
and refreshSlots().
2023-07-08 17:20:30 +02:00
Wilhelm Schuster c11f51624d Store serialhandlers.cfg as an internal asset instead of an array of strings
Is copied into the config directory upon first launch. Also, comments
are now allowed (only from the beginning of the file).

Removes GTNH-specific code to be replaced with a configuration file.
2023-07-08 17:17:39 +02:00
Wilhelm Schuster b63b2d082b Store heighthackhandlers.cfg as an internal asset instead of an array of strings
Is copied into the config directory upon first launch. Also, comments
are now allowed (only from the beginning of the file).
2023-07-08 17:17:39 +02:00
Raven Szewczyk e748c6779b Fix wildcard import 2023-07-04 20:11:20 +01:00
Raven Szewczyk 75e8270bad Fix layout relative to tooltip boxes 2023-07-04 20:08:42 +01:00
Raven Szewczyk c4c7d6d055 Make recipe tooltips configurable and only show in the bookmarks panel 2023-07-04 19:42:08 +01:00
Raven Szewczyk 2630d887eb Show a full recipe widget in item tooltips for bookmarked recipes 2023-07-02 22:50:55 +01:00
Raven Szewczyk f8cc9bd0e6 Update buildscript 2023-06-30 20:59:51 +01:00
14 changed files with 403 additions and 129 deletions

No files matched your search

-7
View File
@@ -27,13 +27,6 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
* Remove TMI style
* Removed inventory Load/Save state
## Development
Before launching, you need to add
```
-Dfml.coreMods.load=codechicken.nei.asm.NEICorePlugin
```
as a command line argument to the VM.
## License
GTNH Modifications Copyright (c) 2019-2022 mitchej123 and the GTNH Team
+3
View File
@@ -26,3 +26,6 @@ blowdryerSetup {
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.2.0')
//devLocal '.' // Use this when testing config updates locally
}
rootProject.name = "NotEnoughItems"
@@ -84,6 +84,10 @@ public class BookmarkPanel extends PanelWidget {
protected boolean[] todoSpaces;
protected int todoItemsCount = 0;
public BookmarkGrid() {
this.setShowRecipeTooltips(true);
}
public void setViewMode(BookmarkViewMode mode) {
if (viewMode == mode) {
return;
@@ -9,9 +9,6 @@ import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -48,20 +45,12 @@ import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.StackInfo;
import cpw.mods.fml.client.CustomModLoadingErrorDisplayException;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
public class ClientHandler {
private static String[] defaultSerialHandlers = {
"WayofTime.alchemicalWizardry.client.nei.NEIAlchemyRecipeHandler" };
private static String[] defaultHeightHackHandlerRegex = { "buildcraft.compat.nei.*",
"cofh.thermalexpansion.plugins.nei.handlers.*", "crazypants.enderio.nei.*",
"forestry.factory.recipes.nei.*", "ic2.neiIntegration.core.recipehandler.*", "mariculture.plugins.nei.*",
"redgear.brewcraft.plugins.nei.*", "tconstruct.plugins.nei.*",
"WayofTime.alchemicalWizardry.client.nei.*", };
private static String[] defaultHandlerOrdering = {
"# Each line in this file should either be a comment (starts with '#') or an ordering.",
"# Ordering lines are <handler ID>,<ordering number>.",
@@ -165,16 +154,19 @@ public class ClientHandler {
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default serial handlers list {}", file);
Collection<String> toSave = Loader.isModLoaded("dreamcraft") ? Collections.singletonList("")
: Arrays.asList(defaultSerialHandlers);
IOUtils.writeLines(toSave, "\n", writer);
URL defaultSerialHandlersResource = ClientHandler.class
.getResource("/assets/nei/cfg/serialhandlers.cfg");
if (defaultSerialHandlersResource != null) {
IOUtils.copy(defaultSerialHandlersResource.openStream(), writer);
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default serial handlers list to file {}", file, e);
}
}
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading serial handlers from file {}", file);
NEIClientConfig.serialHandlers = new HashSet<>(IOUtils.readLines(reader));
NEIClientConfig.serialHandlers = IOUtils.readLines(reader).stream().filter((line) -> !line.startsWith("#"))
.collect(Collectors.toCollection(HashSet::new));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load serial handlers from file {}", file, e);
}
@@ -185,8 +177,11 @@ public class ClientHandler {
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default height hack handlers list {}", file);
Collection<String> toSave = Arrays.asList(defaultHeightHackHandlerRegex);
IOUtils.writeLines(toSave, "\n", writer);
URL defaultHeightHackHandlersResource = ClientHandler.class
.getResource("/assets/nei/cfg/heighthackhandlers.cfg");
if (defaultHeightHackHandlersResource != null) {
IOUtils.copy(defaultHeightHackHandlersResource.openStream(), writer);
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default height hack handlers list to file {}", file, e);
}
@@ -194,7 +189,8 @@ public class ClientHandler {
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading height hack handlers from file {}", file);
NEIClientConfig.heightHackHandlerRegex = IOUtils.readLines(reader).stream().map(Pattern::compile)
NEIClientConfig.heightHackHandlerRegex = IOUtils.readLines(reader).stream()
.filter((line) -> !line.startsWith("#")).map(Pattern::compile)
.collect(Collectors.toCollection(HashSet::new));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load height hack handlers from file {}", file, e);
@@ -1,19 +1,24 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
@@ -22,6 +27,9 @@ import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.BookmarkRecipeId;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
public class ItemsGrid {
@@ -43,6 +51,7 @@ public class ItemsGrid {
protected int rows;
protected int columns;
protected boolean showRecipeTooltips = false;
protected boolean[] invalidSlotMap;
@@ -150,6 +159,10 @@ public class ItemsGrid {
refreshBuffer = true;
}
public void setShowRecipeTooltips(boolean show) {
this.showRecipeTooltips = show;
}
public void refresh(GuiContainer gui) {
updateGuiOverlapSlots(gui);
shiftPage(0);
@@ -244,6 +257,121 @@ public class ItemsGrid {
}
}
private int recipeTooltipSlotIdx = -1;
private int recipeTooltipLines = 2;
private Runnable recipeTooltipUpdater = null;
private GuiRecipe<?> recipeTooltipGui = null;
public void update() {
if (recipeTooltipUpdater != null) {
recipeTooltipUpdater.run();
recipeTooltipUpdater = null;
}
if (recipeTooltipGui != null) {
recipeTooltipGui.updateAsTooltip();
}
}
private static <T> List<T> listOrEmptyList(final List<T> listOrNull) {
return listOrNull == null ? Collections.emptyList() : listOrNull;
}
private void drawRecipeTooltip(int mousex, int mousey) {
final Minecraft mc = Minecraft.getMinecraft();
ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
if (focused == null) {
recipeTooltipSlotIdx = -1;
recipeTooltipGui = null;
return;
}
final List<Integer> mask = getMask();
int slotIdx = -1;
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) == null) {
continue;
}
if (focused.slotIndex != mask.get(i)) {
continue;
}
slotIdx = i;
break;
}
if (slotIdx == -1) {
recipeTooltipSlotIdx = -1;
recipeTooltipGui = null;
return;
}
final Point mouseover = getMousePosition();
final ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
final BookmarkRecipeId recipeId;
if (panelSlot != null) {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
} else {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(focused.item);
}
if (recipeId == null) {
return;
}
if (slotIdx != recipeTooltipSlotIdx) {
recipeTooltipSlotIdx = slotIdx;
recipeTooltipGui = null;
recipeTooltipUpdater = () -> {
recipeTooltipGui = GuiCraftingRecipe.createRecipeGui("item", false, false, false, focused.item);
if (recipeTooltipGui != null) {
recipeTooltipGui.limitToOneRecipe();
recipeTooltipGui.initGui(true);
recipeTooltipGui.guiTop = 0;
recipeTooltipGui.guiLeft = 0;
}
recipeTooltipLines = 2;
if (focused.item != null && mc.currentScreen instanceof GuiContainer) {
final List<String> tooltip = GuiContainerManager
.itemDisplayNameMultiline(focused.item, (GuiContainer) mc.currentScreen, true);
recipeTooltipLines = tooltip.size();
}
};
}
if (recipeTooltipGui == null) {
return;
}
GL11.glPushMatrix();
final float tooltipYOffset;
if (mousey > height / 2) {
tooltipYOffset = mousey - recipeTooltipGui.getHeightAsWidget() + 8;
} else {
tooltipYOffset = mousey - 7 + (recipeTooltipLines * 10);
}
GL11.glTranslatef(mousex, tooltipYOffset, 100);
final GuiContainer gui;
if (mc.currentScreen instanceof GuiRecipe) {
gui = ((GuiRecipe<?>) mc.currentScreen).firstGui;
} else if (mc.currentScreen instanceof GuiContainer) {
gui = (GuiContainer) mc.currentScreen;
} else {
gui = null;
}
recipeTooltipGui.drawGuiContainerBackgroundLayer(0.0f, -100, -100);
if (recipeTooltipGui.slotcontainer != null) {
@SuppressWarnings("unchecked")
List<Slot> slots = (List<Slot>) recipeTooltipGui.slotcontainer.inventorySlots;
for (Slot slot : slots) {
if (slot != null && slot.getStack() != null) {
GuiContainerManager.drawItem(slot.xDisplayPosition, slot.yDisplayPosition, slot.getStack());
}
}
}
recipeTooltipGui.drawGuiContainerForegroundLayer(-100, -100);
for (GuiButton btn : recipeTooltipGui.getOverlayButtons()) {
btn.drawButton(mc, -100, -100);
}
GL11.glPopMatrix();
}
protected void drawSlotOutline(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (focused != null && focused.slotIndex == slotIdx) {
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
@@ -327,6 +455,13 @@ public class ItemsGrid {
drawSlotOutlines(mousex, mousey);
drawItems();
}
if (NEIClientConfig.showRecipeTooltips() && showRecipeTooltips) {
try {
drawRecipeTooltip(mousex, mousey);
} catch (Exception e) {
NEIClientConfig.logger.warn("Cannot draw recipe tooltip", e);
}
}
}
public void setVisible() {
@@ -242,6 +242,9 @@ public class NEIClientConfig {
tag.getTag("inventory.bookmarksAnimationEnabled").setComment("REI Style Animation in Bookmarks")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarksAnimationEnabled", true));
tag.getTag("inventory.recipeTooltipsEnabled").setComment("Show recipe tooltips in Bookmarks")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.recipeTooltipsEnabled", true));
tag.getTag("inventory.showRecipeMarker").setComment("Show Recipe Marker").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.showRecipeMarker", true));
@@ -559,6 +562,10 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.bookmarksAnimationEnabled");
}
public static boolean showRecipeTooltips() {
return getBooleanSetting("inventory.recipeTooltipsEnabled");
}
public static boolean showRecipeMarker() {
return getBooleanSetting("inventory.showRecipeMarker");
}
@@ -171,6 +171,11 @@ public abstract class PanelWidget extends Widget {
}
}
@Override
public void update() {
grid.update();
}
@Override
public void draw(int mousex, int mousey) {
grid.draw(mousex, mousey);
@@ -121,6 +121,43 @@ public class BookmarkRecipeId {
return arr;
}
/**
* Ensures the {@link BookmarkRecipeId#recipetype} and {@link BookmarkRecipeId#position} fields point to a valid
* recipe. This is needed, because the recipe IDs are loaded lazily on first use.
*
* @param recipeHandlers The subset of recipe handlers to search for the recipe
*/
public void updateTargetRecipe(List<? extends IRecipeHandler> recipeHandlers) {
if (this.recipetype == -1 || this.position == -1) {
this.recipetype = 0;
this.position = 0;
if (this.handlerName != null) {
for (int j = 0; j < recipeHandlers.size(); j++) {
IRecipeHandler localHandler = recipeHandlers.get(j);
HandlerInfo localHandlerInfo = GuiRecipeTab.getHandlerInfo(localHandler);
if (localHandlerInfo.getHandlerName().equals(this.handlerName)) {
if (!this.ingredients.isEmpty()) {
for (int i = 0; i < localHandler.numRecipes(); i++) {
if (this.equalsIngredients(localHandler.getIngredientStacks(i))) {
this.recipetype = j;
this.position = i;
break;
}
}
}
break;
}
}
}
}
}
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
@@ -28,28 +28,27 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
public static boolean openRecipeGui(String outputId, final Boolean overlay, final Boolean shift,
Object... results) {
return createRecipeGui(outputId, overlay, shift, true, results) != null;
}
public static GuiRecipe<?> createRecipeGui(String outputId, final Boolean overlay, final Boolean shift,
final boolean open, Object... results) {
final Minecraft mc = NEIClientUtils.mc();
final BookmarkRecipeId recipeId = "item".equals(outputId)
? getRecipeId(mc.currentScreen, (ItemStack) results[0])
: getCurrentRecipe(mc.currentScreen);
if (overlay && recipeId == null) return false;
if (overlay && recipeId == null) return null;
final RecipeHandlerQuery<ICraftingHandler> recipeQuery = new RecipeHandlerQuery<>(
h -> h.getRecipeHandler(outputId, results),
craftinghandlers,
serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: " + outputId,
"results: " + Arrays.toString(results));
final ArrayList<ICraftingHandler> handlers = recipeQuery.runWithProfiling("recipe.concurrent.crafting");
final ArrayList<ICraftingHandler> handlers = getCraftingHandlers(outputId, results);
if (!handlers.isEmpty()) {
GuiCraftingRecipe gui = new GuiCraftingRecipe(handlers, recipeId);
mc.displayGuiScreen(gui);
if (open) {
mc.displayGuiScreen(gui);
}
if (recipeId != null) {
gui.openTargetRecipe(gui.recipeId);
@@ -59,10 +58,22 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
gui.overlayRecipe(gui.recipeId.position, shift);
}
return true;
return gui;
}
return false;
return null;
}
public static ArrayList<ICraftingHandler> getCraftingHandlers(String outputId, Object... results) {
final RecipeHandlerQuery<ICraftingHandler> recipeQuery = new RecipeHandlerQuery<>(
h -> h.getRecipeHandler(outputId, results),
craftinghandlers,
serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: " + outputId,
"results: " + Arrays.toString(results));
return recipeQuery.runWithProfiling("recipe.concurrent.crafting");
}
protected static BookmarkRecipeId getRecipeId(GuiScreen gui, ItemStack stackover) {
@@ -1,5 +1,7 @@
package codechicken.nei.recipe;
import static codechicken.lib.gui.GuiDraw.fontRenderer;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
@@ -11,8 +13,10 @@ import java.util.regex.Matcher;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
@@ -59,6 +63,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private static final int buttonWidth = 13;
private static final int buttonHeight = 12;
private boolean limitToOneRecipe = false;
// Background image
final DrawableResource bgTop = new DrawableBuilder("nei:textures/gui/recipebg.png", 0, BG_TOP_Y, 176, BG_TOP_HEIGHT)
.build();
@@ -100,6 +106,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private int yShift = 0;
/**
* This will only be true iff height hacking has been configured for the current recipe handler AND we are currently
* within the scope of an active {@link HeightHack} instance.
*/
private boolean isHeightHackApplied = false;
protected GuiRecipe(GuiScreen prevgui) {
super(new ContainerRecipe());
recipeTabs = new GuiRecipeTabs(this);
@@ -116,9 +128,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
}
/** Changes the GUI mode to only display one recipe at a time, e.g. for tooltip usage */
public void limitToOneRecipe() {
limitToOneRecipe = true;
}
/**
* Many old mods assumed a fixed NEI window height of {@code 166} pixels. Now that this is no longer the case, their
* fluid mouseover handling is broken. This helper class fixes these old mods by hacking the {@link #height}
* tooltip and click zone handling is broken. This helper class fixes these old mods by hacking the {@link #height}
* property's value so that these old mods' calculations return the correct value for the new height.
*
* <p>
@@ -128,40 +145,68 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private class HeightHack implements AutoCloseable {
private final int trueHeight;
private final int trueGuiTop;
private HeightHack() {
trueHeight = height;
trueGuiTop = guiTop;
boolean applyHeightHack = NEIClientConfig.heightHackHandlerRegex.stream()
isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream()
.map(pattern -> pattern.matcher(handler.getHandlerId())).anyMatch(Matcher::matches);
if (applyHeightHack) {
// The old mods use the calculation ((height - 166) / 2) to compute the y-value of
// the top edge of the NEI window.
// guiTop is exactly that: the y-value of the top edge of the NEI window.
// So we set height to be equal to the inverse of this calculation, applied to
// guiTop, so that old mods get the right result back when they use this calculation.
if (isHeightHackApplied) {
// guiTop is the top edge of the recipe screen on the y-axis. Old recipe handlers expect a single paging
// widget at the top and at the bottom of the recipe screen with a height of 16px, but GTNH NEI move the
// bottom paging widget to the top following JEI's UI increasing the forbidden zone at the top to 32px.
// To fix these old recipe handlers we move guiTop down 16px so that they can keep working with the old
// 16px gap.
guiTop += 16;
// The old NEI recipe screen had a fixed width and height and was always centered on the screen. Legacy
// recipe handlers use the calculation ((height - 166) / 2) to compute the y-value of the top edge of
// the NEI recipe screen. GTNH NEI now has a flexible recipe screen length and is no longer centered
// vertically, so in order for the top-of-screen calculation to return the correct result, we have to
// hack the height field with an inverse of the calculation using the actual top of the recipe screen
// stored in guiTop.
height = (2 * guiTop) + 166;
// For reference, in case we ever need to modify width as well:
// the legacy calculation used for width is ((width - 176) / 2), which should
// evaluate to be equal to guiWidth (the x-value of the left edge of the NEI window).
// So if we wanted to override width as well, we'd do this:
// the legacy calculation used for width is ((width - 176) / 2), which should evaluate to be equal to
// guiWidth (the x-value of the left edge of the NEI recipe screen). So if we wanted to override width
// as well, we'd do this:
// width = (2 * guiWidth) + 176;
}
}
@Override
public void close() {
guiTop = trueGuiTop;
height = trueHeight;
isHeightHackApplied = false;
}
}
@Override
@SuppressWarnings("unchecked")
public void initGui() {
initGui(false);
}
@SuppressWarnings("unchecked")
public void initGui(boolean asWidget) {
xSize = 176;
ySize = Math.min(Math.max(height - 68, 166), 370);
super.initGui();
if (!asWidget) {
super.initGui();
} else {
this.guiLeft = (this.width - this.xSize) / 2;
this.mc = Minecraft.getMinecraft();
this.fontRendererObj = mc.fontRenderer;
ScaledResolution scaledresolution = new ScaledResolution(
this.mc,
this.mc.displayWidth,
this.mc.displayHeight);
this.width = scaledresolution.getScaledWidth();
this.height = scaledresolution.getScaledHeight();
}
guiTop = (height - ySize) / 2 + 10;
currenthandlers = getCurrentRecipeHandlers(); // Probably don't comment me out
@@ -198,14 +243,24 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final int recipesPerPage = getRecipesPerPage();
overlayButtons = new GuiButton[recipesPerPage];
final int xOffset = limitToOneRecipe ? (xSize / 2) : (width / 2);
final int yOffset = limitToOneRecipe ? -14 : guiTop;
final String overlayKeyName = NEIClientConfig
.getKeyName(NEIClientConfig.getKeyBinding("gui.overlay_use"), true);
for (int i = 0; i < recipesPerPage; i++) {
overlayButtons[i] = new GuiNEIButton(
OVERLAY_BUTTON_ID_START + i,
(width / 2) + 65,
guiTop + 16 + (handlerInfo.getHeight() * (i + 1)) - 2,
xOffset + 65,
yOffset + 16 + (handlerInfo.getHeight() * (i + 1)) - 2,
buttonWidth,
buttonHeight,
"?");
if (overlayKeyName != null && limitToOneRecipe) {
overlayButtons[i].visible = true;
overlayButtons[i].displayString = overlayKeyName;
overlayButtons[i].width = fontRenderer.getStringWidth(overlayKeyName) + 6;
overlayButtons[i].xPosition = xOffset + 85 - overlayButtons[i].width;
}
}
Collections.addAll(buttonList, overlayButtons);
itemPresenceCacheRecipe = -1;
@@ -232,41 +287,17 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
initOverlayButtons();
}
public List<GuiButton> getOverlayButtons() {
return Collections.unmodifiableList(Arrays.asList(overlayButtons));
}
public void openTargetRecipe(BookmarkRecipeId recipeId) {
if (recipeId == null) {
return;
}
if (recipeId.recipetype == -1 || recipeId.position == -1) {
recipeId.recipetype = 0;
recipeId.position = 0;
if (recipeId.handlerName != null) {
for (int j = 0; j < currenthandlers.size(); j++) {
H localHandler = currenthandlers.get(j);
HandlerInfo localHandlerInfo = GuiRecipeTab.getHandlerInfo(localHandler);
if (localHandlerInfo.getHandlerName().equals(recipeId.handlerName)) {
if (!recipeId.ingredients.isEmpty()) {
for (int i = 0; i < localHandler.numRecipes(); i++) {
if (recipeId.equalsIngredients(localHandler.getIngredientStacks(i))) {
recipeId.recipetype = j;
recipeId.position = i;
break;
}
}
}
break;
}
}
}
}
recipeId.updateTargetRecipe(currenthandlers);
setRecipePage(recipeId.recipetype, recipeId.position);
}
@@ -438,6 +469,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
public void updateScreen() {
super.updateScreen();
updateAsTooltip();
}
/** updateScreen() that's safe to call when this isn't the currently open GUI */
public void updateAsTooltip() {
handler.onUpdate();
refreshPage();
}
@@ -454,9 +490,9 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack stack, int mousex, int mousey,
List<String> currenttip) {
// Height hacking is probably not needed as it doesn't look like any mods check mouse
// position for this method.
for (int i : getRecipeIndices()) currenttip = handler.handleItemTooltip(this, stack, currenttip, i);
try (HeightHack heightHack = new HeightHack()) {
for (int i : getRecipeIndices()) currenttip = handler.handleItemTooltip(this, stack, currenttip, i);
}
return currenttip;
}
@@ -542,6 +578,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final int recipesPerPage = getRecipesPerPage();
for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) {
Point p = getRecipePosition(i);
// Legacy recipe handlers only expect a single paging widget at the top of the recipe screen, in contrast,
// GTNH NEI moves the recipe paging widget from the bottom to the top, which means said legacy handlers will
// position item slots 16px too high in the screen.
if (isHeightHackApplied) {
p.translate(0, 16);
}
List<PositionedStack> stacks = handler.getIngredientStacks(i);
for (PositionedStack stack : stacks) slotcontainer.addSlot(stack, p.x, p.y);
@@ -552,11 +594,13 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
PositionedStack result = handler.getResultStack(i);
if (result != null) slotcontainer.addSlot(result, p.x, p.y);
List<PositionedStack> catalysts = RecipeCatalysts.getRecipeCatalysts(handler);
for (PositionedStack catalyst : catalysts) {
int xOffset = -GuiRecipeCatalyst.ingredientSize + 1;
int yOffset = BG_TOP_Y + GuiRecipeCatalyst.fullBorder;
slotcontainer.addSlot(catalyst, xOffset, yOffset);
if (!limitToOneRecipe) {
List<PositionedStack> catalysts = RecipeCatalysts.getRecipeCatalysts(handler);
for (PositionedStack catalyst : catalysts) {
int xOffset = -GuiRecipeCatalyst.ingredientSize + 1;
int yOffset = BG_TOP_Y + GuiRecipeCatalyst.fullBorder;
slotcontainer.addSlot(catalyst, xOffset, yOffset);
}
}
}
}
@@ -590,21 +634,24 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
public void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
GuiContainerManager.enable2DRender();
final int recipesPerPage = getRecipesPerPage();
String s = handler.getRecipeName().trim();
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 5, 0xffffff);
s = NEIClientUtils.translate("recipe.page", page + 1, (handler.numRecipes() - 1) / recipesPerPage + 1);
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 19, 0xffffff);
final int ySkip = limitToOneRecipe ? 25 : 0;
if (!limitToOneRecipe) {
String s = handler.getRecipeName().trim();
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 5, 0xffffff);
s = NEIClientUtils.translate("recipe.page", page + 1, (handler.numRecipes() - 1) / recipesPerPage + 1);
fontRendererObj.drawStringWithShadow(s, (xSize - fontRendererObj.getStringWidth(s)) / 2, 19, 0xffffff);
}
final boolean drawItemPresence = NEIClientConfig.isJEIStyleItemPresenceOverlayVisible();
GL11.glPushMatrix();
GL11.glTranslatef(5, 32 + yShift, 0);
GL11.glTranslatef(5, 32 - ySkip + yShift, 0);
try (HeightHack heightHack = new HeightHack()) {
for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) {
handler.drawForeground(i);
if (drawItemPresence && isMouseOverOverlayButton(i - page * recipesPerPage)
if (drawItemPresence && (isMouseOverOverlayButton(i - page * recipesPerPage) || limitToOneRecipe)
&& firstGui.inventorySlots != null) {
List<PositionedStack> ingredients = handler.getIngredientStacks(i);
if (itemPresenceCacheRecipe != i || itemPresenceCacheSlots == null
@@ -624,28 +671,27 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
@Override
protected void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
final int recipesPerPage = getRecipesPerPage();
final int ySkip = limitToOneRecipe ? 25 : 0;
GL11.glColor4f(1, 1, 1, 1);
final int j = (width - xSize) / 2;
final int k = guiTop;
drawBackgroundTiled(j, k);
drawBackgroundTiled(guiLeft, guiTop);
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nexttype.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nexttype.yPosition + buttonHeight,
0x30000000);
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nextpage.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nextpage.yPosition + buttonHeight,
0x30000000);
if (NEIClientConfig.areJEIStyleTabsVisible() && !limitToOneRecipe) {
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nexttype.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nexttype.yPosition + buttonHeight,
0x30000000);
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
nextpage.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nextpage.yPosition + buttonHeight,
0x30000000);
if (NEIClientConfig.areJEIStyleTabsVisible()) {
RenderHelper.enableGUIStandardItemLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
recipeTabs.draw(mouseX, mouseY);
@@ -656,7 +702,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
GL11.glPushMatrix();
GL11.glTranslatef(j + 5, k + 32 + yShift, 0);
GL11.glTranslatef(guiLeft + 5, guiTop - ySkip + 32 + yShift, 0);
try (HeightHack heightHack = new HeightHack()) {
for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) {
handler.drawBackground(i);
@@ -668,10 +714,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private void drawBackgroundTiled(int j, int k) {
// Draw the top
final int ySkip = limitToOneRecipe ? 25 : 0;
final int handlerHeight = limitToOneRecipe ? getHeightAsWidget() : ySize;
bgTop.draw(j, k + BG_TOP_Y);
// Maybe Tile the middle
final int tiledHeight = ySize - BG_TOP_HEIGHT - BG_BOTTOM_HEIGHT;
final int tiledHeight = handlerHeight - ySkip - BG_TOP_HEIGHT - BG_BOTTOM_HEIGHT;
if (tiledHeight > 0) {
final int yTileCount = tiledHeight / BG_MIDDLE_HEIGHT;
@@ -688,7 +736,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
// Draw the bottom
bgBottom.draw(j, k + ySize - BG_BOTTOM_HEIGHT);
bgBottom.draw(j, k + handlerHeight - ySkip - BG_BOTTOM_HEIGHT);
}
public int getHeightAsWidget() {
return (handlerInfo == null) ? ySize : (handlerInfo.getHeight() + 40);
}
@Override
@@ -724,7 +776,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
private int getRecipesPerPage() {
return getRecipesPerPage(handlerInfo);
return limitToOneRecipe ? 1 : getRecipesPerPage(handlerInfo);
}
private int getRecipesPerPage(HandlerInfo handlerInfo) {
@@ -735,7 +787,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
public Point getRecipePosition(int recipe) {
return new Point(5, 32 + yShift + ((recipe % getRecipesPerPage()) * handlerInfo.getHeight()));
// Legacy recipe handlers using the height hack might use getRecipePosition in combination with guiTop/height to
// position certain elements like tooltips. Since guiTop is moved down by 16px during height hacking, we need to
// reduce the vertical shift here to 16px instead of 32px.
return new Point(
5,
(isHeightHackApplied ? 16 : 32) - (limitToOneRecipe ? 25 : 0)
+ yShift
+ ((recipe % getRecipesPerPage()) * handlerInfo.getHeight()));
}
public abstract ArrayList<H> getCurrentRecipeHandlers();
@@ -0,0 +1,15 @@
# Each line in this file should either be a comment (line starts with '#'), or a fully-qualified class name (that
# includes the package name) for a recipe handler. Wildcard patterns ('*') can be used to catch multiple classes with a
# single entry.
# If you delete this file, it will be regenerated with the default height hacked handlers list.
buildcraft.compat.nei.*
cofh.thermalexpansion.plugins.nei.handlers.*
crazypants.enderio.nei.*
forestry.factory.recipes.nei.*
ic2.neiIntegration.core.recipehandler.*
mariculture.plugins.nei.*
redgear.brewcraft.plugins.nei.*
tconstruct.plugins.nei.*
WayofTime.alchemicalWizardry.client.nei.*
exnihilo.compatibility.nei.*
blusunrize.immersiveengineering.client.nei.*
@@ -0,0 +1,6 @@
# This version of NEI loads recipes in parallel. Some recipe handlers have not been designed with that in mind and might
# crash. List these handlers in this file to force them to be loaded single threaded. Each line in this file should
# either be a comment (line starts with '#'), or a fully-qualified class name (that includes the package name) for a
# recipe handler.
# If you delete this file, it will be regenerated with the default serial handlers list.
WayofTime.alchemicalWizardry.client.nei.NEIAlchemyRecipeHandler
@@ -373,11 +373,11 @@ NEIArcFurnaceHandlerCarrot Ingot,Immersive Engineering,minecraft:carrot,,Immersi
NEIArcFurnaceHandlerExtraction,Immersive Engineering,minecraft:glowstone_dust,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIShaderBagHandler,Immersive Engineering,ImmersiveEngineering:shaderBag,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBlueprintHandler,Immersive Engineering,ImmersiveEngineering:woodenDevice:5,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEICokeOvenHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:1,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBlastFurnaceHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:2,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEISqueezerHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:2,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIFermenterHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:3,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIRefineryHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:4,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEICokeOvenHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:1,,ImmersiveEngineering,TRUE,,,71,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBlastFurnaceHandler,Immersive Engineering,ImmersiveEngineering:stoneDecoration:2,,ImmersiveEngineering,TRUE,,,71,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEISqueezerHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:2,,ImmersiveEngineering,TRUE,,1,64,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIFermenterHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:3,,ImmersiveEngineering,TRUE,,1,64,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIRefineryHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:4,,ImmersiveEngineering,TRUE,,,65,166,2,,,,,,
blusunrize.immersiveengineering.client.nei.NEIBottlingMachineHandler,Immersive Engineering,minecraft:glass_bottle,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEIMetalPressHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:13,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,
blusunrize.immersiveengineering.client.nei.NEICrusherHandler,Immersive Engineering,ImmersiveEngineering:metalMultiblock:5,,ImmersiveEngineering,TRUE,,,71,166,5,,,,,,
@@ -410,13 +410,13 @@ cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCharger,Thermal Expansio
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingMachine,Thermal Expansion,ThermalExpansion:Frame,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingSecure,Thermal Expansion,ThermalExpansion:material:16,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingUpgrade,Thermal Expansion,ThermalExpansion:Frame:3,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCrucible,Thermal Expansion,ThermalExpansion:Machine:4,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCrucible,Thermal Expansion,ThermalExpansion:Machine:4,,ThermalExpansion,TRUE,,,65,166,2,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerFurnace,Thermal Expansion,ThermalExpansion:Machine:0,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerInsolator,Thermal Expansion,ThermalExpansion:Machine:11,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerInsolator,Thermal Expansion,ThermalExpansion:Machine:11,,ThermalExpansion,TRUE,,,65,166,2,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerPulverizer,Thermal Expansion,ThermalExpansion:Machine:1,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSawmill,Thermal Expansion,ThermalExpansion:Machine:2,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSmelter,Thermal Expansion,ThermalExpansion:Machine:3,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerTransposer,Thermal Expansion,ThermalExpansion:Machine:5,,ThermalExpansion,TRUE,,,65,166,5,,,,,,
cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerTransposer,Thermal Expansion,ThermalExpansion:Machine:5,,ThermalExpansion,TRUE,,,65,166,2,,,,,,
mekanism.client.nei.ChemicalCrystallizerRecipeHandler,Mekanism,Mekanism:MachineBlock2:8,,Mekanism,TRUE,,,79,,4,,,,,,
mekanism.client.nei.ChemicalDissolutionChamberRecipeHandler,Mekanism,Mekanism:MachineBlock2:6,,Mekanism,TRUE,,,79,,4,,,,,,
mekanism.client.nei.ChemicalInfuserRecipeHandler,Mekanism,Mekanism:MachineBlock2:2,,Mekanism,TRUE,,,80,,4,,,,,,
@@ -437,7 +437,7 @@ mekanism.client.nei.ShapelessMekanismRecipeHandler,Mekanism,minecraft:crafting_t
mekanism.client.nei.SolarNeutronRecipeHandler,Mekanism,Mekanism:MachineBlock3:1,,Mekanism,TRUE,,,70,,5,,,,,,
mekanism.client.nei.ThermalEvaporationRecipeHandler,Mekanism,Mekanism:BasicBlock:14,,Mekanism,TRUE,,,62,,5,,,,,,
exnihilo.compatibility.nei.RecipeHandlerHammer,Ex Nihilo,exnihilo:hammer_iron,,exnihilo,TRUE,,,58,,5,,,,,,
exnihilo.compatibility.nei.RecipeHandlerSieve,Ex Nihilo,exnihilo:sifting_table,,exnihilo,TRUE,,,130,,2,,,,,,
exnihilo.compatibility.nei.RecipeHandlerSieve,Ex Nihilo,exnihilo:sifting_table,,exnihilo,TRUE,,,130,,1,,,,,,
gregtech.Alloy,GregTech-Addon,gregtech_addon:machine:56,,gregtech_addon,TRUE,,15,145,166,2,,,,,,
gregtech.Assembler,GregTech-Addon,gregtech_addon:machine:60,,gregtech_addon,TRUE,,15,145,166,2,,,,,,
gregtech.Bender,GregTech-Addon,gregtech_addon:machine:59,,gregtech_addon,TRUE,,15,145,166,2,,,,,,
1 handler modName itemName nbtInfo modId modRequired excludedModId yShift handlerHeight handlerWidth maxRecipesPerPage imageResource imageX imageY imageWidth imageHeight itemNotes
373 NEIArcFurnaceHandlerExtraction Immersive Engineering minecraft:glowstone_dust ImmersiveEngineering TRUE 65 166 5
374 blusunrize.immersiveengineering.client.nei.NEIShaderBagHandler Immersive Engineering ImmersiveEngineering:shaderBag ImmersiveEngineering TRUE 65 166 5
375 blusunrize.immersiveengineering.client.nei.NEIBlueprintHandler Immersive Engineering ImmersiveEngineering:woodenDevice:5 ImmersiveEngineering TRUE 65 166 5
376 blusunrize.immersiveengineering.client.nei.NEICokeOvenHandler Immersive Engineering ImmersiveEngineering:stoneDecoration:1 ImmersiveEngineering TRUE 71 166 5 2
377 blusunrize.immersiveengineering.client.nei.NEIBlastFurnaceHandler Immersive Engineering ImmersiveEngineering:stoneDecoration:2 ImmersiveEngineering TRUE 71 166 5 2
378 blusunrize.immersiveengineering.client.nei.NEISqueezerHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:2 ImmersiveEngineering TRUE 1 71 64 166 5 2
379 blusunrize.immersiveengineering.client.nei.NEIFermenterHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:3 ImmersiveEngineering TRUE 1 71 64 166 5 2
380 blusunrize.immersiveengineering.client.nei.NEIRefineryHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:4 ImmersiveEngineering TRUE 65 166 5 2
381 blusunrize.immersiveengineering.client.nei.NEIBottlingMachineHandler Immersive Engineering minecraft:glass_bottle ImmersiveEngineering TRUE 65 166 5
382 blusunrize.immersiveengineering.client.nei.NEIMetalPressHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:13 ImmersiveEngineering TRUE 65 166 5
383 blusunrize.immersiveengineering.client.nei.NEICrusherHandler Immersive Engineering ImmersiveEngineering:metalMultiblock:5 ImmersiveEngineering TRUE 71 166 5
410 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingMachine Thermal Expansion ThermalExpansion:Frame ThermalExpansion TRUE 65 166 5
411 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingSecure Thermal Expansion ThermalExpansion:material:16 ThermalExpansion TRUE 65 166 5
412 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCraftingUpgrade Thermal Expansion ThermalExpansion:Frame:3 ThermalExpansion TRUE 65 166 5
413 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerCrucible Thermal Expansion ThermalExpansion:Machine:4 ThermalExpansion TRUE 65 166 5 2
414 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerFurnace Thermal Expansion ThermalExpansion:Machine:0 ThermalExpansion TRUE 65 166 5
415 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerInsolator Thermal Expansion ThermalExpansion:Machine:11 ThermalExpansion TRUE 65 166 5 2
416 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerPulverizer Thermal Expansion ThermalExpansion:Machine:1 ThermalExpansion TRUE 65 166 5
417 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSawmill Thermal Expansion ThermalExpansion:Machine:2 ThermalExpansion TRUE 65 166 5
418 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerSmelter Thermal Expansion ThermalExpansion:Machine:3 ThermalExpansion TRUE 65 166 5
419 cofh.thermalexpansion.plugins.nei.handlers.RecipeHandlerTransposer Thermal Expansion ThermalExpansion:Machine:5 ThermalExpansion TRUE 65 166 5 2
420 mekanism.client.nei.ChemicalCrystallizerRecipeHandler Mekanism Mekanism:MachineBlock2:8 Mekanism TRUE 79 4
421 mekanism.client.nei.ChemicalDissolutionChamberRecipeHandler Mekanism Mekanism:MachineBlock2:6 Mekanism TRUE 79 4
422 mekanism.client.nei.ChemicalInfuserRecipeHandler Mekanism Mekanism:MachineBlock2:2 Mekanism TRUE 80 4
437 mekanism.client.nei.SolarNeutronRecipeHandler Mekanism Mekanism:MachineBlock3:1 Mekanism TRUE 70 5
438 mekanism.client.nei.ThermalEvaporationRecipeHandler Mekanism Mekanism:BasicBlock:14 Mekanism TRUE 62 5
439 exnihilo.compatibility.nei.RecipeHandlerHammer Ex Nihilo exnihilo:hammer_iron exnihilo TRUE 58 5
440 exnihilo.compatibility.nei.RecipeHandlerSieve Ex Nihilo exnihilo:sifting_table exnihilo TRUE 130 2 1
441 gregtech.Alloy GregTech-Addon gregtech_addon:machine:56 gregtech_addon TRUE 15 145 166 2
442 gregtech.Assembler GregTech-Addon gregtech_addon:machine:60 gregtech_addon TRUE 15 145 166 2
443 gregtech.Bender GregTech-Addon gregtech_addon:machine:59 gregtech_addon TRUE 15 145 166 2
@@ -152,6 +152,9 @@ nei.options.inventory.saveCurrentRecipeInBookmarksEnabled.false=Disabled
nei.options.inventory.useNBTInBookmarks=Use NBT in Bookmarks
nei.options.inventory.useNBTInBookmarks.true=Yes
nei.options.inventory.useNBTInBookmarks.false=No
nei.options.inventory.recipeTooltipsEnabled=Show recipe tooltips in Bookmarks
nei.options.inventory.recipeTooltipsEnabled.true=Yes
nei.options.inventory.recipeTooltipsEnabled.false=No
nei.options.inventory.bookmarksAnimationEnabled=REI Style Animation in Bookmarks
nei.options.inventory.bookmarksAnimationEnabled.true=Yes
nei.options.inventory.bookmarksAnimationEnabled.false=No
@@ -342,4 +345,4 @@ nei.presets.whitelist.tooltip=Whitelist
nei.presets.textfield.tooltip.1=Enter - save
nei.presets.textfield.tooltip.2=Escape - cancel
nei.presets.label.tooltip=Double click to edit
nei.presets.label.selected=%s Presets
nei.presets.label.selected=%s Presets