mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-10-26 22:33:52 +00:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81e2c9b499 | ||
|
|
42055d4a40 | ||
|
|
7ab8940287 | ||
|
|
3449e9d153 | ||
|
|
c5fc636b13 | ||
|
|
cfe35b0bef | ||
|
|
3a0892f9db | ||
|
|
d1af307b82 | ||
|
|
9109da8fca | ||
|
|
238e945126 | ||
|
|
e748c6779b | ||
|
|
75e8270bad | ||
|
|
c4c7d6d055 | ||
|
|
2630d887eb | ||
|
|
f8cc9bd0e6 |
No files matched your search
@@ -2,11 +2,13 @@
|
||||
|
||||
A continuation of NotEnoughItems for 1.7.10 by the developers of Gregtech: New Horizons modpack, with features either inspired and/or backported from JustEnoughItems
|
||||
|
||||
We've tested this against all of the mods included in GTNH, as well as a limited set of other mods (like Reika's mods). Every effort has been made to maintain backwards compatibility, however the focus is on the mods contained in the GTNH modpack.
|
||||
We've tested this against all the mods included in GTNH, as well as a limited set of other mods (like Reika's mods). Every effort has been made to maintain backwards compatibility, however the focus is on the mods contained in the GTNH modpack.
|
||||
|
||||
If you have issues with NEI outside of the GTNH modpack you may report them in the [GTNH NEI GitHub](https://github.com/GTNewHorizons/NotEnoughItems).
|
||||
If you have issues with NEI outside the GTNH modpack, please report them in the [GTNH NEI GitHub](https://github.com/GTNewHorizons/NotEnoughItems).
|
||||
|
||||
## New Features:
|
||||
## Changes in this fork
|
||||
|
||||
### New Features:
|
||||
|
||||
* Speed
|
||||
- Uses a parallel stream to search the item list over multiple cores, resulting in 2-6x faster searches on average
|
||||
@@ -22,12 +24,205 @@ 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
|
||||
|
||||
## Other items of note:
|
||||
### Other items of note:
|
||||
|
||||
* Remove TMI style
|
||||
* Removed inventory Load/Save state
|
||||
|
||||
## Development
|
||||
## Adding support for GTNH NEI features to your mod
|
||||
|
||||
### Help! My mod is broken in your version of NEI! How can I fix it?
|
||||
|
||||
Our version of NEI changes the recipe UI to be a bit more similar to [JEI][JEI]. As such, some legacy recipe handlers that assume the specific UI layout of old NEI might break even after providing additional metadata. Changes to the UI include the following: the recipe screen no longer has a fixed height, but can stretch to show more recipes at once. Additionally, the screen is no longer vertically centered, but at a fixed offset from the top of the MC window. Furthermore, the recipe paging widget has been moved from the bottom to the top of the recipe screen.
|
||||
|
||||
The following sections list strategies for fixing broken handlers. You are also always welcome to open an issue in our repository if you are stuck with a broken recipe handler.
|
||||
|
||||
#### My mod is broken and I can't fix it, because I'm not a developer, or the mod's license doesn't allow modification
|
||||
|
||||
Some mods are no longer maintained and cannot be updated due to licensing. For those we provide two ways of fixing broken recipe handlers. The first one are the `handlers.csv` and `catalysts.csv` files that are packaged in the NEI mod jar. These files include recipe handler metadata for mods that don't ship it on their own. If the broken recipe handler is not already in there, you can enable the config options under `NEI Options > Tools > Load handlers/catalysts from Config` that will put a copy of those files into the config directory which you then can edit. The columns are described in the sections below.
|
||||
|
||||
Second, if tweak handler parameters via `handlers.csv` doesn't help and there are still some glitches, we provide a last-ditch effort called the "height hack". This tries to emulate the old NEI recipe layout, specifically on the vertical axis where our version of NEI had the most significant changes. This should help with misaligned tooltips and click zones especially. The height hack can be enabled by adding the fully-qualified class name of the recipe handler to the `heighthackhandlers.cfg` config file. If you encounter a recipe handler that requires this measure please open an issue and let us know.
|
||||
|
||||
#### I'm a developer working on my own mod or maintaining a forked mod
|
||||
|
||||
Please consider adding support for our IMC messages or events to automatically register handler metadata for your mod. The fields available in the new metadata are described in the following section.
|
||||
|
||||
Even after providing handler metadata, there may still be broken elements in your handler. In our experience this most commonly affects tooltips and custom click zones. **Please make sure to not rely on a fixed screen layout!** In particular, do not use `GuiScreen.height` to calculate the top edge of the recipe UI, instead use `guiTop`. Also, do not assume a fixed offset from the top edge of the recipe screen (the offset is different in legacy NEI compared to our version), instead use `GuiRecipe#getRecipePosition`. `GuiRecipe` may already be passed to certain handler methods if you're overriding `TemplateRecipeHandler`, alternatively, you can obtain a reference to it via:
|
||||
```java
|
||||
GuiRecipe gui = (GuiRecipe) Minecraft.getMinecraft().currentScreen;
|
||||
```
|
||||
|
||||
Also, do not assume a fixed number of recipes will be shown at a time. Due to the flexible layout, the number might vary between 1 and `maxRecipesPerPage`. Again, make use of `GuiRecipe#getRecipePosition`.
|
||||
|
||||
Here is an example of a poorly implemented recipe handler:
|
||||
```java
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiRecipe gui, List<String> list, int recipeIdx) {
|
||||
CachedMachineRecipe r = (CachedMachineRecipe) this.arecipes.get(recipeIdx % this.arecipes.size());
|
||||
if (r != null) {
|
||||
Point mousePosition = GuiDraw.getMousePosition();
|
||||
int gleft = (gui.width - 176) / 2;
|
||||
int gtop = (gui.height - 134) / 2; // BAD: uses gui.height instead of gui.guiTop
|
||||
if (r.fluid != null) {
|
||||
if (mousePosition.x > gleft + 110
|
||||
&& mousePosition.x <= gleft + 110 + 16
|
||||
&& mousePosition.y > gtop + 13 // BAD: assumes a fixed offset from gtop/guiTop
|
||||
&& mousePosition.y <= gtop + 13 + 47) {
|
||||
list.add(r.fluid.getLocalizedName());
|
||||
list.add(r.fluid.amount + " mB");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.handleTooltip(gui, list, recipeIdx);
|
||||
}
|
||||
```
|
||||
Here is an improved version that should work both in our NEI and in legacy NEI:
|
||||
```java
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiRecipe gui, List<String> list, int recipeIdx) {
|
||||
CachedMachineRecipe r = (CachedMachineRecipe) this.arecipes.get(recipeIdx % this.arecipes.size());
|
||||
if (r != null) {
|
||||
Point mousePosition = GuiDraw.getMousePosition();
|
||||
Point recipePosition = gui.getRecipePosition(recipeIdx);
|
||||
if (r.fluid != null) {
|
||||
if (mousePosition.x > (gui.guiLeft + recipePosition.x + 110)
|
||||
&& mousePosition.x <= (gui.guiLeft + recipePosition.x + 110 + 16)
|
||||
&& mousePosition.y > (gui.guiTop + recipePosition.y + 13)
|
||||
&& mousePosition.y <= (gui.guiTop + recipePosition.y + 13 + 47) {
|
||||
list.add(r.fluid.getLocalizedName());
|
||||
list.add(r.fluid.amount + " mB");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.handleTooltip(gui, list, recipeIdx);
|
||||
}
|
||||
```
|
||||
|
||||
### New Metadata for recipe handlers
|
||||
|
||||
Legacy NEI only had a small, fixed size recipe screen, showing one or two recipes at a time. Our version, borrowing from JEI, improves this by switching to a flexible screen height that allows showing up to 5 recipes at a time in many cases. In addition, the new JEI-style tab bar improves navigation between handlers by showing an icon for each recipe handler.
|
||||
|
||||
To enable these new capabilities, NEI has to be given additional metadata to make it work. This version of NEI includes new native APIs and additionally ships with two files `assets/nei/csv/handlers.csv`, and `assets/nei/csv/catalysts.csv` as a fallback solution to include the necessary information for mods that are no longer updated and do not take advantage of the native APIs that are provided. If you are working on a mod of your own that includes NEI integration, we encourage you to add IMC or event support as described below.
|
||||
|
||||
#### Recipe handler metadata
|
||||
|
||||
(values are strings if not specified otherwise)
|
||||
|
||||
- **handlerID:** handler identifier, usually the fully-qualified class name of the recipe handler (including package name); can differ to provide multiple handlers from a single class; check the handler dump described in a section below
|
||||
- example: `vazkii.botania.client.integration.nei.recipe.RecipeHandlerPureDaisy`
|
||||
- *required*
|
||||
- **modName:** display name of the mod to which the recipe handler belongs to
|
||||
- example: `Botania`
|
||||
- *required*
|
||||
- **itemName**, and **nbtInfo:** item used as an icon to represent the recipe handler in the tab bar
|
||||
- example: `Botania:specialFlower` (itemName), `{type:puredaisy}` (nbtInfo)
|
||||
- **modId:** modid of the mod for which the recipe handler is responsible
|
||||
- example: `Botania`
|
||||
- *required*
|
||||
- **modRequired:** whether the mod specified in `modId` needs to be present in order for NEI to load the recipe handler (boolean value; `TRUE`/`FALSE` in CSV)
|
||||
- **excludedModId:** prevent the recipe handler from being loaded if the specified mod is present
|
||||
- **yShift:** allows fine control over vertical alignment of the recipes from top of the recipe screen; value is in pixels (integer value)
|
||||
- default: `0`
|
||||
- **handlerHeight:** height of a single recipe in pixels, used for tiling multiple recipes vertically according to `maxRecipesPerPage` (integer value)
|
||||
- default: `65`
|
||||
- **handlerWidth:** width of a single recipe in pixels (integer value)
|
||||
- default: `166`
|
||||
- **maxRecipesPerPage:** maximum number of recipes to show per page; less recipes will be shown if they do not fit on the screen (integer value)
|
||||
- default: `1`
|
||||
- **imageResource**, **imageX**, **imageY**, **imageWidth**, and **imageHeight:** allow specifying an arbitrary texture as icon for this recipe handler instead of an item; `imageX`, `imageY`, `imageWidth`, and `imageHeight` allow indexing into a sprite sheet (integer values except for `imageResource`)
|
||||
- example: `nei:textures/nei_tabbed_sprites.png` (imageResource), `80` (imageX), `0` (imageY), `14` (imageWidth), `14` (imageHeight)
|
||||
- **itemNotes:** ignored by NEI; this field is purely informational for development; not available via IMC/event
|
||||
|
||||
#### Catalyst metadata
|
||||
|
||||
The catalyst concept has been borrowed from JEI. The idea behind it is, that in addition to the recipe inputs and outputs, a recipe is also associated with the "machine" that processes it (also called a 'catalyst'). That way, if you look up a recipe you can also see which "machines" enable it. For example regular crafting recipes can be processed in a Crafting Table, however there may be many more blocks that provide the same functionality and NEI now lists them alongside the recipe. Similarly, if you look up uses for a "machine" or catalyst, it will automatically show all recipes that can be processed with it.
|
||||
|
||||
Again, this needs additional metadata work, either provided by mods themselves, or through default configuration in `assets/nei/csv/catalysts.csv`.
|
||||
|
||||
(values are strings if not specified otherwise)
|
||||
|
||||
- **catalystHandlerID:** identifier of the handler for which this catalyst can be used; by default, this should be the overlay identifier, or alternatively the handler identifier if the former is not defined, or `forceClassName` is true; appropriate values can be inferred from the handler information dump described in a following section
|
||||
- example: `vazkii.botania.client.integration.nei.recipe.RecipeHandlerPureDaisy`, or `crafting`
|
||||
- *required*
|
||||
- **itemName:**, and **nbtInfo:** actual catalyst item
|
||||
- example: `Botania:specialFlower` (itemName), `{type:puredaisy}` (nbtInfo)
|
||||
- *required* (itemName)
|
||||
- **modId:** modid of the mod which includes the catalyst
|
||||
- **modRequired:** whether the mod specified in `modId` needs to be present in order for NEI to load the catalyst (boolean value; `TRUE`/`FALSE` in CSV)
|
||||
- *required*
|
||||
- **excludedModId:** prevent the catalyst from being loaded if the specified mod is present
|
||||
- **priority:** position of the catalyst within the list of all possible catalysts for a given recipe handler; higher priority takes precedence (integer value)
|
||||
- default: `0`
|
||||
- **minVersion:**, and **maxVersion:** only present in `catalysts.csv`, currently unused
|
||||
- **forceClassName:** `catalystHandlerID` by default refers to the overlay identifier of the recipe handler and only falls back to the handler identifier if the former is undefined, so this options allows forcing matching the handler identifier even when an overlay identifier exists separately; only supported in `catalysts.csv` (boolean value)
|
||||
- **itemNotes:** ignored by NEI; this field is purely informational for development; not available via IMC
|
||||
|
||||
#### Dumping recipe handler information for debugging
|
||||
|
||||
NEI can dump information about all currently loaded recipe handlers. This helps especially with finding the correct handler and overlay identifiers for matching handler and catalyst metadata.
|
||||
|
||||
This information can be dumped through NEI options > Tools > Dumps > Handler.
|
||||
|
||||
Among other things, this dump lists all loaded recipe handlers by their handler identifier and their overlay identifier (if defined).
|
||||
|
||||
#### Sending metadata via IMC
|
||||
|
||||
Our version of NEI adds a range of IMC messages for registering handler metadata. This is the preferred way of specifying handler metadata. Please consider adding support for this in your own mod.
|
||||
|
||||
The following messages are available:
|
||||
- **registerHandlerInfo:** NBT IMC message; allowed keys are specified in the handler metadata section
|
||||
- **removeHandlerInfo:** NBT IMC message; required key: `handlerID`, identifier string of the handler to be removed
|
||||
- **registerCatalystInfo:** NBT IMC message; allowed keys are specified in the catalyst metadata section
|
||||
- **removeCatalystInfo:** NBT IMC message; required keys: `catalystHandlerID` ( identifier string of the handler from which the catalyst is to be removed), `itemName` (optionally specify `nbtInfo` if necessary)
|
||||
|
||||
Here is an example of how to send the handler and catalyst metadata via IMC:
|
||||
```java
|
||||
NEIInscriberRecipeHandler inscriberHandler = new NEIInscriberRecipeHandler();
|
||||
API.registerRecipeHandler(inscriberHandler);
|
||||
|
||||
NBTTagCompound handlerMetadata = new NBTTagCompound();
|
||||
handlerMetadata.setString("handlerID", inscriberHandler.getHandlerId());
|
||||
handlerMetadata.setString("modName", MOD_NAME);
|
||||
handlerMetadata.setString("modId", MOD_ID);
|
||||
handlerMetadata.setBoolean("modRequired", true);
|
||||
handlerMetadata.setString("itemName", GameRegistry.findUniqueIdentifierFor(block));
|
||||
handlerMetadata.setInteger("handlerHeight", 70);
|
||||
handlerMetadata.setInteger("maxRecipesPerPage", 5);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", handlerMetadata);
|
||||
|
||||
NBTTagCompound catalystMetadata = new NBTTagCompound();
|
||||
catalystMetadata.setString("catalystHandlerID", inscriberHandler.getOverlayIdentifier());
|
||||
catalystMetadata.setString("itemName", GameRegistry.findUniqueIdentifierFor(block));
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerCatalystInfo", catalystMetadata);
|
||||
```
|
||||
|
||||
#### Sending metadata through event handling
|
||||
|
||||
Besides IMC, there exists another native path for adding metadata to recipe handlers: subscribing to `NEIRegisterHandlerInfosEvent`. This requires adding NEI as a dependency to your project.
|
||||
|
||||
This event provides the `registerHandlerInfo()` method for adding metadata to your handlers. It takes a `Consumer` function which receives a `HandlerInfo` builder (`HandlerInfo` is the NEI class representing handler metadata).
|
||||
|
||||
Here is an example for handling such an event:
|
||||
```java
|
||||
@SubscribeEvent
|
||||
public void registerHandlers(NEIRegisterHandlerInfosEvent event) {
|
||||
event.registerHandlerInfo(
|
||||
handlerID,
|
||||
modName,
|
||||
modId,
|
||||
(builder) -> {
|
||||
return builder.setHeight(30).setMaxRecipesPerPage(5);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There is currently no event for registering catalysts.
|
||||
|
||||
## Developing NEI
|
||||
|
||||
Before launching, you need to add
|
||||
```
|
||||
-Dfml.coreMods.load=codechicken.nei.asm.NEICorePlugin
|
||||
@@ -40,6 +235,9 @@ GTNH Modifications Copyright (c) 2019-2022 mitchej123 and the GTNH Team
|
||||
|
||||
Licensed under LGPL-3.0 or later - use this however you want, but please give back any modifications
|
||||
|
||||
Parts inspired/borrowed/backported from [JEI](https://github.com/mezz/JustEnoughItems/tree/1.12) under the MIT License.
|
||||
Parts inspired/borrowed/backported from [JEI][JEI112Tree] under the MIT License.
|
||||
|
||||
Originial code Copyright (c) 2014-2015 mezz and was licensed under the MIT License.
|
||||
Original code Copyright (c) 2014-2015 mezz and was licensed under the MIT License.
|
||||
|
||||
[JEI]: https://github.com/mezz/JustEnoughItems
|
||||
[JEI112Tree]: https://github.com/mezz/JustEnoughItems/tree/1.12
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -21,8 +20,6 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import codechicken.core.CCUpdateChecker;
|
||||
import codechicken.core.ClassDiscoverer;
|
||||
import codechicken.core.ClientUtils;
|
||||
@@ -89,11 +86,6 @@ public class NEIClientConfig {
|
||||
// Any handler not in the map will be assigned to 0, and negative numbers are fine.
|
||||
public static HashMap<String, Integer> handlerOrdering = new HashMap<>();
|
||||
|
||||
// Function that extracts the handler ID from a handler, with special logic for
|
||||
// TemplateRecipeHandler: prefer using the overlay ID if it exists.
|
||||
public static final Function<IRecipeHandler, String> HANDLER_ID_FUNCTION = handler -> Objects
|
||||
.firstNonNull(handler.getOverlayIdentifier(), handler.getHandlerId());
|
||||
|
||||
public static int getHandlerOrder(IRecipeHandler handler) {
|
||||
if (handlerOrdering.get(handler.getOverlayIdentifier()) != null) {
|
||||
return handlerOrdering.get(handler.getOverlayIdentifier());
|
||||
@@ -242,6 +234,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 +554,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);
|
||||
|
||||
@@ -346,12 +346,12 @@ public class API {
|
||||
* category.
|
||||
*
|
||||
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
|
||||
* @param handler the recipe category handled by the ingredient
|
||||
* @param handler the handler that shows the ingredient's recipes
|
||||
* @param priority higher priority comes first, default to 0
|
||||
*/
|
||||
public static void addRecipeCatalyst(ItemStack stack, IRecipeHandler handler, int priority) {
|
||||
String handlerID = RecipeCatalysts.getRecipeID(handler);
|
||||
addRecipeCatalyst(stack, handlerID, priority);
|
||||
String catalystHandlerID = RecipeCatalysts.getCatalystHandlerId(handler);
|
||||
addRecipeCatalyst(stack, catalystHandlerID, priority);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,12 +366,13 @@ public class API {
|
||||
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
|
||||
* category.
|
||||
*
|
||||
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
|
||||
* @param handlerID recipe category identifier (see also {@link RecipeCatalysts#getRecipeID(IRecipeHandler)})
|
||||
* @param priority higher priority comes first, default to 0
|
||||
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
|
||||
* @param catalystHandlerID catalyst handler identifier (see
|
||||
* {@link RecipeCatalysts#getCatalystHandlerId(IRecipeHandler)})
|
||||
* @param priority higher priority comes first, default to 0
|
||||
*/
|
||||
public static void addRecipeCatalyst(ItemStack stack, String handlerID, int priority) {
|
||||
RecipeCatalysts.addRecipeCatalyst(handlerID, new CatalystInfo(stack, priority));
|
||||
public static void addRecipeCatalyst(ItemStack stack, String catalystHandlerID, int priority) {
|
||||
RecipeCatalysts.addRecipeCatalyst(catalystHandlerID, new CatalystInfo(stack, priority));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,12 +383,12 @@ public class API {
|
||||
}
|
||||
|
||||
public static void removeRecipeCatalyst(ItemStack stack, IRecipeHandler handler) {
|
||||
String handlerID = RecipeCatalysts.getRecipeID(handler);
|
||||
removeRecipeCatalyst(stack, handlerID);
|
||||
String catalystHandlerID = RecipeCatalysts.getCatalystHandlerId(handler);
|
||||
removeRecipeCatalyst(stack, catalystHandlerID);
|
||||
}
|
||||
|
||||
public static void removeRecipeCatalyst(ItemStack stack, String handlerID) {
|
||||
RecipeCatalysts.removeRecipeCatalyst(handlerID, stack);
|
||||
public static void removeRecipeCatalyst(ItemStack stack, String catalystHandlerID) {
|
||||
RecipeCatalysts.removeRecipeCatalyst(catalystHandlerID, stack);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -398,9 +399,9 @@ public class API {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void addRecipeCatalyst(List<ItemStack> stacks, String handlerID) {
|
||||
public static void addRecipeCatalyst(List<ItemStack> stacks, String catalystHandlerID) {
|
||||
for (ItemStack stack : stacks) {
|
||||
addRecipeCatalyst(stack, handlerID);
|
||||
addRecipeCatalyst(stack, catalystHandlerID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ public class HandlerDumper extends DataDumper {
|
||||
|
||||
@Override
|
||||
public String[] header() {
|
||||
return new String[] { "Handler Recipe Name", "Handler Class", "Overlay Identifier", "Mod DisplayName",
|
||||
"ItemStack" };
|
||||
return new String[] { "Handler Display Name", "Handler Identifier", "Overlay Identifier", "Mod Display Name",
|
||||
"Icon ItemStack" };
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,23 +56,33 @@ public class IMCHandler {
|
||||
return;
|
||||
}
|
||||
final NBTTagCompound tag = message.getNBTValue();
|
||||
final String handler = tag.getString("handler");
|
||||
NEIClientConfig.logger.info("Processing registerHandlerInfo `" + handler + "` from " + message.getSender());
|
||||
final String handlerID;
|
||||
if (tag.hasKey("handler")) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"Received tag 'handler' for registerHandlerInfo IMC from {}, this tag has been renamed to 'handlerID'",
|
||||
message.getSender());
|
||||
handlerID = tag.getString("handler");
|
||||
} else {
|
||||
handlerID = tag.getString("handlerID");
|
||||
}
|
||||
|
||||
NEIClientConfig.logger.info("Processing registerHandlerInfo for '{}' from {}", handlerID, message.getSender());
|
||||
final String modName = tag.getString("modName");
|
||||
final String modId = tag.getString("modId");
|
||||
final boolean requiresMod = tag.getBoolean("modRequired");
|
||||
final String excludedModId = tag.hasKey("excludedModId") ? tag.getString("excludedModId") : null;
|
||||
|
||||
if (handler.equals("") || modName.equals("") || modId.equals("")) {
|
||||
NEIClientConfig.logger.warn("Missing relevant information to registerHandlerInfo!");
|
||||
if (handlerID.equals("") || modName.equals("") || modId.equals("")) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"registerHandlerInfo IMC from {} is missing required tags 'handlerID', 'modName', and 'modID'",
|
||||
message.getSender());
|
||||
return;
|
||||
}
|
||||
|
||||
if (requiresMod && !Loader.isModLoaded(modId)) return;
|
||||
if (excludedModId != null && Loader.isModLoaded(excludedModId)) return;
|
||||
|
||||
HandlerInfo info = new HandlerInfo(handler, modName, modId, requiresMod, excludedModId);
|
||||
HandlerInfo info = new HandlerInfo(handlerID, modName, modId, requiresMod, excludedModId);
|
||||
final String imageResource = tag.hasKey("imageResource") ? tag.getString("imageResource") : null;
|
||||
if (imageResource != null && !imageResource.equals("")) {
|
||||
info.setImage(
|
||||
@@ -100,11 +110,11 @@ 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 '{}'", handlerID);
|
||||
}
|
||||
|
||||
GuiRecipeTab.handlerAdderFromIMC.remove(handler);
|
||||
GuiRecipeTab.handlerAdderFromIMC.put(handler, info);
|
||||
GuiRecipeTab.handlerAdderFromIMC.remove(handlerID);
|
||||
GuiRecipeTab.handlerAdderFromIMC.put(handlerID, info);
|
||||
}
|
||||
|
||||
private static void handleRemoveHandlerInfo(IMCMessage message) {
|
||||
@@ -113,10 +123,19 @@ public class IMCHandler {
|
||||
return;
|
||||
}
|
||||
final NBTTagCompound tag = message.getNBTValue();
|
||||
final String handler = tag.getString("handler");
|
||||
NEIClientConfig.logger.info("Processing removeHandlerInfo `" + handler + "` from " + message.getSender());
|
||||
final String handlerID;
|
||||
if (tag.hasKey("handler")) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"Received tag 'handler' for removeHandlerInfo IMC from {}, this tag has been renamed to 'handlerID'",
|
||||
message.getSender());
|
||||
handlerID = tag.getString("handler");
|
||||
} else {
|
||||
handlerID = tag.getString("handlerID");
|
||||
}
|
||||
|
||||
GuiRecipeTab.handlerRemoverFromIMC.add(handler);
|
||||
NEIClientConfig.logger
|
||||
.info("Processing removeHandlerInfo IMC for '{}' from {}", handlerID, message.getSender());
|
||||
GuiRecipeTab.handlerRemoverFromIMC.add(handlerID);
|
||||
}
|
||||
|
||||
private static void handleRegisterCatalystInfo(IMCMessage message) {
|
||||
@@ -126,32 +145,56 @@ public class IMCHandler {
|
||||
}
|
||||
|
||||
if (!processedCatalystSenders.contains(message.getSender())) {
|
||||
NEIClientConfig.logger.info("Processing registerCatalystInfo from " + message.getSender());
|
||||
processedCatalystSenders.add(message.getSender());
|
||||
}
|
||||
final NBTTagCompound tag = message.getNBTValue();
|
||||
final String handlerID = tag.getString("handlerID");
|
||||
if (handlerID.isEmpty()) {
|
||||
NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
|
||||
final String catalystHandlerID;
|
||||
if (tag.hasKey("handlerID")) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"Received tag 'handlerID' for registerCatalystInfo IMC from {}, this is deprecated, please use 'catalystHandlerID' instead",
|
||||
message.getSender());
|
||||
catalystHandlerID = tag.getString("handlerID");
|
||||
} else {
|
||||
catalystHandlerID = tag.getString("catalystHandlerID");
|
||||
}
|
||||
if (catalystHandlerID.equals("")) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"registerCatalystInfo IMC from {} is missing required tag 'catalystHandlerID'",
|
||||
message.getSender());
|
||||
return;
|
||||
}
|
||||
NEIClientConfig.logger
|
||||
.info("Processing registerCatalystInfo IMC for '{}' from {}", catalystHandlerID, message.getSender());
|
||||
|
||||
final String modId = tag.hasKey("modId") ? tag.getString("modId") : null;
|
||||
final boolean requiresMod = tag.getBoolean("modRequired");
|
||||
final String excludedModId = tag.hasKey("excludedModId") ? tag.getString("excludedModId") : null;
|
||||
|
||||
if (requiresMod && modId != null && !Loader.isModLoaded(modId)) return;
|
||||
if (excludedModId != null && Loader.isModLoaded(excludedModId)) 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));
|
||||
NEIClientConfig.logger.warn(
|
||||
"registerCatalystInfo IMC for '{}' from {} is missing required tag 'itemName'",
|
||||
catalystHandlerID,
|
||||
message.getSender());
|
||||
return;
|
||||
}
|
||||
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
|
||||
if (itemStack == null) {
|
||||
NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
|
||||
NEIClientConfig.logger.warn("Cannot find item '{}'!", itemName);
|
||||
return;
|
||||
}
|
||||
final int priority = tag.getInteger("priority");
|
||||
|
||||
RecipeCatalysts
|
||||
.addOrPut(RecipeCatalysts.catalystsAdderFromIMC, handlerID, new CatalystInfo(itemStack, priority));
|
||||
RecipeCatalysts.addOrPut(
|
||||
RecipeCatalysts.catalystsAdderFromIMC,
|
||||
catalystHandlerID,
|
||||
new CatalystInfo(itemStack, priority));
|
||||
NEIClientConfig.logger
|
||||
.info(String.format("Added catalyst `%s` to handler %s", itemStack.getDisplayName(), handlerID));
|
||||
.info("Added catalyst '{}' to catalyst handler {}", itemStack.getDisplayName(), catalystHandlerID);
|
||||
}
|
||||
|
||||
private static void handleRemoveCatalystInfo(IMCMessage message) {
|
||||
@@ -160,33 +203,46 @@ public class IMCHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
NEIClientConfig.logger.info("Processing removeCatalystInfo from " + message.getSender());
|
||||
NEIClientConfig.logger.info("Processing removeCatalystInfo IMC from {}", message.getSender());
|
||||
final NBTTagCompound tag = message.getNBTValue();
|
||||
final String handlerID = tag.getString("handlerID");
|
||||
if (handlerID.isEmpty()) {
|
||||
NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
|
||||
final String catalystHandlerID;
|
||||
if (tag.hasKey("handlerID")) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"Received tag 'handlerID' for removeCatalystInfo IMC from {}, this is deprecated, please use 'catalystHandlerID' instead",
|
||||
message.getSender());
|
||||
catalystHandlerID = tag.getString("handlerID");
|
||||
} else {
|
||||
catalystHandlerID = tag.getString("catalystHandlerID");
|
||||
}
|
||||
if (catalystHandlerID.isEmpty()) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"removeCatalystInfo IMC from {} is missing required tag 'catalystHandlerID'",
|
||||
message.getSender());
|
||||
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));
|
||||
NEIClientConfig.logger.warn(
|
||||
"removeCatalystInfo IMC for '{}' from {} is missing required tag 'itemName'",
|
||||
catalystHandlerID,
|
||||
message.getSender());
|
||||
return;
|
||||
}
|
||||
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
|
||||
if (itemStack == null) {
|
||||
NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
|
||||
NEIClientConfig.logger.warn("Cannot find item '{}'!", itemName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RecipeCatalysts.catalystsRemoverFromIMC.containsKey(handlerID)) {
|
||||
RecipeCatalysts.catalystsRemoverFromIMC.get(handlerID).add(itemStack);
|
||||
if (RecipeCatalysts.catalystsRemoverFromIMC.containsKey(catalystHandlerID)) {
|
||||
RecipeCatalysts.catalystsRemoverFromIMC.get(catalystHandlerID).add(itemStack);
|
||||
} else {
|
||||
RecipeCatalysts.catalystsRemoverFromIMC
|
||||
.put(handlerID, new ArrayList<>(Collections.singletonList(itemStack)));
|
||||
.put(catalystHandlerID, new ArrayList<>(Collections.singletonList(itemStack)));
|
||||
}
|
||||
NEIClientConfig.logger
|
||||
.info(String.format("Removed catalyst `%s` from handler %s", itemStack.getDisplayName(), handlerID));
|
||||
.info("Removed catalyst '{}' from catalyst handler {}", itemStack.getDisplayName(), catalystHandlerID);
|
||||
}
|
||||
|
||||
private static void logInvalidMessage(FMLInterModComms.IMCMessage message, String type) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import codechicken.nei.recipe.IRecipeHandler;
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Event is posted every time the handler infos got registered or reloaded. During it, you can safely register your
|
||||
* Event is posted every time the handler infos get registered or reloaded. During it, you can safely register your
|
||||
* custom handler info.
|
||||
*
|
||||
* <br>
|
||||
@@ -21,9 +21,15 @@ import cpw.mods.fml.common.eventhandler.Event;
|
||||
*/
|
||||
public class NEIRegisterHandlerInfosEvent extends Event {
|
||||
|
||||
public void registerHandlerInfo(String handlerName, String modName, String modId,
|
||||
/**
|
||||
* @param handlerID handler identifier as returned by {@link IRecipeHandler#getHandlerId}
|
||||
* @param modName display name of the mod to which the recipe handler belongs
|
||||
* @param modId modId of the mod for which the recipe handler is responsible
|
||||
* @param builder
|
||||
*/
|
||||
public void registerHandlerInfo(String handlerID, String modName, String modId,
|
||||
Consumer<HandlerInfo.Builder> builder) {
|
||||
HandlerInfo.Builder b = new HandlerInfo.Builder(handlerName, modName, modId);
|
||||
HandlerInfo.Builder b = new HandlerInfo.Builder(handlerID, modName, modId);
|
||||
builder.accept(b);
|
||||
HandlerInfo info = b.build();
|
||||
if (GuiRecipeTab.handlerMap.put(info.getHandlerName(), info) != null) {
|
||||
|
||||
@@ -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();
|
||||
@@ -116,6 +122,11 @@ 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}
|
||||
@@ -157,11 +168,27 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
}
|
||||
|
||||
@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 +225,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 +269,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 +451,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();
|
||||
}
|
||||
@@ -552,11 +570,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 +610,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 +647,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 +678,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 +690,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 +712,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 +752,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 +763,9 @@ 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()));
|
||||
return new Point(
|
||||
5,
|
||||
32 - (limitToOneRecipe ? 25 : 0) + yShift + ((recipe % getRecipesPerPage()) * handlerInfo.getHeight()));
|
||||
}
|
||||
|
||||
public abstract ArrayList<H> getCurrentRecipeHandlers();
|
||||
|
||||
@@ -203,13 +203,13 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
if (fromJar) {
|
||||
url = handlerUrl;
|
||||
if (url == null) {
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers csv.");
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers.csv");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
File handlerFile = NEIClientConfig.handlerFile;
|
||||
if (!handlerFile.exists()) {
|
||||
NEIClientConfig.logger.info("Config file doesn't exist, creating");
|
||||
NEIClientConfig.logger.info("Config file handler.csv doesn't exist, initializing");
|
||||
try {
|
||||
assert handlerUrl != null;
|
||||
ReadableByteChannel readableByteChannel = Channels.newChannel(handlerUrl.openStream());
|
||||
@@ -224,15 +224,24 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
try {
|
||||
url = NEIClientConfig.handlerFile.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers csv (via config).");
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers.csv (via config)");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
||||
CSVParser csvParser = CSVFormat.EXCEL.withFirstRecordAsHeader().parse(reader);
|
||||
if (csvParser.getHeaderNames().contains("handler")) {
|
||||
NEIClientConfig.logger.warn("Found column 'handler' in catalysts.csv. Please rename to 'handlerID'");
|
||||
}
|
||||
for (CSVRecord record : csvParser) {
|
||||
final String handler = record.get("handler");
|
||||
final String handlerID;
|
||||
if (record.isMapped("handler")) {
|
||||
handlerID = record.get("handler");
|
||||
} else {
|
||||
handlerID = record.get("handlerID");
|
||||
}
|
||||
|
||||
final String modName = record.get("modName");
|
||||
final String modId = record.get("modId");
|
||||
final boolean requiresMod = Boolean.parseBoolean(record.get("modRequired"));
|
||||
@@ -241,7 +250,7 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
if (requiresMod && !Loader.isModLoaded(modId)) continue;
|
||||
if (excludedModId != null && Loader.isModLoaded(excludedModId)) continue;
|
||||
|
||||
HandlerInfo info = new HandlerInfo(handler, modName, modId, requiresMod, excludedModId);
|
||||
HandlerInfo info = new HandlerInfo(handlerID, modName, modId, requiresMod, excludedModId);
|
||||
final String imageResource = record.get("imageResource");
|
||||
if (imageResource != null && !imageResource.equals("")) {
|
||||
info.setImage(
|
||||
@@ -268,14 +277,14 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
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 " + handlerID);
|
||||
}
|
||||
|
||||
handlerMap.put(handler, info);
|
||||
NEIClientConfig.logger.info("Loaded " + handler);
|
||||
handlerMap.put(handlerID, info);
|
||||
NEIClientConfig.logger.info("Loaded " + handlerID);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.info("Error parsing CSV");
|
||||
NEIClientConfig.logger.error("Error parsing handlers.csv");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -287,10 +296,12 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
Set<String> handlerIds = new HashSet<>(handlerMap.keySet());
|
||||
handlerAdderFromIMC.keySet().forEach(handlerName -> {
|
||||
if (!handlerIds.contains(handlerName)) {
|
||||
NEIClientConfig.logger.warn("Could not find a registered handlerID that matches " + handlerName);
|
||||
NEIClientConfig.logger.warn(
|
||||
"Could not find a registered handlerID that matches '{}' as received via IMC",
|
||||
handlerName);
|
||||
handlerIds.forEach(handler -> {
|
||||
if (handler.equalsIgnoreCase(handlerName)) {
|
||||
NEIClientConfig.logger.warn(" -- Did you mean: " + handler);
|
||||
NEIClientConfig.logger.warn(" -- Did you mean: {}", handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public interface IRecipeHandler {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The name of this inventory. To be displayed at the top of the viewing container.
|
||||
* @return The display name of this handler. To be displayed at the top of the viewing container.
|
||||
*/
|
||||
String getRecipeName();
|
||||
|
||||
|
||||
@@ -42,17 +42,17 @@ public class RecipeCatalysts {
|
||||
private static final List<String> forceClassNameList = new ArrayList<>();
|
||||
private static int heightCache;
|
||||
|
||||
public static void addRecipeCatalyst(String handlerID, CatalystInfo catalystInfo) {
|
||||
if (handlerID == null || handlerID.isEmpty() || catalystInfo.getStack() == null) return;
|
||||
addOrPut(catalystsAdderFromAPI, handlerID, catalystInfo);
|
||||
public static void addRecipeCatalyst(String catalystHandlerID, CatalystInfo catalystInfo) {
|
||||
if (catalystHandlerID == null || catalystHandlerID.isEmpty() || catalystInfo.getStack() == null) return;
|
||||
addOrPut(catalystsAdderFromAPI, catalystHandlerID, catalystInfo);
|
||||
}
|
||||
|
||||
public static void removeRecipeCatalyst(String handlerID, ItemStack stack) {
|
||||
if (handlerID == null || handlerID.isEmpty() || stack == null) return;
|
||||
if (catalystsRemoverFromAPI.containsKey(handlerID)) {
|
||||
catalystsRemoverFromAPI.get(handlerID).add(stack);
|
||||
public static void removeRecipeCatalyst(String catalystHandlerID, ItemStack stack) {
|
||||
if (catalystHandlerID == null || catalystHandlerID.isEmpty() || stack == null) return;
|
||||
if (catalystsRemoverFromAPI.containsKey(catalystHandlerID)) {
|
||||
catalystsRemoverFromAPI.get(catalystHandlerID).add(stack);
|
||||
} else {
|
||||
catalystsRemoverFromAPI.put(handlerID, new ArrayList<>(Collections.singletonList(stack)));
|
||||
catalystsRemoverFromAPI.put(catalystHandlerID, new ArrayList<>(Collections.singletonList(stack)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,23 +61,23 @@ public class RecipeCatalysts {
|
||||
}
|
||||
|
||||
public static List<PositionedStack> getRecipeCatalysts(IRecipeHandler handler) {
|
||||
return getRecipeCatalysts(getRecipeID(handler));
|
||||
return getRecipeCatalysts(getCatalystHandlerId(handler));
|
||||
}
|
||||
|
||||
public static List<PositionedStack> getRecipeCatalysts(String handlerID) {
|
||||
public static List<PositionedStack> getRecipeCatalysts(String catalystHandlerID) {
|
||||
if (!NEIClientConfig.areJEIStyleTabsVisible() || !NEIClientConfig.areJEIStyleRecipeCatalystsVisible()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return positionedRecipeCatalystMap.getOrDefault(handlerID, Collections.emptyList());
|
||||
return positionedRecipeCatalystMap.getOrDefault(catalystHandlerID, Collections.emptyList());
|
||||
}
|
||||
|
||||
public static boolean containsCatalyst(IRecipeHandler handler, ItemStack candidate) {
|
||||
return containsCatalyst(getRecipeID(handler), candidate);
|
||||
return containsCatalyst(getCatalystHandlerId(handler), candidate);
|
||||
}
|
||||
|
||||
public static boolean containsCatalyst(String handlerID, ItemStack candidate) {
|
||||
if (recipeCatalystMap.containsKey(handlerID)) {
|
||||
return recipeCatalystMap.get(handlerID).contains(candidate);
|
||||
public static boolean containsCatalyst(String catalystHandlerID, ItemStack candidate) {
|
||||
if (recipeCatalystMap.containsKey(catalystHandlerID)) {
|
||||
return recipeCatalystMap.get(catalystHandlerID).contains(candidate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public class RecipeCatalysts {
|
||||
|
||||
public static void loadCatalystInfo() {
|
||||
final boolean fromJar = NEIClientConfig.loadCatalystsFromJar();
|
||||
NEIClientConfig.logger.info("Loading catalyst info from " + (fromJar ? "JAR" : "Config"));
|
||||
NEIClientConfig.logger.info("Loading catalyst info from {}", (fromJar ? "JAR" : "Config"));
|
||||
recipeCatalystMap.clear();
|
||||
URL handlerUrl = RecipeCatalysts.class.getResource("/assets/nei/csv/catalysts.csv");
|
||||
|
||||
@@ -157,15 +157,24 @@ public class RecipeCatalysts {
|
||||
try {
|
||||
url = NEIClientConfig.catalystFile.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
NEIClientConfig.logger.warn("Invalid URL for catalysts csv (via config).");
|
||||
NEIClientConfig.logger.warn("Invalid URL for catalysts.csv (via config).");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
||||
CSVParser csvParser = CSVFormat.EXCEL.withFirstRecordAsHeader().parse(reader);
|
||||
if (csvParser.getHeaderNames().contains("handlerID")) {
|
||||
NEIClientConfig.logger
|
||||
.warn("Found column 'handlerID' in catalysts.csv. Please rename to 'catalystHandlerID'");
|
||||
}
|
||||
for (CSVRecord record : csvParser) {
|
||||
final String handler = record.get("handler");
|
||||
final String catalystHandlerID;
|
||||
if (record.isMapped("handlerID")) {
|
||||
catalystHandlerID = record.get("handlerID");
|
||||
} else {
|
||||
catalystHandlerID = record.get("catalystHandlerID");
|
||||
}
|
||||
final String modId = record.get("modId");
|
||||
final boolean requiresMod = Boolean.parseBoolean(record.get("modRequired"));
|
||||
final String excludedModId = record.get("excludedModId");
|
||||
@@ -191,41 +200,41 @@ public class RecipeCatalysts {
|
||||
String handlerID;
|
||||
try {
|
||||
// gently handling copy&paste from handlers.csv
|
||||
Class<?> clazz = Class.forName(handler);
|
||||
Class<?> clazz = Class.forName(catalystHandlerID);
|
||||
Object object = clazz.newInstance();
|
||||
if (object instanceof IRecipeHandler) {
|
||||
if (forceClassName) {
|
||||
forceClassNameList.add(handler);
|
||||
forceClassNameList.add(catalystHandlerID);
|
||||
}
|
||||
handlerID = getRecipeID((IRecipeHandler) object);
|
||||
handlerID = getCatalystHandlerId((IRecipeHandler) object);
|
||||
} else {
|
||||
handlerID = handler;
|
||||
handlerID = catalystHandlerID;
|
||||
}
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
handlerID = handler;
|
||||
handlerID = catalystHandlerID;
|
||||
} catch (InstantiationException ignored) {
|
||||
NEIClientConfig.logger.warn("failed to create instance for " + handler);
|
||||
handlerID = handler;
|
||||
NEIClientConfig.logger.warn("failed to create instance for " + catalystHandlerID);
|
||||
handlerID = catalystHandlerID;
|
||||
}
|
||||
|
||||
addOrPut(recipeCatalystMap, handlerID, catalystInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.warn("Error parsing CSV");
|
||||
NEIClientConfig.logger.warn("Error parsing catalysts.csv");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, CatalystInfoList> entry : catalystsAdderFromAPI.entrySet()) {
|
||||
String handlerID = entry.getKey();
|
||||
String catalystHandlerID = entry.getKey();
|
||||
for (CatalystInfo catalyst : entry.getValue()) {
|
||||
addOrPut(recipeCatalystMap, handlerID, catalyst);
|
||||
addOrPut(recipeCatalystMap, catalystHandlerID, catalyst);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, CatalystInfoList> entry : catalystsAdderFromIMC.entrySet()) {
|
||||
String handlerID = entry.getKey();
|
||||
String catalystHandlerID = entry.getKey();
|
||||
for (CatalystInfo catalyst : entry.getValue()) {
|
||||
addOrPut(recipeCatalystMap, handlerID, catalyst);
|
||||
addOrPut(recipeCatalystMap, catalystHandlerID, catalyst);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,27 +243,29 @@ public class RecipeCatalysts {
|
||||
Set<String> handlerIds = new HashSet<>(GuiRecipeTab.handlerMap.keySet());
|
||||
catalystsAdderFromIMC.keySet().forEach(handlerName -> {
|
||||
if (!handlerIds.contains(handlerName)) {
|
||||
NEIClientConfig.logger.warn("Could not find a registered handlerID that matches " + handlerName);
|
||||
NEIClientConfig.logger.warn(
|
||||
"Could not find a registered catalystHandlerID that matches '{}' as received via IMC",
|
||||
handlerName);
|
||||
handlerIds.forEach(handler -> {
|
||||
if (handler.equalsIgnoreCase(handlerName)) {
|
||||
NEIClientConfig.logger.warn(" -- Did you mean: " + handler);
|
||||
NEIClientConfig.logger.warn(" -- Did you mean: {}", handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
for (Map.Entry<String, List<ItemStack>> entry : catalystsRemoverFromAPI.entrySet()) {
|
||||
String handlerID = entry.getKey();
|
||||
if (recipeCatalystMap.containsKey(handlerID)) {
|
||||
CatalystInfoList catalysts = recipeCatalystMap.get(handlerID);
|
||||
String catalystHandlerID = entry.getKey();
|
||||
if (recipeCatalystMap.containsKey(catalystHandlerID)) {
|
||||
CatalystInfoList catalysts = recipeCatalystMap.get(catalystHandlerID);
|
||||
entry.getValue().forEach(catalysts::remove);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, List<ItemStack>> entry : catalystsRemoverFromIMC.entrySet()) {
|
||||
String handlerID = entry.getKey();
|
||||
if (recipeCatalystMap.containsKey(handlerID)) {
|
||||
CatalystInfoList catalysts = recipeCatalystMap.get(handlerID);
|
||||
String catalystHandlerID = entry.getKey();
|
||||
if (recipeCatalystMap.containsKey(catalystHandlerID)) {
|
||||
CatalystInfoList catalysts = recipeCatalystMap.get(catalystHandlerID);
|
||||
entry.getValue().forEach(catalysts::remove);
|
||||
}
|
||||
}
|
||||
@@ -263,22 +274,24 @@ public class RecipeCatalysts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Basically {@link NEIClientConfig#HANDLER_ID_FUNCTION}. Force using {@link IRecipeHandler#getHandlerId()} if
|
||||
* specified in catalysts.csv. In other words, refuse to share handlerID defined in
|
||||
* {@link TemplateRecipeHandler#getOverlayIdentifier()}.
|
||||
* Computes the catalyst handler identifier for matching a catalyst to its corresponding recipes.
|
||||
*
|
||||
* @return defaults to {@link IRecipeHandler#getOverlayIdentifier()}, but falls back to the results of
|
||||
* {@link IRecipeHandler#getHandlerId()} if the former is null. If forceClassName is enabled in
|
||||
* catalysts.csv, {@link IRecipeHandler#getHandlerId()} is returned always.
|
||||
*/
|
||||
public static String getRecipeID(IRecipeHandler handler) {
|
||||
public static String getCatalystHandlerId(IRecipeHandler handler) {
|
||||
if (forceClassNameList.stream().anyMatch(s -> s.equals(handler.getHandlerId()))) {
|
||||
return handler.getHandlerId();
|
||||
}
|
||||
return Objects.firstNonNull(handler.getOverlayIdentifier(), handler.getHandlerId());
|
||||
}
|
||||
|
||||
public static void addOrPut(Map<String, CatalystInfoList> map, String handlerID, CatalystInfo catalyst) {
|
||||
if (map.containsKey(handlerID)) {
|
||||
map.get(handlerID).add(catalyst);
|
||||
public static void addOrPut(Map<String, CatalystInfoList> map, String catalystHandlerID, CatalystInfo catalyst) {
|
||||
if (map.containsKey(catalystHandlerID)) {
|
||||
map.get(catalystHandlerID).add(catalyst);
|
||||
} else {
|
||||
map.put(handlerID, new CatalystInfoList(handlerID, catalyst));
|
||||
map.put(catalystHandlerID, new CatalystInfoList(catalystHandlerID, catalyst));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
handler,itemName,nbtInfo,modId,modRequired,excludedModId,priority,minVersion,maxVersion,forceClassName,itemNotes
|
||||
catalystHandlerID,itemName,nbtInfo,modId,modRequired,excludedModId,priority,minVersion,maxVersion,forceClassName,itemNotes
|
||||
crafting,minecraft:crafting_table,,minecraft,FALSE,terrafirmacraftplus,100,,,,
|
||||
smelting,minecraft:furnace,,minecraft,FALSE,terrafirmacraftplus,100,,,,
|
||||
codechicken.nei.recipe.BrewingRecipeHandler,minecraft:brewing_stand,,minecraft,FALSE,terrafirmacraftplus,100,,,,
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
handler,modName,itemName,nbtInfo,modId,modRequired,excludedModId,yShift,handlerHeight,handlerWidth,maxRecipesPerPage,imageResource,imageX,imageY,imageWidth,imageHeight,itemNotes
|
||||
handlerID,modName,itemName,nbtInfo,modId,modRequired,excludedModId,yShift,handlerHeight,handlerWidth,maxRecipesPerPage,imageResource,imageX,imageY,imageWidth,imageHeight,itemNotes
|
||||
codechicken.nei.recipe.BrewingRecipeHandler,Minecraft,minecraft:brewing_stand,,minecraft,FALSE,,,65,166,5,,,,,,
|
||||
codechicken.nei.recipe.FireworkRecipeHandler,Minecraft,minecraft:fireworks,,minecraft,FALSE,,,65,166,5,,,,,,
|
||||
codechicken.nei.recipe.FurnaceRecipeHandler,Minecraft,minecraft:furnace,,minecraft,FALSE,,,65,166,5,,,,,,
|
||||
|
||||
|
@@ -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
|
||||
Reference in new issue
Block a user