diff --git a/README.md b/README.md
index 06ba32b3..ed4fca1d 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,59 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
* Cycle between Recipe, Utility, and Cheat mode by ctrl clicking on the Wrench Icon
* GT5u Tools/Items and GT6 tools should now properly work with the Overlay Recipe Transfer
+### Information Page Handler
+Want to add some information about a block or item without making a massive tooltip for it? You can add information about any block or item by registering it in the Information Handler.
+
+Information page(s) are displayed when either the uses or recipes of a matching item are searched. All matching items will cycle at the top of the information page.
+
+Your mod can call:
+```java
+FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", nbt);
+```
+Where nbt is an NBTTagCompound formatted as described below.
+
+| Tag | Type | Description |
+|------------------|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `filter` | String | A string filter to match what items should return this information page.
modname:itemname, metadata, Ore Dictionary tags, and regex can all be used. The full format may be seen in `config/NEI/collapsibleitems.cfg`. |
+| `page` / `pages` | String / String NBTTagList | The actual text to display. See below for differences between single and multi-page messages.
Both formats will automatically translate provided strings. |
+
+#### Single Page Format
+
+Use the `"page"` string tag when you only want to add one page of information:
+```java
+NBTTagCompound tag = new NBTTagCompound();
+tag.setString("filter", "minecraft:log 3");
+tag.setString("page", "Exotic wood found in tropical climates.");
+
+FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", tag);
+```
+
+#### Multiple Page Format
+
+Use the `"pages"` tag as an `NBTTagList` of strings when you want more than one page:
+```java
+NBTTagCompound tag = new NBTTagCompound();
+tag.setString("filter", "minecraft:diamond_sword");
+
+NBTTagList pages = new NBTTagList();
+pages.appendTag(new NBTTagString("A powerful melee weapon."));
+pages.appendTag(new NBTTagString("Can be enchanted for extra effects."));
+
+tag.setTag("pages", pages);
+
+FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", tag);
+```
+* Each list entry is one page.
+* Pages will appear in NEI with buttons to scroll through them.
+
+#### Item Matching
+
+All items that match `filter` will show your information page. See `config/NEI/collapsibleitems.cfg` for the full filter format.
+
+#### Item Information Config File
+
+If you're a modpack creator and want to make custom item information pages, they can easily be added in `config/NEI/informationpages.cfg`, which has a few more examples.
+
## Other items of note:
* Remove TMI style
diff --git a/src/main/java/codechicken/nei/ItemList.java b/src/main/java/codechicken/nei/ItemList.java
index 88aa744d..91b28296 100644
--- a/src/main/java/codechicken/nei/ItemList.java
+++ b/src/main/java/codechicken/nei/ItemList.java
@@ -28,6 +28,7 @@ import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
+import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.search.TooltipFilter;
public class ItemList {
@@ -289,7 +290,7 @@ public class ItemList {
.collect(Collectors.toList());
}
- // For optimization it generate itemslist, permutations, orders & collapsibleitems
+ // Generate itemlist, permutations, orders, collapsibleitems, and informationhandler stacks
@Override
@SuppressWarnings("unchecked")
public void execute() {
@@ -303,6 +304,7 @@ public class ItemList {
ItemSorter.instance.ordering.clear();
CollapsibleItems.clearCache();
TooltipFilter.clearCache();
+ InformationHandler.clearCache();
List items = new ArrayList<>();
ListMultimap- itemMap = ArrayListMultimap.create();
@@ -329,6 +331,7 @@ public class ItemList {
CollapsibleItems.putItem(stack);
TooltipFilter.getSearchTooltip(stack);
+ InformationHandler.populateStacks(stack);
}
}
diff --git a/src/main/java/codechicken/nei/NEIClientConfig.java b/src/main/java/codechicken/nei/NEIClientConfig.java
index f36d4bf7..a44ab846 100644
--- a/src/main/java/codechicken/nei/NEIClientConfig.java
+++ b/src/main/java/codechicken/nei/NEIClientConfig.java
@@ -58,6 +58,7 @@ import codechicken.nei.config.preset.GuiPresetList;
import codechicken.nei.event.NEIConfigsLoadedEvent;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.IRecipeHandler;
+import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.util.NEIKeyboardUtils;
@@ -899,6 +900,7 @@ public class NEIClientConfig {
LayoutManager.load();
NEIController.load();
BookmarkContainerInfo.load();
+ InformationHandler.load();
mainNEIConfigLoaded = true;
new Thread("NEI Plugin Loader") {
diff --git a/src/main/java/codechicken/nei/config/IMCHandler.java b/src/main/java/codechicken/nei/config/IMCHandler.java
index 06ab21af..62837a3c 100644
--- a/src/main/java/codechicken/nei/config/IMCHandler.java
+++ b/src/main/java/codechicken/nei/config/IMCHandler.java
@@ -1,13 +1,13 @@
package codechicken.nei.config;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
import codechicken.core.CommonUtils;
import codechicken.nei.NEIClientConfig;
@@ -15,6 +15,7 @@ import codechicken.nei.NEIServerUtils;
import codechicken.nei.recipe.CatalystInfo;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.HandlerInfo;
+import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
@@ -33,18 +34,11 @@ public class IMCHandler {
if (type == null || type.isEmpty()) continue;
if (CommonUtils.isClient()) {
switch (type) {
- case "registerHandlerInfo":
- handleRegisterHandlerInfo(message);
- break;
- case "removeHandlerInfo":
- handleRemoveHandlerInfo(message);
- break;
- case "registerCatalystInfo":
- handleRegisterCatalystInfo(message);
- break;
- case "removeCatalystInfo":
- handleRemoveCatalystInfo(message);
- break;
+ case "registerHandlerInfo" -> handleRegisterHandlerInfo(message);
+ case "removeHandlerInfo" -> handleRemoveHandlerInfo(message);
+ case "registerCatalystInfo" -> handleRegisterCatalystInfo(message);
+ case "removeCatalystInfo" -> handleRemoveCatalystInfo(message);
+ case "addItemInfo" -> handleAddItemInfo(message);
}
}
}
@@ -57,7 +51,7 @@ public class IMCHandler {
}
final NBTTagCompound tag = message.getNBTValue();
final String handler = tag.getString("handler");
- NEIClientConfig.logger.info("Processing registerHandlerInfo `" + handler + "` from " + message.getSender());
+ NEIClientConfig.logger.info("Processing registerHandlerInfo `{}` from {}", handler, message.getSender());
final String modName = tag.getString("modName");
final String modId = tag.getString("modId");
@@ -100,7 +94,7 @@ public class IMCHandler {
: HandlerInfo.DEFAULT_MAX_PER_PAGE;
info.setHandlerDimensions(imageHeight, imageWidth, maxRecipesPerPage);
} catch (NumberFormatException ignored) {
- NEIClientConfig.logger.info("Error setting handler dimensions for " + handler);
+ NEIClientConfig.logger.info("Error setting handler dimensions for {}", handler);
}
// true if not set to false
@@ -118,7 +112,7 @@ public class IMCHandler {
}
final NBTTagCompound tag = message.getNBTValue();
final String handler = tag.getString("handler");
- NEIClientConfig.logger.info("Processing removeHandlerInfo `" + handler + "` from " + message.getSender());
+ NEIClientConfig.logger.info("Processing removeHandlerInfo `{}` from {}", handler, message.getSender());
GuiRecipeTab.handlerRemoverFromIMC.add(handler);
}
@@ -130,7 +124,7 @@ public class IMCHandler {
}
if (!processedCatalystSenders.contains(message.getSender())) {
- NEIClientConfig.logger.info("Processing registerCatalystInfo from " + message.getSender());
+ NEIClientConfig.logger.info("Processing registerCatalystInfo from {}", message.getSender());
processedCatalystSenders.add(message.getSender());
}
final NBTTagCompound tag = message.getNBTValue();
@@ -139,23 +133,14 @@ public class IMCHandler {
NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
return;
}
- final String itemName = tag.getString("itemName");
- final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
- if (itemName.isEmpty()) {
- NEIClientConfig.logger.warn(String.format("Missing itemName for registerCatalystInfo in `%s`!", handlerID));
- return;
- }
- final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
+ final ItemStack itemStack = getItemStackFromIMC(message, "registerCatalystInfo");
if (itemStack == null) {
- NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
return;
}
final int priority = tag.getInteger("priority");
-
RecipeCatalysts
.addOrPut(RecipeCatalysts.catalystsAdderFromIMC, handlerID, new CatalystInfo(itemStack, priority));
- NEIClientConfig.logger
- .info(String.format("Added catalyst `%s` to handler %s", itemStack.getDisplayName(), handlerID));
+ NEIClientConfig.logger.info("Added catalyst `{}` to handler {}", itemStack.getDisplayName(), handlerID);
}
private static void handleRemoveCatalystInfo(IMCMessage message) {
@@ -164,33 +149,62 @@ public class IMCHandler {
return;
}
- NEIClientConfig.logger.info("Processing removeCatalystInfo from " + message.getSender());
final NBTTagCompound tag = message.getNBTValue();
final String handlerID = tag.getString("handlerID");
if (handlerID.isEmpty()) {
- NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
+ NEIClientConfig.logger.warn("Missing handlerID for removeCatalystInfo!");
return;
}
- final String itemName = tag.getString("itemName");
- final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
- if (itemName.isEmpty()) {
- NEIClientConfig.logger.warn(String.format("Missing itemName for registerCatalystInfo in `%s`!", handlerID));
- return;
- }
- final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
+ final ItemStack itemStack = getItemStackFromIMC(message, "removeCatalystInfo");
if (itemStack == null) {
- NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
return;
}
- if (RecipeCatalysts.catalystsRemoverFromIMC.containsKey(handlerID)) {
- RecipeCatalysts.catalystsRemoverFromIMC.get(handlerID).add(itemStack);
- } else {
- RecipeCatalysts.catalystsRemoverFromIMC
- .put(handlerID, new ArrayList<>(Collections.singletonList(itemStack)));
+ RecipeCatalysts.catalystsRemoverFromIMC.computeIfAbsent(handlerID, k -> new ArrayList<>()).add(itemStack);
+ NEIClientConfig.logger.info("Removed catalyst `{}` from handler {}", itemStack.getDisplayName(), handlerID);
+ }
+
+ private static void handleAddItemInfo(IMCMessage message) {
+ if (!message.isNBTMessage()) {
+ logInvalidMessage(message, "NBT");
+ return;
}
- NEIClientConfig.logger
- .info(String.format("Removed catalyst `%s` from handler %s", itemStack.getDisplayName(), handlerID));
+
+ final NBTTagCompound tag = message.getNBTValue();
+ if (tag.hasKey("pages")) addMultipleInfoPages(message);
+ if (tag.hasKey("page")) addSingleInfoPage(message);
+ }
+
+ private static void addMultipleInfoPages(IMCMessage message) {
+ final NBTTagCompound tag = message.getNBTValue();
+ final String filter = tag.getString("filter");
+ final NBTTagList pages = tag.getTagList("pages", 8); // 8 = TAG_String
+ for (int i = 0; i < pages.tagCount(); i++) {
+ String page = pages.getStringTagAt(i);
+ InformationHandler.addInformationPage(filter, page);
+ }
+ }
+
+ private static void addSingleInfoPage(IMCMessage message) {
+ final NBTTagCompound tag = message.getNBTValue();
+ String filter = tag.getString("filter");
+ String page = tag.getString("page");
+ InformationHandler.addInformationPage(filter, page);
+ }
+
+ private static ItemStack getItemStackFromIMC(IMCMessage message, String logAction) {
+ final NBTTagCompound tag = message.getNBTValue();
+ final String itemName = tag.getString("itemName");
+ final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
+
+ NEIClientConfig.logger.info("Processing {} for item `{}` from {}", logAction, itemName, message.getSender());
+ final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
+
+ if (itemStack == null) {
+ NEIClientConfig.logger.warn("Cannot find item `{}`!", itemName);
+ }
+
+ return itemStack;
}
private static void logInvalidMessage(FMLInterModComms.IMCMessage message, String type) {
diff --git a/src/main/java/codechicken/nei/recipe/InformationHandler.java b/src/main/java/codechicken/nei/recipe/InformationHandler.java
new file mode 100644
index 00000000..d59b7f5b
--- /dev/null
+++ b/src/main/java/codechicken/nei/recipe/InformationHandler.java
@@ -0,0 +1,150 @@
+package codechicken.nei.recipe;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.StatCollector;
+
+import codechicken.nei.ClientHandler;
+import codechicken.nei.NEIClientConfig;
+import codechicken.nei.NEIClientUtils;
+import codechicken.nei.PositionedStack;
+import codechicken.nei.api.ItemFilter;
+import codechicken.nei.util.ItemStackFilterParser;
+
+public class InformationHandler extends TemplateRecipeHandler {
+
+ private static final List ITEM_INFO = new ArrayList<>();
+
+ public static void addInformationPage(String filter, String description) {
+ if (filter.isEmpty() || description.isEmpty()) return;
+ ITEM_INFO.add(new InformationPage(filter, description));
+ }
+
+ public static void populateStacks(ItemStack stack) {
+ for (InformationPage page : ITEM_INFO) {
+ page.addItem(stack);
+ }
+ }
+
+ @Override
+ public void drawExtras(int recipe) {
+ CachedInfoPage page = (CachedInfoPage) this.arecipes.get(recipe);
+ drawWrappedText(StatCollector.translateToLocal(page.getPage().info).replace("\\n", "\n"), 4, 24);
+ }
+
+ private void drawWrappedText(String text, int x, int y) {
+ FontRenderer font = Minecraft.getMinecraft().fontRenderer;
+ List lines = font.listFormattedStringToWidth(text, 156);
+ for (String line : lines) {
+ font.drawString(line, x, y, 0);
+ y += 10;
+ }
+ }
+
+ public static void clearCache() {
+ for (InformationPage page : ITEM_INFO) {
+ page.items.clear();
+ }
+ }
+
+ @Override
+ public String getRecipeName() {
+ return NEIClientUtils.translate("recipe.information");
+ }
+
+ @Override
+ public String getOverlayIdentifier() {
+ return "information";
+ }
+
+ @Override
+ public void loadCraftingRecipes(ItemStack result) {
+ for (InformationPage page : ITEM_INFO) {
+ if (page.filter.matches(result)) {
+ arecipes.add(new CachedInfoPage(page));
+ }
+ }
+ }
+
+ @Override
+ public void loadUsageRecipes(ItemStack ingredient) {
+ loadCraftingRecipes(ingredient);
+ }
+
+ @Override
+ public String getGuiTexture() {
+ return "nei:textures/gui/recipebg.png";
+ }
+
+ private class CachedInfoPage extends CachedRecipe {
+
+ private final InformationPage page;
+ private final PositionedStack stack;
+
+ public CachedInfoPage(InformationPage page) {
+ this.page = page;
+ stack = new PositionedStack(page.items, 75, 2);
+ }
+
+ @Override
+ public PositionedStack getResult() {
+ return null;
+ }
+
+ @Override
+ public List getIngredients() {
+ return getCycledIngredients(cycleticks / 20, Collections.singletonList(this.stack));
+ }
+
+ public InformationPage getPage() {
+ return page;
+ }
+ }
+
+ private static class InformationPage {
+
+ final List items = new ArrayList<>();
+ final String info;
+ final ItemFilter filter;
+
+ public InformationPage(String filter, String info) {
+ this.filter = ItemStackFilterParser.parse(filter.trim());
+ this.info = info;
+ }
+
+ /**
+ * Adds the item stack if it matches the filter.
+ */
+ public void addItem(ItemStack stack) {
+ if (filter.matches(stack)) items.add(stack);
+ }
+ }
+
+ public static void load() {
+ ClientHandler.loadSettingsFile(
+ "informationpages.cfg",
+ lines -> parseFile(lines.collect(Collectors.toCollection(ArrayList::new))));
+ }
+
+ private static void parseFile(List lines) {
+ for (String rawLine : lines) {
+ String line = rawLine.trim();
+
+ int sepIndex = line.indexOf('=');
+ if (sepIndex == -1) {
+ NEIClientConfig.logger.warn("[NEI Info] Invalid line (no '=') in config: {}", line);
+ continue;
+ }
+
+ String filter = line.substring(0, sepIndex).trim();
+ String description = line.substring(sepIndex + 1).trim();
+ addInformationPage(filter, description);
+ }
+ }
+}
diff --git a/src/main/java/codechicken/nei/recipe/RecipeInfo.java b/src/main/java/codechicken/nei/recipe/RecipeInfo.java
index e5703230..c1c33020 100644
--- a/src/main/java/codechicken/nei/recipe/RecipeInfo.java
+++ b/src/main/java/codechicken/nei/recipe/RecipeInfo.java
@@ -101,6 +101,8 @@ public class RecipeInfo {
API.registerUsageHandler(new BrewingRecipeHandler());
API.registerRecipeHandler(new FuelRecipeHandler());
API.registerUsageHandler(new FuelRecipeHandler());
+ API.registerRecipeHandler(new InformationHandler());
+ API.registerUsageHandler(new InformationHandler());
API.registerGuiOverlay(GuiCrafting.class, "crafting");
API.registerGuiOverlay(GuiInventory.class, "crafting2x2", 63, 20);
diff --git a/src/main/resources/assets/nei/cfg/hiddenitems.cfg b/src/main/resources/assets/nei/cfg/hiddenitems.cfg
index 262fa7c5..ce0cd6f8 100644
--- a/src/main/resources/assets/nei/cfg/hiddenitems.cfg
+++ b/src/main/resources/assets/nei/cfg/hiddenitems.cfg
@@ -1,18 +1,6 @@
# Hidden Items Filters
#
-# parts:
-# modname:itemid - identify
-# $orename - ore dictionary
-# tag.color=red - tag
-# 0 or 0-12 - damage
-#
-# modifiers:
-# ! - logical not. exclude items that match the following expression (!minecraft:portal)
-# r/.../ - standard java regex (r/^m\w{6}ft$/ = minecraft)
-# , - logical or in token (minecraft:potion 16384-16462,!16386)
-# | - logical or multi-item search (wrench|hammer)
-#
-# example: minecraft:potion 16384-16462,!16386 | $oreiron | tag.color=red
+# Uses the same filter format at collapsibleitems.cfg
#
minecraft:portal
minecraft:end_portal
diff --git a/src/main/resources/assets/nei/cfg/informationpages.cfg b/src/main/resources/assets/nei/cfg/informationpages.cfg
new file mode 100644
index 00000000..7abf966b
--- /dev/null
+++ b/src/main/resources/assets/nei/cfg/informationpages.cfg
@@ -0,0 +1,28 @@
+# NEI Item Information Config
+#
+# One page per line, in the format:
+# filter = description text
+#
+# The filter uses the same format as collapsibleitems.cfg.
+#
+# You can repeat the same filter on multiple lines to add extra pages.
+# Use \n to insert line breaks inside the description. Use it multiple times for a larger gap between lines.
+# Using a translation key for the description will automatically translate it.
+# Only the first '=' after the filter is treated as the separator; feel free to put them in your descriptions.
+# Spaces before and after '=' are removed from the description and are optional.
+# The same item can match filters for multiple pages, unlike collapsibleitems.cfg only putting them in the first matching group.
+#
+# Empty lines and lines starting with # are ignored.
+#
+# Examples:
+# # Jungle Wood (meta 3)
+# minecraft:log 3 = Exotic wood found in tropical climates.
+#
+# # Diamond Sword (two pages of information)
+# minecraft:diamond_sword = A powerful melee weapon. Does 8 damage total.
+# minecraft:diamond_sword = Can be enchanted for extra effects.
+#
+# # Two different ore dictionary tags. Iron ingots match both.
+# $iron = Iron is a very versatile material. It can be found below sea level in the Overworld.
+# $ingot = Ingots are the refined form of metal or clay.
+#
diff --git a/src/main/resources/assets/nei/csv/handlers.csv b/src/main/resources/assets/nei/csv/handlers.csv
index ba9096d2..10e9d557 100644
--- a/src/main/resources/assets/nei/csv/handlers.csv
+++ b/src/main/resources/assets/nei/csv/handlers.csv
@@ -5,6 +5,7 @@ codechicken.nei.recipe.FurnaceRecipeHandler,Minecraft,minecraft:furnace,,minecra
codechicken.nei.recipe.ShapedRecipeHandler,Minecraft,minecraft:crafting_table,,minecraft,FALSE,,,65,166,5,,,,,,
codechicken.nei.recipe.ShapelessRecipeHandler,Minecraft,minecraft:crafting_table,,minecraft,FALSE,,,65,166,5,,,,,,
codechicken.nei.recipe.FuelRecipeHandler,Minecraft,,,minecraft,FALSE,,,65,166,5,nei:textures/nei_tabbed_sprites.png,80,0,14,14,
+codechicken.nei.recipe.InformationHandler,Not Enough Items,,,nei,FALSE,,,65,166,1,nei:textures/nei_tabbed_sprites.png,96,0,16,16,
advsolar.client.nei.MTRecipeHandler,Advanced Solar Panels,AdvancedSolarPanel:BlockMolecularTransformer,,AdvancedSolarPanel,TRUE,,,68,,5,,,,,,
appeng.integration.modules.NEIHelpers.NEIAEShapedRecipeHandler,Applied Energistics 2,appliedenergistics2:item.ItemMultiPart:380,,appliedenergistics2,TRUE,,,65,,5,,,,,,
appeng.integration.modules.NEIHelpers.NEIAEShapelessRecipeHandler,Applied Energistics 2,appliedenergistics2:item.ItemMultiPart:380,,appliedenergistics2,TRUE,,,65,,5,,,,,,
diff --git a/src/main/resources/assets/nei/lang/en_US.lang b/src/main/resources/assets/nei/lang/en_US.lang
index 9b81b45e..f5ea555d 100644
--- a/src/main/resources/assets/nei/lang/en_US.lang
+++ b/src/main/resources/assets/nei/lang/en_US.lang
@@ -513,6 +513,8 @@ nei.recipe.favorite=Favorite
nei.recipe.favorite.bookmark_recipe=Save Recipe Tree
nei.recipe.favorite.change_result_index=Change Output
+nei.recipe.information=Information
+
nei.itemsort.minecraft=Minecraft
nei.itemsort.minecraft.tip=Sorts items from vanilla minecraft first
nei.itemsort.mod=Mod
diff --git a/src/main/resources/assets/nei/textures/nei_tabbed_sprites.png b/src/main/resources/assets/nei/textures/nei_tabbed_sprites.png
index ec3c6e42..e752d943 100644
Binary files a/src/main/resources/assets/nei/textures/nei_tabbed_sprites.png and b/src/main/resources/assets/nei/textures/nei_tabbed_sprites.png differ