mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-11-15 01:34:42 +00:00
Compare commits
48
Commits
2.8.157-GTNH
...
mu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da55c3b12c | ||
|
|
ebe83f970f | ||
|
|
ad9beb7f90 | ||
|
|
68bdb51c6b | ||
|
|
e4e1964dec | ||
|
|
560618024f | ||
|
|
e2a2d2a9df | ||
|
|
7163630cb1 | ||
|
|
ab168ad6ba | ||
|
|
e13e3483f0 | ||
|
|
de26547b64 | ||
|
|
c49f8808fd | ||
|
|
1c6cc8b693 | ||
|
|
9f74331116 | ||
|
|
43ae1b613a | ||
|
|
cdac4cc4a8 | ||
|
|
402c4325a6 | ||
|
|
550e85c456 | ||
|
|
1673079cbb | ||
|
|
9958dd45ff | ||
|
|
a25879aaad | ||
|
|
d8c5870a91 | ||
|
|
e6174c446a | ||
|
|
869b4571b0 | ||
|
|
96260fe68b | ||
|
|
35f5400ecb | ||
|
|
1e2801c891 | ||
|
|
f44536d2e8 | ||
|
|
fa8342cfed | ||
|
|
82ddc4da41 | ||
|
|
3d1d2f79e5 | ||
|
|
867651ecab | ||
|
|
0674aae0ec | ||
|
|
5277fd36f5 | ||
|
|
b6b31eca33 | ||
|
|
0dbeae9f68 | ||
|
|
f0547b5ca6 | ||
|
|
e7a252a0de | ||
|
|
442118d2e4 | ||
|
|
972d0e4f3c | ||
|
|
bffef55cb8 | ||
|
|
e1d19e0bfc | ||
|
|
b0c5f6fcda | ||
|
|
953638be05 | ||
|
|
e53d728baf | ||
|
|
58b63671ce | ||
|
|
a1631b0f58 | ||
|
|
eafd9ff4a3 |
No files matched your search
@@ -33,12 +33,10 @@ body:
|
||||
description: What Java version are you using? It's worth mentioning that if you play on Java9+ you should try update to latest minor release (e.g. prefer Java 17.0.6 over 17.0.2) of that version.
|
||||
options:
|
||||
- Java 8
|
||||
- Java 9
|
||||
- Java 11
|
||||
- Java 17
|
||||
- Java 19
|
||||
- Java 20
|
||||
- Java 21
|
||||
- java 25
|
||||
- java 26
|
||||
- Other (Please Specify)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
+5
-4
@@ -5,13 +5,14 @@ configurations.create('gtnhlibEmbed') {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.21:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.11.49:dev')
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.22:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.11.54:dev')
|
||||
|
||||
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
|
||||
|
||||
compileOnly('maven.modrinth:forge-essentials:7.5.1')
|
||||
compileOnly('com.cardinalstar.cubicchunks:CubicChunks1710:v0.1.14-alpha:dev')
|
||||
compileOnly('com.ruling_0:MaterialLib:0.24.0-mu:dev')
|
||||
|
||||
antlr('org.antlr:antlr4:4.13.2')
|
||||
shadowImplementation('org.antlr:antlr4-runtime:4.13.2')
|
||||
@@ -23,8 +24,8 @@ dependencies {
|
||||
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
|
||||
testRuntimeOnly("org.lwjgl.lwjgl:lwjgl:2.9.3");
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:GTNHLib:0.11.49") { transitive = false }
|
||||
gtnhlibEmbed("com.github.GTNewHorizons:GTNHLib:0.11.49") { transitive = false }
|
||||
compileOnly("com.github.GTNewHorizons:GTNHLib:0.11.54") { transitive = false }
|
||||
gtnhlibEmbed("com.github.GTNewHorizons:GTNHLib:0.11.54") { transitive = false }
|
||||
}
|
||||
|
||||
def embedArchiveOperations = gtnhGradle.archiveOperations
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Add any additional repositories for your dependencies here
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven {
|
||||
name = "Modrinth"
|
||||
url = "https://api.modrinth.com/maven"
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.31'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.34'
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -574,7 +574,8 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
|
||||
} else if (this.sortableGroup != null) {
|
||||
final int overRowIndex = Math.min(grid.getRowIndex(mousey), grid.getRows() - 1);
|
||||
|
||||
if (overRowIndex >= 0 && this.sortableGroup.groupId != this.grid.getRowGroupId(overRowIndex)) {
|
||||
if (overRowIndex >= 0 && !isOverNamespaceControls(mousex, mousey)
|
||||
&& !this.sortableGroup.matches(this.grid, this.grid.getRowGroupId(overRowIndex))) {
|
||||
this.grid.moveGroup(this.sortableGroup, overRowIndex);
|
||||
}
|
||||
|
||||
@@ -1022,14 +1023,18 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
|
||||
this.mouseDownSlot = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int shift, int mousex, int mousey) {
|
||||
|
||||
if ((!inEditingState() || this.sortableGroup != null) && new Rectangle4i(
|
||||
private boolean isOverNamespaceControls(int mousex, int mousey) {
|
||||
return new Rectangle4i(
|
||||
namespacePrev.x,
|
||||
namespacePrev.y,
|
||||
namespaceNext.x + namespaceNext.w - namespacePrev.x,
|
||||
namespacePrev.h).contains(mousex, mousey)) {
|
||||
namespacePrev.h).contains(mousex, mousey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int shift, int mousex, int mousey) {
|
||||
|
||||
if ((!inEditingState() || this.sortableGroup != null) && isOverNamespaceControls(mousex, mousey)) {
|
||||
|
||||
if (shift > 0) {
|
||||
this.storage.prevNamespace();
|
||||
@@ -1108,7 +1113,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
|
||||
final int overRowIndex = Math.min(grid.getRowIndex(mousey), grid.getRows() - 1);
|
||||
|
||||
if (this.sortableGroup != null && overRowIndex >= 0
|
||||
&& this.sortableGroup.groupId != this.grid.getRowGroupId(overRowIndex)) {
|
||||
&& !this.sortableGroup.matches(this.grid, this.grid.getRowGroupId(overRowIndex))) {
|
||||
this.grid.moveGroup(this.sortableGroup, overRowIndex);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,40 +7,36 @@ import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
|
||||
public class GuiNEIButton extends GuiButton {
|
||||
|
||||
protected static final ResourceLocation guiTex = new ResourceLocation("textures/gui/widgets.png");
|
||||
private static final DrawableResource[] BACKGROUNDS = new DrawableResource[3];
|
||||
|
||||
static {
|
||||
for (int state = 0; state < BACKGROUNDS.length; state++) {
|
||||
BACKGROUNDS[state] = new DrawableBuilder(guiTex, 0, 46 + state * 20, 200, 20).setSlices(2, 2, 2, 2).build();
|
||||
}
|
||||
}
|
||||
|
||||
public GuiNEIButton(int i, int j, int k, int l, int i1, String s) {
|
||||
super(i, j, k, l, i1, s);
|
||||
}
|
||||
|
||||
protected DrawableResource getBackground(int mouseX, int mouseY, boolean mouseOver) {
|
||||
return BACKGROUNDS[getHoverState(mouseOver)];
|
||||
}
|
||||
|
||||
public void drawButton(Minecraft minecraft, int x, int y) {
|
||||
if (!visible) return;
|
||||
|
||||
minecraft.renderEngine.bindTexture(guiTex);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
boolean mouseOver = x >= xPosition && y >= yPosition && x < xPosition + width && y < yPosition + height;
|
||||
int k = getHoverState(mouseOver);
|
||||
drawTexturedModalRect(xPosition, yPosition, 0, 46 + k * 20, width / 2, height / 2); // top left
|
||||
drawTexturedModalRect(xPosition + width / 2, yPosition, 200 - width / 2, 46 + k * 20, width / 2, height / 2); // top
|
||||
// right
|
||||
drawTexturedModalRect(
|
||||
xPosition,
|
||||
yPosition + height / 2,
|
||||
0,
|
||||
46 + k * 20 + 20 - height / 2,
|
||||
width / 2,
|
||||
height / 2); // bottom left
|
||||
drawTexturedModalRect(
|
||||
xPosition + width / 2,
|
||||
yPosition + height / 2,
|
||||
200 - width / 2,
|
||||
46 + k * 20 + 20 - height / 2,
|
||||
width / 2,
|
||||
height / 2); // bottom right
|
||||
mouseDragged(minecraft, x, y);
|
||||
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
getBackground(x, y, mouseOver).draw(xPosition, yPosition, width, height);
|
||||
mouseDragged(minecraft, x, y);
|
||||
drawContent(minecraft, x, y, mouseOver);
|
||||
}
|
||||
|
||||
@@ -55,7 +51,7 @@ public class GuiNEIButton extends GuiButton {
|
||||
return ColorUtils.buttonLabelNormal.getColor();
|
||||
}
|
||||
|
||||
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
|
||||
protected void drawContent(Minecraft minecraft, int x, int y, boolean mouseOver) {
|
||||
FontRenderer fontrenderer = minecraft.fontRenderer;
|
||||
int color = getTextColour(mouseOver);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.regex.Pattern;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
@@ -103,7 +104,7 @@ public class ItemList {
|
||||
}
|
||||
|
||||
for (String alias : ItemInfo.getAliases(item)) {
|
||||
if (this.pattern.matcher(alias).find()) {
|
||||
if (this.pattern.matcher(StatCollector.translateToLocal(alias)).find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,13 +75,7 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
|
||||
}
|
||||
|
||||
public static void updateItemList(ArrayList<ItemStack> newItems) {
|
||||
final ItemsPanelGrid grid = ItemPanels.itemPanel.getGrid();
|
||||
|
||||
if (grid.rawItems.size() != newItems.size()) {
|
||||
grid.setPage(0);
|
||||
}
|
||||
|
||||
grid.setItems(newItems);
|
||||
ItemPanels.itemPanel.getGrid().setItems(newItems);
|
||||
ItemPanels.itemPanel.realItems = newItems;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,8 +111,14 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
this.xPosition = (availableAreaWidth - this.scale * SLOT_SIZE) / 2;
|
||||
this.availableAreaWidth = (int) (availableAreaWidth / screenScale);
|
||||
|
||||
if (availableAreaWidth / screenScale >= mouse.x) {
|
||||
this.xPosition += gui.width * screenScale - availableAreaWidth;
|
||||
final float rightSideShift = gui.width * screenScale - availableAreaWidth;
|
||||
final boolean leftSideFree = availableAreaWidth / screenScale < mouse.x;
|
||||
final boolean rightSideFree = mouse.x < gui.width - availableAreaWidth / screenScale;
|
||||
|
||||
final boolean showOnRight = leftSideFree && rightSideFree ? !preferLeftSide() : !leftSideFree;
|
||||
|
||||
if (showOnRight) {
|
||||
this.xPosition += rightSideShift;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -128,6 +134,22 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean preferLeftSide() {
|
||||
switch (NEIClientConfig.getIntSetting("inventory.itemzoom.preferredSide")) {
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
return false;
|
||||
}
|
||||
|
||||
final int leftCount = NEIClientConfig.isBookmarkPanelHidden()
|
||||
|| ItemPanels.bookmarkPanel.getGrid().getPerPage() == 0 ? 0 : ItemPanels.bookmarkPanel.getGrid().size();
|
||||
final int rightCount = ItemPanels.itemPanel.getGrid().getPerPage() == 0 ? 0
|
||||
: ItemPanels.itemPanel.getGrid().size();
|
||||
|
||||
return leftCount <= rightCount;
|
||||
}
|
||||
|
||||
private float getPointSize(GuiContainer gui) {
|
||||
final float screenScale = 1.0f / getScreenScale();
|
||||
final float availableAreaWidth = (gui.width - (gui.xSize + gui.width) / 2) * screenScale;
|
||||
|
||||
@@ -89,6 +89,10 @@ public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot,
|
||||
public void refresh(GuiContainer gui) {
|
||||
|
||||
if (this.newItems != null) {
|
||||
if (this.rawItems.size() != this.newItems.size()) {
|
||||
this.page = 0;
|
||||
}
|
||||
|
||||
this.groupItems.clear();
|
||||
this.itemToGroup.clear();
|
||||
this.forceExpand = false;
|
||||
|
||||
@@ -167,7 +167,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
protected int activeStackIndex = -1;
|
||||
protected Dimension size = new Dimension();
|
||||
|
||||
protected final boolean showNames;
|
||||
protected int maxNamedRows = Integer.MAX_VALUE;
|
||||
|
||||
protected int length = 0;
|
||||
protected int rows = 0;
|
||||
@@ -175,29 +175,25 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
protected int gridColumns = 0;
|
||||
protected int gridCount = 0;
|
||||
|
||||
public static ItemsTooltipLineHandler grid(String label, List<ItemStack> items, int maxRows) {
|
||||
return new ItemsTooltipLineHandler(label, items, true, maxRows, false);
|
||||
}
|
||||
|
||||
public static ItemsTooltipLineHandler list(String label, List<ItemStack> items, int maxRows) {
|
||||
return new ItemsTooltipLineHandler(label, items, true, maxRows, true);
|
||||
public static ItemsTooltipLineHandler of(String label, List<ItemStack> items, int maxRows, int maxNamedRows) {
|
||||
return new ItemsTooltipLineHandler(label, items, true, maxRows, maxNamedRows);
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items) {
|
||||
this(label, items, true, DEFAULT_MAX_ROWS, false);
|
||||
this(label, items, true, DEFAULT_MAX_ROWS, 0);
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize, int maxRows) {
|
||||
this(label, items, saveStackSize, maxRows, false);
|
||||
this(label, items, saveStackSize, maxRows, 0);
|
||||
}
|
||||
|
||||
protected ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize, int maxRows,
|
||||
boolean showNames) {
|
||||
int maxNamedRows) {
|
||||
this.label = label;
|
||||
this.items = groupingItemStacks(items);
|
||||
this.amountRenderer = saveStackSize ? new TotalAmountRenderer() : new NoAmountRenderer();
|
||||
this.length = this.items.size();
|
||||
this.showNames = showNames;
|
||||
this.maxNamedRows = maxNamedRows;
|
||||
|
||||
setMaxRows(maxRows);
|
||||
}
|
||||
@@ -214,7 +210,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
this.names.clear();
|
||||
this.nameRows = 0;
|
||||
|
||||
if (!this.showNames || !layoutWithNames(maxRows)) {
|
||||
if (!layoutWithNames(maxRows)) {
|
||||
layoutAsGrid(maxRows);
|
||||
}
|
||||
|
||||
@@ -228,7 +224,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
}
|
||||
|
||||
protected boolean layoutWithNames(int maxRows) {
|
||||
final int maxNames = this.length <= maxRows ? this.length : maxRows - 1;
|
||||
final int maxNames = Math.min(this.maxNamedRows, this.length <= maxRows ? this.length : maxRows - 1);
|
||||
final int[] lineWidth = new int[maxNames + 1];
|
||||
lineWidth[0] = labelWidth();
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ public class NEICPH implements IClientPacketHandler {
|
||||
case S2C.CACHE_BOOKMARK_DATA:
|
||||
handleCacheBookmarkData(packet);
|
||||
break;
|
||||
case S2C.SYNC:
|
||||
ServerSync.onReply(packet.readInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +200,11 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.bookmarks.showRecipeMarkerMode").setComment("Show Recipe Marker").getIntValue(0);
|
||||
API.addOption(new OptionCycled("inventory.bookmarks.showRecipeMarkerMode", 3, true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.maxVerticalTooltipRows")
|
||||
.setComment("Max rows in vertical crafting chain tooltip lists (0 - disable, always use grid)")
|
||||
.getIntValue(12);
|
||||
API.addOption(new OptionIntegerField("inventory.bookmarks.maxVerticalTooltipRows", 0, 50));
|
||||
|
||||
tag.getTag("inventory.bookmarks.recipeMarkerColor").setComment("Color of the icon marker")
|
||||
.getHexValue(0xADADAD);
|
||||
API.addOption(
|
||||
@@ -267,6 +272,11 @@ public class NEIClientConfig {
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.scrollPages", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.freezeCycleOnHover")
|
||||
.setComment("Stop cycling the recipe while hovering over an ingredient or a button")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.freezeCycleOnHover", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
|
||||
|
||||
@@ -372,6 +382,11 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.itemzoom.onlySolid").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.itemzoom.onlySolid", true));
|
||||
|
||||
tag.getTag("inventory.itemzoom.preferredSide")
|
||||
.setComment("Which side to prefer showing the zoomed item on, when both sides are free.")
|
||||
.getIntValue(0);
|
||||
API.addOption(new OptionCycled("inventory.itemzoom.preferredSide", 3, true));
|
||||
|
||||
tag.getTag("inventory.itemzoom.helpText")
|
||||
.setComment("Display name \"Item Zoom\" and the hotkey to toggle this mod below the zoomed item.")
|
||||
.getBooleanValue(true);
|
||||
@@ -1106,6 +1121,10 @@ public class NEIClientConfig {
|
||||
return getIntSetting("inventory.bookmarks.showRecipeMarkerMode");
|
||||
}
|
||||
|
||||
public static int getMaxVerticalTooltipRows() {
|
||||
return getIntSetting("inventory.bookmarks.maxVerticalTooltipRows");
|
||||
}
|
||||
|
||||
public static boolean showItemQuantityWidget() {
|
||||
return getBooleanSetting("inventory.showItemQuantityWidget");
|
||||
}
|
||||
@@ -1166,6 +1185,10 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
|
||||
}
|
||||
|
||||
public static boolean freezeCycleOnHover() {
|
||||
return getBooleanSetting("inventory.guirecipe.freezeCycleOnHover");
|
||||
}
|
||||
|
||||
public static boolean requireShiftForOverlayRecipe() {
|
||||
return getBooleanSetting("inventory.guirecipe.shiftOverlayRecipe");
|
||||
}
|
||||
|
||||
@@ -14,11 +14,13 @@ import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.IConfigureNEI;
|
||||
import codechicken.nei.asm.NEICorePlugin;
|
||||
import codechicken.nei.config.IMCHandler;
|
||||
import codechicken.nei.guihook.HideousLinkedList;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.stackinfo.MaterialLibStackStringifyHandler;
|
||||
import cpw.mods.fml.client.FMLFileResourcePack;
|
||||
import cpw.mods.fml.client.FMLFolderResourcePack;
|
||||
import cpw.mods.fml.common.DummyModContainer;
|
||||
@@ -114,6 +116,10 @@ public class NEIModContainer extends DummyModContainer {
|
||||
IMCForNEI.IMCSender();
|
||||
}
|
||||
ServerHandler.load();
|
||||
|
||||
if (Loader.isModLoaded("materiallib")) {
|
||||
API.registerStackStringifyHandler(new MaterialLibStackStringifyHandler());
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
||||
@@ -92,9 +92,17 @@ public class NEISPH implements IServerPacketHandler {
|
||||
case C2S.SEND_CHAT_ITEM_LINK:
|
||||
handleSendChatItemLink(sender, packet);
|
||||
break;
|
||||
case C2S.SYNC:
|
||||
handleSync(sender, packet.readInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSync(EntityPlayerMP sender, int id) {
|
||||
sender.sendContainerAndContentsToPlayer(sender.openContainer, sender.openContainer.getInventory());
|
||||
new PacketCustom(channel, S2C.SYNC).writeInt(id).sendToPlayer(sender);
|
||||
}
|
||||
|
||||
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
|
||||
final NBTTagCompound payloadTag = packet.readNBTTagCompound();
|
||||
NEIServerUtils.sendChatItemLink(sender, payloadTag);
|
||||
|
||||
@@ -24,6 +24,7 @@ public final class PacketIDs {
|
||||
public static final int REQUEST_POTION_GUI = 24;
|
||||
public static final int SET_DUMMY_SLOT = 25;
|
||||
public static final int SEND_CHAT_ITEM_LINK = 26;
|
||||
public static final int SYNC = 27;
|
||||
}
|
||||
|
||||
public static final class S2C {
|
||||
@@ -38,5 +39,6 @@ public final class PacketIDs {
|
||||
public static final int SET_CREATIVE_PLUS_MODE = 23;
|
||||
public static final int OPEN_POTION_GUI = 24;
|
||||
public static final int CACHE_BOOKMARK_DATA = 25;
|
||||
public static final int SYNC = 26;
|
||||
}
|
||||
}
|
||||
@@ -445,7 +445,7 @@ public class SearchTokenParser {
|
||||
final char ch = input.charAt(index);
|
||||
|
||||
if (!insideQuotes && delimiters.indexOf(ch) >= 0
|
||||
&& (!space || index == 0 || input.charAt(index - 1) == ' ')) {
|
||||
&& (!space || index == 0 || input.charAt(index - 1) == ' ' || lastEnd == index)) {
|
||||
|
||||
if (lastEnd == index) {
|
||||
token += String.valueOf(ch);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.nei.PacketIDs.C2S;
|
||||
|
||||
/**
|
||||
* Waits until the server has processed everything the client sent before. The server handles slot clicks and NEI
|
||||
* packets in the order they came and answers after it has sent the slot updates, so once the answer is here the client
|
||||
* container holds what the server computed.
|
||||
*/
|
||||
public final class ServerSync {
|
||||
|
||||
private static int lastId;
|
||||
private static volatile int awaiting;
|
||||
|
||||
private ServerSync() {}
|
||||
|
||||
public static void request() {
|
||||
|
||||
if (!NEIClientConfig.hasSMPCounterPart()) {
|
||||
awaiting = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
awaiting = ++lastId;
|
||||
new PacketCustom(NEICPH.channel, C2S.SYNC).writeInt(awaiting).sendToServer();
|
||||
}
|
||||
|
||||
public static boolean pending() {
|
||||
return awaiting != 0;
|
||||
}
|
||||
|
||||
static void onReply(int id) {
|
||||
if (id == awaiting) awaiting = 0;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -541,14 +542,22 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
final AtomicInteger resolved = new AtomicInteger();
|
||||
final AtomicInteger invalid = new AtomicInteger();
|
||||
|
||||
Stream.of(dir.listFiles()).filter(file -> !file.isDirectory()).forEach(file -> {
|
||||
ClientHandler.loadSettingsFile(
|
||||
"subsets/" + file.getName(),
|
||||
lines -> parseFile(file.getName(), lines.collect(Collectors.toList())));
|
||||
lines -> parseFile(file.getName(), lines.collect(Collectors.toList()), resolved, invalid));
|
||||
});
|
||||
|
||||
if (resolved.get() + invalid.get() > 0) {
|
||||
NEIClientConfig.logger.info("Resolved {} MaterialLib entries ({} invalid)", resolved.get(), invalid.get());
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseFile(String resource, List<String> itemStrings) {
|
||||
private static void parseFile(String resource, List<String> itemStrings, AtomicInteger resolved,
|
||||
AtomicInteger invalid) {
|
||||
final JsonParser parser = new JsonParser();
|
||||
final int dotIndex = resource.lastIndexOf('.');
|
||||
final String subsetNamespace = dotIndex > 0 ? resource.substring(0, dotIndex) : resource;
|
||||
@@ -578,7 +587,13 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
|
||||
final NBTBase nbt = NBTJson.toNbt(parser.parse(itemStr));
|
||||
|
||||
if (nbt instanceof NBTTagCompound tag) {
|
||||
((ItemStackSet) processedTag.filter).add(StackInfo.loadFromNBT(tag));
|
||||
final ItemStack stack = StackInfo.loadFromNBT(tag);
|
||||
|
||||
if (tag.getString("strId").startsWith(StackInfo.MATERIALLIB_PREFIX)) {
|
||||
(stack != null ? resolved : invalid).incrementAndGet();
|
||||
}
|
||||
|
||||
((ItemStackSet) processedTag.filter).add(stack);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Expected NBTTagCompound but got " + nbt.getClass().getSimpleName());
|
||||
|
||||
@@ -180,6 +180,8 @@ public class API {
|
||||
|
||||
/**
|
||||
* Add an alias name that this item can be found by in the search field, in addition to its display name.
|
||||
*
|
||||
* @param aliases translation keys, localized at search time
|
||||
*/
|
||||
public static void setAliases(ItemStack item, String... aliases) {
|
||||
final List<String> list = Arrays.asList(aliases).stream().filter(Objects::nonNull).map(String::trim)
|
||||
|
||||
@@ -19,7 +19,6 @@ import codechicken.nei.BookmarkContainerInfo;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemQuantityField;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.KeyManager;
|
||||
import codechicken.nei.LayoutManager;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
@@ -38,6 +37,7 @@ import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiFavoriteButton;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
import codechicken.nei.recipe.HoveredRecipe;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
@@ -415,41 +415,37 @@ public abstract class ShortcutInputHandler {
|
||||
|
||||
private static Recipe getFocusedRecipe(ItemStack stackover, int mousex, int mousey, boolean useFavorites) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
Recipe recipe = null;
|
||||
|
||||
if (useFavorites) {
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
final RecipeId recipeId = itemSlot.getRecipeId();
|
||||
|
||||
if (recipeId != null && (recipe = Recipe.of(recipeId)) != null) {
|
||||
|
||||
recipe.getIngredients().stream().forEach(ingr -> {
|
||||
final List<ItemStack> permutations = ingr.getPermutations();
|
||||
for (int index = 0; index < permutations.size(); index++) {
|
||||
if (FavoriteRecipes.contains(permutations.get(index))) {
|
||||
ingr.setActiveIndex(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return focusedRecipe;
|
||||
}
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
recipe = guiRecipe.getFocusedRecipe();
|
||||
if (!useFavorites) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, stackover);
|
||||
|
||||
if (hovered == null || hovered.source != HoveredRecipe.Source.ITEM_PANEL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Recipe recipe = Recipe.of(hovered.recipeId);
|
||||
|
||||
if (recipe != null) {
|
||||
recipe.getIngredients().stream().forEach(ingr -> {
|
||||
final List<ItemStack> permutations = ingr.getPermutations();
|
||||
for (int index = 0; index < permutations.size(); index++) {
|
||||
if (FavoriteRecipes.contains(permutations.get(index))) {
|
||||
ingr.setActiveIndex(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return recipe;
|
||||
@@ -529,7 +525,9 @@ public abstract class ShortcutInputHandler {
|
||||
}
|
||||
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
|
||||
final RecipeId recipeId = getHotkeyRecipeId(gui, mousex, mousey, stack, slot);
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, stack);
|
||||
final RecipeId recipeId = hovered == null || hovered.source == HoveredRecipe.Source.OTHER
|
||||
|| hovered.source == HoveredRecipe.Source.BOOKMARK && hovered.favorite ? null : hovered.recipeId;
|
||||
|
||||
if (slot != null) {
|
||||
final BookmarkGroup group = slot.getGroup();
|
||||
@@ -729,36 +727,4 @@ public abstract class ShortcutInputHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
|
||||
BookmarksGridSlot slot) {
|
||||
|
||||
if (slot != null) {
|
||||
return slot.getType() == BookmarkItemType.INGREDIENT ? null : slot.getRecipeId();
|
||||
}
|
||||
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
return itemSlot.getRecipeId();
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return focusedRecipe.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import static org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
||||
import static org.objectweb.asm.Opcodes.IRETURN;
|
||||
import static org.objectweb.asm.Opcodes.NEW;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -22,11 +23,14 @@ import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
import codechicken.lib.asm.ASMBlock;
|
||||
@@ -98,6 +102,48 @@ public class NEITransformer implements IClassTransformer {
|
||||
}
|
||||
});
|
||||
|
||||
if (Boolean.getBoolean("nei.recipeOrigins")) {
|
||||
// Replace the plain ArrayList CraftingManager's constructor builds its recipe list with, so every recipe
|
||||
// added anywhere (including vanilla's own, added in that same constructor) is observed for
|
||||
// codechicken.nei.recipe.debug.RecipeOrigins. Must be done at classload time, since by the time any mod
|
||||
// code runs vanilla has already populated the list. Capturing a stack trace per recipe is slow, so this is
|
||||
// opt-in via -Dnei.recipeOrigins=true.
|
||||
transformer.add(
|
||||
new MethodTransformer(
|
||||
new ObfMapping("net/minecraft/item/crafting/CraftingManager", "<init>", "()V")) {
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
ASMHelper.logger.debug("NEI: Hooking CraftingManager recipe list for origin tracking");
|
||||
|
||||
TypeInsnNode newInsn = null;
|
||||
MethodInsnNode initInsn = null;
|
||||
|
||||
// only the first ArrayList construction, the recipe list field
|
||||
for (AbstractInsnNode insn : mv.instructions.toArray()) {
|
||||
if (newInsn == null) {
|
||||
if (insn.getOpcode() == NEW
|
||||
&& "java/util/ArrayList".equals(((TypeInsnNode) insn).desc)) {
|
||||
newInsn = (TypeInsnNode) insn;
|
||||
}
|
||||
} else if (insn.getOpcode() == INVOKESPECIAL
|
||||
&& "java/util/ArrayList".equals(((MethodInsnNode) insn).owner)
|
||||
&& "<init>".equals(((MethodInsnNode) insn).name)) {
|
||||
initInsn = (MethodInsnNode) insn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newInsn == null || initInsn == null) {
|
||||
ASMHelper.logger.warn("NEI: CraftingManager recipe list not found, origins disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
newInsn.desc = initInsn.owner = "codechicken/nei/recipe/debug/RecipeOrigins$TrackingList";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// put glint alpha into the buffer correctly for exporting
|
||||
transformer.add(
|
||||
new MethodReplacer(
|
||||
|
||||
@@ -452,8 +452,9 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
if (!this.isEmpty() && this.gridGenerator.maxAbsoluteSlotIndex > 0) {
|
||||
final GroupingItem groupingItem = ItemPanels.bookmarkPanel.groupingItem;
|
||||
final int sortableGroupId = ItemPanels.bookmarkPanel.sortableGroup != null
|
||||
? ItemPanels.bookmarkPanel.sortableGroup.groupId
|
||||
: -3;
|
||||
&& ItemPanels.bookmarkPanel.sortableGroup.grid == this
|
||||
? ItemPanels.bookmarkPanel.sortableGroup.groupId
|
||||
: -3;
|
||||
final int rowShift = this.page * this.rows;
|
||||
Map<Integer, Integer> groups = this.gridGenerator.rowToGroupId;
|
||||
|
||||
@@ -795,8 +796,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
this.bookmarkItems.add(item);
|
||||
}
|
||||
|
||||
sortableGroup.grid = this;
|
||||
sortableGroup.groupId = groupId;
|
||||
sortableGroup.update(this, groupId);
|
||||
this.onItemsChanged();
|
||||
this.getMask();// force generate grid
|
||||
overGroupId = getRowGroupId(overRowIndex);
|
||||
@@ -1285,7 +1285,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
for (BookmarksGridSlot slot : getMask()) {
|
||||
Rectangle4i rect = getSlotRect(slot.slotIndex);
|
||||
|
||||
if (sortableGroup != null && slot.getGroupId() == sortableGroup.groupId) {
|
||||
if (sortableGroup != null && sortableGroup.matches(this, slot.getGroupId())) {
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, DRAG_COLOR);
|
||||
} else if (sortableItem != null && sortableItem.items.contains(slot.itemIndex)) {
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, DRAG_COLOR);
|
||||
@@ -1314,7 +1314,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
final SortableItem sortableItem = LayoutManager.bookmarkPanel.sortableItem;
|
||||
|
||||
for (BookmarksGridSlot slot : getMask()) {
|
||||
if ((sortableGroup == null || slot.getGroupId() != sortableGroup.groupId)
|
||||
if ((sortableGroup == null || !sortableGroup.matches(this, slot.getGroupId()))
|
||||
&& (sortableItem == null || !sortableItem.items.contains(slot.itemIndex))) {
|
||||
slot.afterDraw(getSlotRect(slot.slotIndex), mouseContext);
|
||||
}
|
||||
@@ -1331,7 +1331,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
|
||||
|
||||
for (BookmarksGridSlot slot : getMask()) {
|
||||
|
||||
if ((sortableGroup == null || slot.getGroupId() != sortableGroup.groupId)
|
||||
if ((sortableGroup == null || !sortableGroup.matches(this, slot.getGroupId()))
|
||||
&& (sortableItem == null || !sortableItem.items.contains(slot.itemIndex))) {
|
||||
final BookmarkItem item = slot.getBookmarkItem();
|
||||
|
||||
|
||||
@@ -340,7 +340,8 @@ public class BookmarkGridGenerator {
|
||||
0,
|
||||
chainItem.getItem(),
|
||||
null,
|
||||
group);
|
||||
group,
|
||||
this.grid);
|
||||
} else {
|
||||
return new BookmarksGridSlot(
|
||||
slotIndex,
|
||||
@@ -350,7 +351,8 @@ public class BookmarkGridGenerator {
|
||||
chainItem.getCalculatedMultiplier(),
|
||||
chainItem.getItem(),
|
||||
chainItem.calculatedType,
|
||||
group);
|
||||
group,
|
||||
this.grid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
@@ -79,10 +80,21 @@ public class BookmarkStorage {
|
||||
|
||||
public int getNamespaceSize() {
|
||||
|
||||
if (this.namespaces.get(this.namespaces.size() - 1).size() > 0) {
|
||||
this.namespaces.add(new BookmarkGrid());
|
||||
} else if (this.activeNamespaceIndex == this.namespaces.size() - 2 && getActiveGrid().size() == 0) {
|
||||
this.namespaces.remove(this.namespaces.size() - 1);
|
||||
final int lastIndex = this.namespaces.size() - 1;
|
||||
final BookmarkGrid lastGrid = this.namespaces.get(lastIndex);
|
||||
final SortableGroup sortableGroup = ItemPanels.bookmarkPanel.sortableGroup;
|
||||
|
||||
if (lastGrid.size() > 0) {
|
||||
if (sortableGroup == null || sortableGroup.grid != lastGrid || !sortableGroup.aloneInGrid) {
|
||||
this.namespaces.add(new BookmarkGrid());
|
||||
}
|
||||
} else if (lastIndex > 0 && this.activeNamespaceIndex != lastIndex) {
|
||||
final BookmarkGrid prevGrid = this.namespaces.get(lastIndex - 1);
|
||||
|
||||
if (sortableGroup != null && sortableGroup.grid == prevGrid && sortableGroup.aloneInGrid
|
||||
|| prevGrid == getActiveGrid() && prevGrid.size() == 0) {
|
||||
this.namespaces.remove(lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return this.namespaces.size();
|
||||
@@ -198,6 +210,11 @@ public class BookmarkStorage {
|
||||
final BookmarkItem item = BookmarkItem.of(parser.parse(itemStr).getAsJsonObject());
|
||||
|
||||
if (item != null) {
|
||||
|
||||
if (!grid.groups.containsKey(item.groupId)) {
|
||||
item.groupId = BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
}
|
||||
|
||||
grid.addItem(item, false);
|
||||
} else {
|
||||
wasError = true;
|
||||
|
||||
@@ -8,7 +8,6 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.ItemsGrid.MouseContext;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
@@ -65,7 +64,8 @@ public class BookmarksGridSlot extends ItemsGridSlot {
|
||||
protected final int rowIndex;
|
||||
|
||||
public BookmarksGridSlot(int slotIndex, int itemIndex, long realMultiplier, long shiftAmount,
|
||||
long calculatedMultiplier, BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
|
||||
long calculatedMultiplier, BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group,
|
||||
BookmarkGrid grid) {
|
||||
super(
|
||||
slotIndex,
|
||||
itemIndex,
|
||||
@@ -96,7 +96,6 @@ public class BookmarksGridSlot extends ItemsGridSlot {
|
||||
: CalculatedType.RESULT;
|
||||
}
|
||||
|
||||
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
|
||||
final BookmarkItem prevItem = grid.getCalculatedItem(
|
||||
grid.gridGenerator.slotToItem.getOrDefault(grid.gridGenerator.itemToSlot.get(this.itemIndex) - 1, -1));
|
||||
this.isFirstOutput = this.itemIndex >= 0 && this.bookmarkItem.type == BookmarkItemType.RESULT
|
||||
|
||||
@@ -13,13 +13,23 @@ public class SortableGroup {
|
||||
|
||||
public int groupId;
|
||||
public BookmarkGrid grid;
|
||||
public boolean aloneInGrid;
|
||||
|
||||
public int shiftX = 0;
|
||||
public int shiftY = 0;
|
||||
|
||||
public SortableGroup(BookmarkGrid grid, int groupId) {
|
||||
update(grid, groupId);
|
||||
}
|
||||
|
||||
public void update(BookmarkGrid grid, int groupId) {
|
||||
this.grid = grid;
|
||||
this.groupId = groupId;
|
||||
this.aloneInGrid = grid.bookmarkItems.stream().allMatch(item -> item.groupId == groupId);
|
||||
}
|
||||
|
||||
public boolean matches(BookmarkGrid grid, int groupId) {
|
||||
return this.grid == grid && this.groupId == groupId;
|
||||
}
|
||||
|
||||
public void postDraw(int mousex, int mousey) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package codechicken.nei.bookmark.tree;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
class Camera {
|
||||
|
||||
private static final float ZOOM_MIN = 0.1f;
|
||||
@@ -39,23 +41,34 @@ class Camera {
|
||||
&& y < this.widgetY + this.widgetH;
|
||||
}
|
||||
|
||||
public void startDrag(int mouseX, int mouseY) {
|
||||
public void startDrag(Point2D mouse) {
|
||||
this.dragging = true;
|
||||
this.lastDragX = mouseX;
|
||||
this.lastDragY = mouseY;
|
||||
this.lastDragX = (float) mouse.getX();
|
||||
this.lastDragY = (float) mouse.getY();
|
||||
}
|
||||
|
||||
public void drag(int mouseX, int mouseY) {
|
||||
public void drag(Point2D mouse) {
|
||||
if (!this.dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
final float mouseX = (float) mouse.getX();
|
||||
final float mouseY = (float) mouse.getY();
|
||||
|
||||
this.scrollX -= (mouseX - this.lastDragX) / this.zoomLevel;
|
||||
this.scrollY -= (mouseY - this.lastDragY) / this.zoomLevel;
|
||||
this.lastDragX = mouseX;
|
||||
this.lastDragY = mouseY;
|
||||
}
|
||||
|
||||
public void update(Point2D mouse, int treeWidth, int treeHeight) {
|
||||
if (this.dragging && Mouse.isButtonDown(0)) {
|
||||
drag(mouse);
|
||||
}
|
||||
|
||||
clampToBounds(treeWidth, treeHeight);
|
||||
}
|
||||
|
||||
public void endDrag() {
|
||||
this.dragging = false;
|
||||
}
|
||||
@@ -79,7 +92,6 @@ class Camera {
|
||||
} else {
|
||||
this.scrollY -= direction * this.widgetH / (SCROLL_STEP_DIVISOR * this.zoomLevel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void centerOn(float worldX, float worldY) {
|
||||
|
||||
@@ -169,12 +169,12 @@ class CraftingTreeCanvas {
|
||||
: -FIT_MARGIN;
|
||||
}
|
||||
|
||||
public void startDrag(int mouseX, int mouseY) {
|
||||
this.camera.startDrag(mouseX, mouseY);
|
||||
public void startDrag(Point2D mouse) {
|
||||
this.camera.startDrag(mouse);
|
||||
}
|
||||
|
||||
public void drag(int mouseX, int mouseY) {
|
||||
this.camera.drag(mouseX, mouseY);
|
||||
public void drag(Point2D mouse) {
|
||||
this.camera.drag(mouse);
|
||||
}
|
||||
|
||||
public void endDrag() {
|
||||
@@ -259,7 +259,7 @@ class CraftingTreeCanvas {
|
||||
|
||||
public void draw(Point2D mouse, Set<BookmarkItem> collapsedItems, SearchResult searchResult,
|
||||
boolean useInventorySnapshot, ItemTreeSlot hoveredNode, ItemTreeSlot deleteHoverNode) {
|
||||
this.camera.clampToBounds(this.treeWidth, this.treeHeight);
|
||||
this.camera.update(mouse, this.treeWidth, this.treeHeight);
|
||||
|
||||
final float zScrollX = this.camera.scrollX * this.camera.zoomLevel;
|
||||
final float zScrollY = this.camera.scrollY * this.camera.zoomLevel;
|
||||
|
||||
@@ -102,20 +102,20 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MARGIN = 4;
|
||||
private static final int PADDING = 9;
|
||||
private static final int PADDING_TOP = 22;
|
||||
|
||||
private static final DrawableResource BG_TEXTURE = new DrawableBuilder(
|
||||
"nei:textures/gui/craftingtree.png",
|
||||
0,
|
||||
0,
|
||||
64,
|
||||
64).build();
|
||||
64).setSlices(PADDING, PADDING, PADDING_TOP, PADDING).build();
|
||||
|
||||
private static final DateTimeFormatter SCREENSHOT_DATE_FORMAT = DateTimeFormatter
|
||||
.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT);
|
||||
|
||||
private static final int MARGIN = 4;
|
||||
private static final int PADDING = 9;
|
||||
private static final int PADDING_TOP = 22;
|
||||
|
||||
private final LRUCache<String, String> handlerTitleCache = new LRUCache<>(100);
|
||||
|
||||
private GuiScreen prevGui;
|
||||
@@ -162,7 +162,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
final ItemTreeSlot replaceNode = this.uiState.replaceRecipeNode;
|
||||
this.uiState.replaceRecipeNode = null;
|
||||
|
||||
if (recipe != null) {
|
||||
if (recipe != null && this.grid.getGroup(this.groupId) != null) {
|
||||
final RecipeId recipeId = recipe.getRecipeId();
|
||||
boolean changed = false;
|
||||
|
||||
@@ -190,6 +190,13 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
|
||||
// the group can be removed from the bookmark panel while a recipe screen opened from this tree is shown
|
||||
if (this.grid.getGroup(this.groupId) == null) {
|
||||
this.mc.displayGuiScreen(this.prevGui);
|
||||
return;
|
||||
}
|
||||
|
||||
this.xSize = this.width;
|
||||
this.ySize = this.height;
|
||||
|
||||
@@ -331,15 +338,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
this.hoveredNode = canHover && hoveredBadgeHandler == null ? this.canvas.getNodeMouseOver(getMousePosition())
|
||||
: null;
|
||||
|
||||
BG_TEXTURE.draw(
|
||||
MARGIN,
|
||||
MARGIN,
|
||||
this.width - MARGIN * 2,
|
||||
this.height - MARGIN * 2,
|
||||
PADDING,
|
||||
PADDING,
|
||||
PADDING_TOP,
|
||||
PADDING);
|
||||
BG_TEXTURE.draw(MARGIN, MARGIN, this.width - MARGIN * 2, this.height - MARGIN * 2);
|
||||
|
||||
if (this.math.outputRecipes.isEmpty()) {
|
||||
drawCenteredString(
|
||||
@@ -758,7 +757,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
return true;
|
||||
}
|
||||
|
||||
this.canvas.startDrag(mouseX, mouseY);
|
||||
this.canvas.startDrag(getMousePosition());
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -779,7 +778,7 @@ public class GuiCraftingTree extends GuiContainer implements INEIGuiHandler, IGu
|
||||
|
||||
}
|
||||
|
||||
this.canvas.drag(mouseX, mouseY);
|
||||
this.canvas.drag(getMousePosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -242,7 +242,7 @@ class StatsPanel extends ScrollContainer {
|
||||
26,
|
||||
84,
|
||||
46,
|
||||
16).build();
|
||||
16).setSlices(0, 0, 2, 0).build();
|
||||
|
||||
private static final DrawableResource SLOT_DEFAULT = new DrawableBuilder(
|
||||
"nei:textures/gui/craftingtree.png",
|
||||
@@ -290,8 +290,8 @@ class StatsPanel extends ScrollContainer {
|
||||
|
||||
public StatsPanel() {
|
||||
final ScrollBar scrollbar = new ScrollBar().setTrackWidth(4)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 100, 24, 4).build(), 0, 0)
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 104, 24, 4).build(), 0, 0)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 100, 24, 4).build())
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/gui/craftingtree.png", 26, 104, 24, 4).build())
|
||||
.setTrackPadding(1, -5, 1, 0).setOverflowType(ScrollBar.OverflowType.AUTO);
|
||||
|
||||
setHorizontalScroll(scrollbar);
|
||||
@@ -589,7 +589,7 @@ class StatsPanel extends ScrollContainer {
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
|
||||
BG_TEXTURE.draw(this.x, this.y, this.w, this.h, 0, 0, 2, 0);
|
||||
BG_TEXTURE.draw(this.x, this.y, this.w, this.h);
|
||||
|
||||
super.draw(mouseX, mouseY);
|
||||
|
||||
|
||||
@@ -74,7 +74,11 @@ public class IMCHandler {
|
||||
tag.getInteger("imageX"),
|
||||
tag.getInteger("imageY"),
|
||||
tag.getInteger("imageWidth"),
|
||||
tag.getInteger("imageHeight"));
|
||||
tag.getInteger("imageHeight"),
|
||||
tag.hasKey("imageTextureWidth") ? tag.getInteger("imageTextureWidth")
|
||||
: HandlerInfo.DEFAULT_IMAGE_TEXTURE_SIZE,
|
||||
tag.hasKey("imageTextureHeight") ? tag.getInteger("imageTextureHeight")
|
||||
: HandlerInfo.DEFAULT_IMAGE_TEXTURE_SIZE);
|
||||
}
|
||||
if (!info.hasImageOrItem()) {
|
||||
final String itemName = tag.getString("itemName");
|
||||
|
||||
@@ -15,13 +15,21 @@ public class DrawableBuilder {
|
||||
private int paddingBottom = 0;
|
||||
private int paddingLeft = 0;
|
||||
private int paddingRight = 0;
|
||||
private int sliceLeft = 0;
|
||||
private int sliceRight = 0;
|
||||
private int sliceTop = 0;
|
||||
private int sliceBottom = 0;
|
||||
|
||||
public DrawableBuilder(String resourceLocation, int u, int v, int width, int height) {
|
||||
this(new ResourceLocation(resourceLocation), u, v, width, height);
|
||||
}
|
||||
|
||||
public DrawableBuilder(ResourceLocation resource, int u, int v, int width, int height) {
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.resourceLocation = new ResourceLocation(resourceLocation);
|
||||
this.resourceLocation = resource;
|
||||
}
|
||||
|
||||
public DrawableBuilder setTextureSize(int width, int height) {
|
||||
@@ -38,6 +46,14 @@ public class DrawableBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public DrawableBuilder setSlices(int sliceLeft, int sliceRight, int sliceTop, int sliceBottom) {
|
||||
this.sliceLeft = sliceLeft;
|
||||
this.sliceRight = sliceRight;
|
||||
this.sliceTop = sliceTop;
|
||||
this.sliceBottom = sliceBottom;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DrawableBuilder trim(int trimTop, int trimBottom, int trimLeft, int trimRight) {
|
||||
this.u += trimLeft;
|
||||
this.v += trimTop;
|
||||
@@ -58,6 +74,10 @@ public class DrawableBuilder {
|
||||
paddingLeft,
|
||||
paddingRight,
|
||||
textureWidth,
|
||||
textureHeight);
|
||||
textureHeight,
|
||||
sliceLeft,
|
||||
sliceRight,
|
||||
sliceTop,
|
||||
sliceBottom);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package codechicken.nei.drawable;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -19,9 +19,42 @@ public class DrawableResource extends Image {
|
||||
private final int paddingLeft;
|
||||
private final int paddingRight;
|
||||
|
||||
private final int sliceLeft;
|
||||
private final int sliceRight;
|
||||
private final int sliceTop;
|
||||
private final int sliceBottom;
|
||||
|
||||
public DrawableResource(ResourceLocation resourceLocation, int u, int v, int width, int height, int paddingTop,
|
||||
int paddingBottom, int paddingLeft, int paddingRight, int textureWidth, int textureHeight) {
|
||||
this(
|
||||
resourceLocation,
|
||||
u,
|
||||
v,
|
||||
width,
|
||||
height,
|
||||
paddingTop,
|
||||
paddingBottom,
|
||||
paddingLeft,
|
||||
paddingRight,
|
||||
textureWidth,
|
||||
textureHeight,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
// negative padding lets the texture overflow the box it is drawn into
|
||||
public DrawableResource(ResourceLocation resourceLocation, int u, int v, int width, int height, int paddingTop,
|
||||
int paddingBottom, int paddingLeft, int paddingRight, int textureWidth, int textureHeight, int sliceLeft,
|
||||
int sliceRight, int sliceTop, int sliceBottom) {
|
||||
super(u, v, width, height);
|
||||
|
||||
this.sliceLeft = sliceLeft;
|
||||
this.sliceRight = sliceRight;
|
||||
this.sliceTop = sliceTop;
|
||||
this.sliceBottom = sliceBottom;
|
||||
|
||||
this.resourceLocation = resourceLocation;
|
||||
this.textureWidth = textureWidth;
|
||||
this.textureHeight = textureHeight;
|
||||
@@ -40,6 +73,14 @@ public class DrawableResource extends Image {
|
||||
return height + paddingTop + paddingBottom;
|
||||
}
|
||||
|
||||
public int getTextureWidth() {
|
||||
return this.textureWidth;
|
||||
}
|
||||
|
||||
public int getTextureHeight() {
|
||||
return this.textureHeight;
|
||||
}
|
||||
|
||||
public void bindTexture() {
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(this.resourceLocation);
|
||||
}
|
||||
@@ -55,18 +96,28 @@ public class DrawableResource extends Image {
|
||||
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
bindTexture();
|
||||
drawModalRectWithCustomSizedTexture(xOffset + maskLeft, yOffset + maskTop, maskLeft, maskTop, width, height);
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.startDrawingQuads();
|
||||
addQuad(tessellator, xOffset + maskLeft, yOffset + maskTop, maskLeft, maskTop, width, height);
|
||||
tessellator.draw();
|
||||
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
public void draw(int xOffset, int yOffset, int width, int height, int sliceLeft, int sliceRight, int sliceTop,
|
||||
int sliceBottom) {
|
||||
final int textureWidth = getWidth();
|
||||
final int textureHeight = getHeight();
|
||||
final int middleWidth = textureWidth - sliceLeft - sliceRight;
|
||||
final int middleHeight = textureHeight - sliceTop - sliceBottom;
|
||||
final int tileWidth = width - sliceLeft - sliceRight;
|
||||
final int tileHeight = height - sliceTop - sliceBottom;
|
||||
public void draw(int xOffset, int yOffset, int width, int height) {
|
||||
|
||||
if (width == getWidth() && height == getHeight()) {
|
||||
draw(xOffset, yOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
final int sliceLeft = this.sliceLeft;
|
||||
final int sliceRight = this.sliceRight;
|
||||
final int sliceTop = this.sliceTop;
|
||||
final int sliceBottom = this.sliceBottom;
|
||||
final int middleWidth = this.width - sliceLeft - sliceRight;
|
||||
final int middleHeight = this.height - sliceTop - sliceBottom;
|
||||
final int tileWidth = width - this.paddingLeft - this.paddingRight - sliceLeft - sliceRight;
|
||||
final int tileHeight = height - this.paddingTop - this.paddingBottom - sliceTop - sliceBottom;
|
||||
|
||||
if (middleWidth > 0 && middleHeight > 0 && tileWidth > 0 && tileHeight > 0) {
|
||||
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
|
||||
@@ -78,14 +129,30 @@ public class DrawableResource extends Image {
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
bindTexture();
|
||||
|
||||
// middle parts
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.startDrawingQuads();
|
||||
|
||||
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
|
||||
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
|
||||
final int x = xOffset + sliceLeft + tileW * middleWidth;
|
||||
|
||||
// border top
|
||||
addQuad(tessellator, x, yOffset, sliceLeft, 0, tileWidthSize, sliceTop);
|
||||
// border bottom
|
||||
addQuad(
|
||||
tessellator,
|
||||
x,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft,
|
||||
sliceTop + middleHeight,
|
||||
tileWidthSize,
|
||||
sliceBottom);
|
||||
|
||||
// middle parts
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
addQuad(
|
||||
tessellator,
|
||||
x,
|
||||
yOffset + sliceTop + tileH * middleHeight,
|
||||
sliceLeft,
|
||||
@@ -95,114 +162,75 @@ public class DrawableResource extends Image {
|
||||
}
|
||||
}
|
||||
|
||||
// border top
|
||||
if (sliceTop > 0) {
|
||||
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
|
||||
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileW * middleWidth,
|
||||
yOffset,
|
||||
sliceLeft,
|
||||
0,
|
||||
tileWidthSize,
|
||||
sliceTop);
|
||||
}
|
||||
}
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
final int y = yOffset + sliceTop + tileH * middleHeight;
|
||||
|
||||
// border bottom
|
||||
if (sliceBottom > 0) {
|
||||
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
|
||||
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileW * middleWidth,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft,
|
||||
sliceTop + middleHeight,
|
||||
tileWidthSize,
|
||||
sliceBottom);
|
||||
}
|
||||
}
|
||||
|
||||
// border left
|
||||
if (sliceLeft > 0) {
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset,
|
||||
yOffset + sliceTop + tileH * middleHeight,
|
||||
0,
|
||||
sliceTop,
|
||||
sliceLeft,
|
||||
tileHeightSize);
|
||||
}
|
||||
}
|
||||
|
||||
// border right
|
||||
if (sliceRight > 0) {
|
||||
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
|
||||
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset + sliceTop + tileH * middleHeight,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop,
|
||||
sliceRight,
|
||||
tileHeightSize);
|
||||
}
|
||||
// border left
|
||||
addQuad(tessellator, xOffset, y, 0, sliceTop, sliceLeft, tileHeightSize);
|
||||
// border right
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
y,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop,
|
||||
sliceRight,
|
||||
tileHeightSize);
|
||||
}
|
||||
|
||||
// angle left-top
|
||||
if (sliceLeft > 0 && sliceTop > 0) {
|
||||
drawModalRectWithCustomSizedTexture(xOffset, yOffset, 0, 0, sliceLeft, sliceTop);
|
||||
}
|
||||
|
||||
addQuad(tessellator, xOffset, yOffset, 0, 0, sliceLeft, sliceTop);
|
||||
// angle right-top
|
||||
if (sliceRight > 0 && sliceTop > 0) {
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset,
|
||||
sliceLeft + middleWidth,
|
||||
0,
|
||||
sliceRight,
|
||||
sliceTop);
|
||||
}
|
||||
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset,
|
||||
sliceLeft + middleWidth,
|
||||
0,
|
||||
sliceRight,
|
||||
sliceTop);
|
||||
// angle left-bottom
|
||||
if (sliceLeft > 0 && sliceBottom > 0) {
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
0,
|
||||
sliceTop + middleHeight,
|
||||
sliceLeft,
|
||||
sliceBottom);
|
||||
}
|
||||
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
0,
|
||||
sliceTop + middleHeight,
|
||||
sliceLeft,
|
||||
sliceBottom);
|
||||
// angle right-bottom
|
||||
if (sliceRight > 0 && sliceBottom > 0) {
|
||||
drawModalRectWithCustomSizedTexture(
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop + middleHeight,
|
||||
sliceRight,
|
||||
sliceBottom);
|
||||
}
|
||||
addQuad(
|
||||
tessellator,
|
||||
xOffset + sliceLeft + tileWidth,
|
||||
yOffset + sliceTop + tileHeight,
|
||||
sliceLeft + middleWidth,
|
||||
sliceTop + middleHeight,
|
||||
sliceRight,
|
||||
sliceBottom);
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawModalRectWithCustomSizedTexture(int xOffset, int yOffset, int u, int v, int width, int height) {
|
||||
Gui.func_146110_a(
|
||||
xOffset + this.paddingLeft,
|
||||
yOffset + this.paddingTop,
|
||||
this.x + u,
|
||||
this.y + v,
|
||||
width,
|
||||
height,
|
||||
this.textureWidth,
|
||||
this.textureHeight);
|
||||
private void addQuad(Tessellator tessellator, int xOffset, int yOffset, int u, int v, int width, int height) {
|
||||
if (width <= 0 || height <= 0) return;
|
||||
|
||||
final float scaleU = 1.0F / this.textureWidth;
|
||||
final float scaleV = 1.0F / this.textureHeight;
|
||||
final int x = xOffset + this.paddingLeft;
|
||||
final int y = yOffset + this.paddingTop;
|
||||
final float u0 = (this.x + u) * scaleU;
|
||||
final float u1 = (this.x + u + width) * scaleU;
|
||||
final float v0 = (this.y + v) * scaleV;
|
||||
final float v1 = (this.y + v + height) * scaleV;
|
||||
|
||||
tessellator.addVertexWithUV(x, y + height, 0.0D, u0, v1);
|
||||
tessellator.addVertexWithUV(x + width, y + height, 0.0D, u1, v1);
|
||||
tessellator.addVertexWithUV(x + width, y, 0.0D, u1, v0);
|
||||
tessellator.addVertexWithUV(x, y, 0.0D, u0, v0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,13 +5,18 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.inventory.SlotCrafting;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.FastTransferManager;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemStackAmount;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.NEIServerUtils;
|
||||
import codechicken.nei.RestartableTask;
|
||||
import codechicken.nei.ServerSync;
|
||||
import codechicken.nei.bookmark.BookmarkItem;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.chain.RecipeChainIterator;
|
||||
@@ -26,6 +31,7 @@ public class AutoCraftingManager {
|
||||
@Override
|
||||
public void execute() {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
final ItemStack[] layout = snapshotLayout(guiContainer);
|
||||
final List<BookmarkItem> initialItems = prepareInitialItems(math, getInventoryItems(guiContainer));
|
||||
boolean processed = false;
|
||||
boolean changed = false;
|
||||
@@ -69,6 +75,11 @@ public class AutoCraftingManager {
|
||||
|
||||
} while (changed && !interrupted(guiContainer));
|
||||
|
||||
if (!interrupted(guiContainer)) {
|
||||
restoreLayout(guiContainer, layout);
|
||||
ServerSync.request();
|
||||
}
|
||||
|
||||
} finally {
|
||||
StackInfo.pauseItemDamageSound(false);
|
||||
}
|
||||
@@ -134,4 +145,70 @@ public class AutoCraftingManager {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
private static ItemStack[] snapshotLayout(GuiContainer guiContainer) {
|
||||
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
|
||||
final ItemStack[] layout = new ItemStack[slots.size()];
|
||||
|
||||
for (int index = 0; index < slots.size(); index++) {
|
||||
final Slot slot = slots.get(index);
|
||||
|
||||
if (slot.getHasStack() && !(slot instanceof SlotCrafting)) {
|
||||
layout[index] = slot.getStack().copy();
|
||||
}
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
private static void restoreLayout(GuiContainer guiContainer, ItemStack[] layout) {
|
||||
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
|
||||
final EntityPlayer player = guiContainer.mc.thePlayer;
|
||||
|
||||
for (int index = 0; index < slots.size() && player.inventory.getItemStack() == null
|
||||
&& guiContainer.mc.currentScreen == guiContainer; index++) {
|
||||
final ItemStack expected = layout[index];
|
||||
final Slot target = slots.get(index);
|
||||
|
||||
if (expected == null || inPlace(slots, layout, index)
|
||||
|| !target.isItemValid(expected)
|
||||
|| target.getHasStack() && !target.canTakeStack(player)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Slot source = findMisplaced(slots, layout, expected, player);
|
||||
if (source == null) continue;
|
||||
|
||||
FastTransferManager.clickSlot(guiContainer, source.slotNumber);
|
||||
FastTransferManager.clickSlot(guiContainer, target.slotNumber);
|
||||
|
||||
if (player.inventory.getItemStack() != null) {
|
||||
FastTransferManager.clickSlot(guiContainer, source.slotNumber);
|
||||
}
|
||||
}
|
||||
|
||||
FastTransferManager.dropHeldItem(guiContainer);
|
||||
}
|
||||
|
||||
private static boolean inPlace(List<Slot> slots, ItemStack[] layout, int index) {
|
||||
final ItemStack stack = slots.get(index).getStack();
|
||||
return stack != null && layout[index] != null
|
||||
&& NEIServerUtils.areStacksSameTypeCraftingWithNBT(layout[index], stack);
|
||||
}
|
||||
|
||||
private static Slot findMisplaced(List<Slot> slots, ItemStack[] layout, ItemStack expected, EntityPlayer player) {
|
||||
|
||||
for (int index = 0; index < slots.size(); index++) {
|
||||
final Slot slot = slots.get(index);
|
||||
|
||||
if (slot.getHasStack() && !(slot instanceof SlotCrafting)
|
||||
&& !inPlace(slots, layout, index)
|
||||
&& slot.canTakeStack(player)
|
||||
&& NEIServerUtils.areStacksSameTypeCraftingWithNBT(expected, slot.getStack())) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -20,10 +21,13 @@ import codechicken.lib.inventory.InventoryUtils;
|
||||
import codechicken.nei.FastTransferManager;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.ServerSync;
|
||||
import codechicken.nei.api.IOverlayHandler;
|
||||
|
||||
public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
|
||||
private static final long SYNC_TIMEOUT_MILLIS = 5000;
|
||||
|
||||
public static class DistributedIngred {
|
||||
|
||||
public DistributedIngred(ItemStack item) {
|
||||
@@ -113,7 +117,8 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
}
|
||||
|
||||
boolean craft = false;
|
||||
while (multiplier > 0) {
|
||||
while (multiplier > 0 && firstGui.mc.currentScreen == firstGui
|
||||
&& presenceOverlay(firstGui, handler, recipeIndex).stream().allMatch(s -> s.isPresent())) {
|
||||
final int transfer = transferRecipe(firstGui, handler, recipeIndex, multiplier);
|
||||
|
||||
if (transfer <= 0) {
|
||||
@@ -122,6 +127,10 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
|
||||
multiplier -= transfer;
|
||||
|
||||
if (!craftingSlot.getHasStack() && !awaitServer(firstGui)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (craftingSlot.getHasStack() && craftingSlot.canTakeStack(firstGui.mc.thePlayer)) {
|
||||
FastTransferManager.clickSlot(firstGui, craftingSlot.slotNumber, 0, 1);
|
||||
|
||||
@@ -139,9 +148,30 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
return craft;
|
||||
}
|
||||
|
||||
private boolean awaitServer(GuiContainer gui) {
|
||||
final long deadline = System.currentTimeMillis() + SYNC_TIMEOUT_MILLIS;
|
||||
ServerSync.request();
|
||||
|
||||
while (ServerSync.pending()) {
|
||||
if (gui.mc.currentScreen != gui || System.currentTimeMillis() > deadline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean clearIngredients(GuiContainer gui, IRecipeHandler handler) {
|
||||
|
||||
for (Slot slot : getCraftMatrixSlots(gui, handler)) {
|
||||
if (gui.mc.currentScreen != gui) return false;
|
||||
|
||||
if (slot.canTakeStack(gui.mc.thePlayer)) {
|
||||
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
|
||||
if (slot.getHasStack()) return false;
|
||||
@@ -206,7 +236,9 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
protected void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
|
||||
final Slot craftingSlot = getCraftingResultSlot(gui);
|
||||
|
||||
for (Slot slot : gui.inventorySlots.inventorySlots) {
|
||||
for (Slot slot : getSourceSlots(gui)) {
|
||||
if (gui.mc.currentScreen != gui) return;
|
||||
|
||||
if (slot == craftingSlot || !slot.getHasStack()
|
||||
|| !canMoveFrom(slot, gui)
|
||||
|| !slot.canTakeStack(gui.mc.thePlayer))
|
||||
@@ -240,6 +272,10 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
FastTransferManager.clickSlot(gui, slot.slotNumber);
|
||||
}
|
||||
|
||||
// A right click with an empty or foreign cursor would take half of the dest stack
|
||||
final ItemStack held = gui.mc.thePlayer.inventory.getItemStack();
|
||||
if (held == null || !canStack(distrib.permutation, held)) break;
|
||||
|
||||
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
|
||||
stackSize--;
|
||||
}
|
||||
@@ -370,7 +406,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
}
|
||||
|
||||
protected void findInventoryQuantities(GuiContainer gui, List<DistributedIngred> ingredStacks) {
|
||||
for (Slot slot : gui.inventorySlots.inventorySlots) /* work out how much we have to go round */ {
|
||||
for (Slot slot : getSourceSlots(gui)) /* work out how much we have to go round */ {
|
||||
if (slot.getHasStack() && canMoveFrom(slot, gui)) {
|
||||
final ItemStack pstack = slot.getStack();
|
||||
final DistributedIngred istack = findIngred(ingredStacks, pstack);
|
||||
@@ -408,6 +444,25 @@ public class DefaultOverlayHandler implements IOverlayHandler {
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Slot> getSourceSlots(GuiContainer gui) {
|
||||
final List<Slot> slots = new ArrayList<>(gui.inventorySlots.inventorySlots);
|
||||
slots.sort(Comparator.comparingLong(slot -> getRemainingDurability(slot.getStack())));
|
||||
return slots;
|
||||
}
|
||||
|
||||
private static long getRemainingDurability(ItemStack stack) {
|
||||
if (stack == null || stack.getMaxStackSize() != 1) return Long.MAX_VALUE;
|
||||
|
||||
final NBTTagCompound tagCompound = stack.getTagCompound();
|
||||
|
||||
if (tagCompound != null && tagCompound.hasKey("GT.ToolStats")) {
|
||||
final NBTTagCompound toolStats = tagCompound.getCompoundTag("GT.ToolStats");
|
||||
return toolStats.getLong("MaxDamage") - toolStats.getLong("Damage");
|
||||
}
|
||||
|
||||
return stack.isItemStackDamageable() ? stack.getMaxDamage() - stack.getItemDamage() : Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
private int getGTToolDamagePerContainerCraft(ItemStack aStack) {
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@@ -13,14 +12,9 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.BookmarksGridSlot;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
|
||||
@@ -138,39 +132,8 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
|
||||
}
|
||||
|
||||
public static RecipeId getRecipeId(GuiScreen gui, ItemStack stackover) {
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return focusedRecipe.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
final Point mouseover = GuiDraw.getMousePosition();
|
||||
final BookmarksGridSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (panelSlot != null) {
|
||||
return panelSlot.getType() == BookmarkItemType.INGREDIENT || panelSlot.getRecipeId() == null
|
||||
? FavoriteRecipes.getFavorite(stackover)
|
||||
: panelSlot.getRecipeId();
|
||||
}
|
||||
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
return itemSlot.getRecipeId();
|
||||
}
|
||||
|
||||
return null;
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, stackover);
|
||||
return hovered != null ? hovered.recipeId : null;
|
||||
}
|
||||
|
||||
private GuiCraftingRecipe(ArrayList<ICraftingHandler> handlers) {
|
||||
|
||||
@@ -177,12 +177,20 @@ public class GuiOverlayButton extends GuiRecipeButton {
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGrid"));
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(
|
||||
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH,
|
||||
NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGridOnce"));
|
||||
}
|
||||
|
||||
} else if (canFillCraftingGrid()) {
|
||||
hotkeys.put(
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGrid"));
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("recipe.overlay.fillCraftingGridOnce"));
|
||||
}
|
||||
|
||||
hotkeys.put(
|
||||
@@ -263,7 +271,7 @@ public class GuiOverlayButton extends GuiRecipeButton {
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
this.missedMaterialsTooltipLineHandler = ItemsTooltipLineHandler
|
||||
.grid(NEIClientUtils.translate("recipe.overlay.missing"), items, Integer.MAX_VALUE);
|
||||
.of(NEIClientUtils.translate("recipe.overlay.missing"), items, Integer.MAX_VALUE, 0);
|
||||
} else {
|
||||
this.missedMaterialsTooltipLineHandler = null;
|
||||
}
|
||||
@@ -329,7 +337,7 @@ public class GuiOverlayButton extends GuiRecipeButton {
|
||||
|
||||
if (!requireShiftForOverlayRecipe() || shift) {
|
||||
if (this.canFillCraftingGrid) {
|
||||
this.handlerRef.fillCraftingGrid(this.firstGui, 0);
|
||||
this.handlerRef.fillCraftingGrid(this.firstGui, NEIClientUtils.controlKey() ? 1 : 0);
|
||||
}
|
||||
} else if (hasOverlay() && useOverlayRenderer()) {
|
||||
this.handlerRef.useOverlayRenderer(this.firstGui);
|
||||
|
||||
@@ -71,15 +71,23 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
0,
|
||||
0,
|
||||
176 + TRANSPARENCY_BORDER * 2,
|
||||
166 + TRANSPARENCY_BORDER * 2).build();
|
||||
166 + TRANSPARENCY_BORDER * 2)
|
||||
.setSlices(
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER)
|
||||
.build();
|
||||
|
||||
private static final int BUTTON_WIDTH = 13;
|
||||
private static final int BUTTON_HEIGHT = 12;
|
||||
|
||||
protected static final ScrollBar VERTICAL_SCROLLBAR = new ScrollBar().setTrackWidth(14)
|
||||
.setOverflowType(OverflowType.AUTO).setScrollPlace(ScrollPlace.END)
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 42, 90, 13, 21).build(), 9, 9)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).build(), 3, 2)
|
||||
.setTrackTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 42, 90, 13, 21).setSlices(0, 0, 9, 9).build())
|
||||
.setThumbTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).setSlices(0, 0, 3, 2).build())
|
||||
.setThumbPadding(1, 6, 0, 6);
|
||||
|
||||
public static final List<IRecipeFilterProvider> recipeFilterers = new LinkedList<>();
|
||||
@@ -958,11 +966,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
this.guiLeft - TRANSPARENCY_BORDER,
|
||||
this.guiTop - TRANSPARENCY_BORDER,
|
||||
this.xSize + TRANSPARENCY_BORDER * 2,
|
||||
this.ySize + TRANSPARENCY_BORDER * 2,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER);
|
||||
this.ySize + TRANSPARENCY_BORDER * 2);
|
||||
|
||||
drawJEITabs(mouseX, mouseY);
|
||||
}
|
||||
|
||||
@@ -55,11 +55,17 @@ public class GuiRecipeCatalyst extends ScrollContainer {
|
||||
0,
|
||||
0,
|
||||
28 + TRANSPARENCY_BORDER * 2,
|
||||
28 + TRANSPARENCY_BORDER * 2).setTextureSize(28 + TRANSPARENCY_BORDER * 2, 28 + TRANSPARENCY_BORDER * 2)
|
||||
28 + TRANSPARENCY_BORDER * 2)
|
||||
.setTextureSize(28 + TRANSPARENCY_BORDER * 2, 28 + TRANSPARENCY_BORDER * 2)
|
||||
.setSlices(
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER)
|
||||
.build();
|
||||
|
||||
private static final DrawableResource FG_TEXTURE = new DrawableBuilder("nei:textures/slot.png", 0, 0, 18, 18)
|
||||
.setTextureSize(18, 18).build();
|
||||
.setTextureSize(18, 18).setSlices(1, 1, 1, 1).build();
|
||||
|
||||
private static final ScrollBar VERTICAL_SCROLLBAR = ScrollBar.defaultVerticalBar()
|
||||
.setOverflowType(ScrollBar.OverflowType.AUTO).setTrackPadding(0, BORDER_PADDING, -13, BORDER_PADDING)
|
||||
@@ -155,20 +161,12 @@ public class GuiRecipeCatalyst extends ScrollContainer {
|
||||
this.x - TRANSPARENCY_BORDER,
|
||||
this.y - TRANSPARENCY_BORDER,
|
||||
this.w + TRANSPARENCY_BORDER * 2,
|
||||
this.h + TRANSPARENCY_BORDER * 2,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER);
|
||||
this.h + TRANSPARENCY_BORDER * 2);
|
||||
FG_TEXTURE.draw(
|
||||
this.x + this.paddingInlineStart - 1,
|
||||
this.y + this.paddingBlockStart - 1,
|
||||
this.w - this.paddingInlineStart - this.paddingInlineEnd + 2,
|
||||
this.h - this.paddingBlockStart - this.paddingBlockEnd + 2,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1);
|
||||
this.h - this.paddingBlockStart - this.paddingBlockEnd + 2);
|
||||
|
||||
super.draw(mx, my);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public class HandlerInfo {
|
||||
|
||||
public static int DEFAULT_HEIGHT = 65;
|
||||
public static int DEFAULT_WIDTH = 166;
|
||||
public static final int DEFAULT_IMAGE_TEXTURE_SIZE = 256;
|
||||
|
||||
@Deprecated
|
||||
public static int DEFAULT_MAX_PER_PAGE = 1;
|
||||
@@ -70,9 +71,22 @@ public class HandlerInfo {
|
||||
}
|
||||
|
||||
public boolean setImage(String resourceLocation, int imageX, int imageY, int imageWidth, int imageHeight) {
|
||||
return setImage(
|
||||
resourceLocation,
|
||||
imageX,
|
||||
imageY,
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
DEFAULT_IMAGE_TEXTURE_SIZE,
|
||||
DEFAULT_IMAGE_TEXTURE_SIZE);
|
||||
}
|
||||
|
||||
public boolean setImage(String resourceLocation, int imageX, int imageY, int imageWidth, int imageHeight,
|
||||
int textureWidth, int textureHeight) {
|
||||
if (hasImageOrItem()) return false;
|
||||
|
||||
this.image = new DrawableBuilder(resourceLocation, imageX, imageY, imageWidth, imageHeight).build();
|
||||
this.image = new DrawableBuilder(resourceLocation, imageX, imageY, imageWidth, imageHeight)
|
||||
.setTextureSize(textureWidth, textureHeight).build();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -211,6 +225,20 @@ public class HandlerInfo {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDisplayImage(ResourceLocation location, int imageX, int imageY, int imageWidth,
|
||||
int imageHeight, int textureWidth, int textureHeight) {
|
||||
this.info.itemStack = null;
|
||||
this.info.setImage(
|
||||
location.toString(),
|
||||
imageX,
|
||||
imageY,
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
textureWidth,
|
||||
textureHeight);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Builder setUseCustomScroll(boolean useCustomScroll) {
|
||||
this.info.setUseCustomScroll(useCustomScroll);
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.BookmarksGridSlot;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public final class HoveredRecipe {
|
||||
|
||||
public enum Source {
|
||||
RECIPE_GUI,
|
||||
BOOKMARK,
|
||||
ITEM_PANEL,
|
||||
OTHER
|
||||
}
|
||||
|
||||
public final RecipeId recipeId;
|
||||
public final Source source;
|
||||
public final boolean favorite;
|
||||
|
||||
private HoveredRecipe(RecipeId recipeId, Source source, boolean favorite) {
|
||||
this.recipeId = recipeId;
|
||||
this.source = source;
|
||||
this.favorite = favorite;
|
||||
}
|
||||
|
||||
public static HoveredRecipe of(GuiScreen gui, ItemStack stackover) {
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe) {
|
||||
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
|
||||
|
||||
if (focusedRecipe != null) {
|
||||
return new HoveredRecipe(focusedRecipe.getRecipeId(), Source.RECIPE_GUI, false);
|
||||
}
|
||||
}
|
||||
|
||||
final Point mouseover = GuiDraw.getMousePosition();
|
||||
final BookmarksGridSlot bookmarkSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (bookmarkSlot != null) {
|
||||
|
||||
if (bookmarkSlot.getType() != BookmarkItemType.INGREDIENT && bookmarkSlot.getRecipeId() != null) {
|
||||
return new HoveredRecipe(bookmarkSlot.getRecipeId(), Source.BOOKMARK, false);
|
||||
}
|
||||
|
||||
return favorite(stackover, Source.BOOKMARK);
|
||||
}
|
||||
|
||||
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot == null) {
|
||||
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
}
|
||||
|
||||
if (itemSlot != null) {
|
||||
|
||||
if (itemSlot.getRecipeId() != null) {
|
||||
return new HoveredRecipe(itemSlot.getRecipeId(), Source.ITEM_PANEL, false);
|
||||
}
|
||||
|
||||
return favorite(stackover, Source.ITEM_PANEL);
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe && guiRecipe.getSlotAtPosition(mouseover.x, mouseover.y) != null) {
|
||||
return favorite(stackover, Source.RECIPE_GUI);
|
||||
}
|
||||
|
||||
return favorite(stackover, Source.OTHER);
|
||||
}
|
||||
|
||||
private static HoveredRecipe favorite(ItemStack stackover, Source source) {
|
||||
final RecipeId recipeId = FavoriteRecipes.getFavorite(stackover);
|
||||
return recipeId != null ? new HoveredRecipe(recipeId, source, true) : null;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -167,6 +168,8 @@ public class RecipeHandlerRef {
|
||||
return transferAlghoritmCache.computeIfAbsent(overlayHandler.getClass(), clazz -> {
|
||||
|
||||
try {
|
||||
final Method transferRecipe = overlayHandler.getClass()
|
||||
.getMethod("transferRecipe", GuiContainer.class, IRecipeHandler.class, int.class, int.class);
|
||||
|
||||
if (overlayHandler instanceof DefaultOverlayHandler) {
|
||||
final Class<?> overlayRecipeClazz = overlayHandler.getClass()
|
||||
@@ -178,14 +181,11 @@ public class RecipeHandlerRef {
|
||||
boolean.class)
|
||||
.getDeclaringClass();
|
||||
|
||||
if (overlayRecipeClazz.equals(DefaultOverlayHandler.class)) {
|
||||
return true;
|
||||
}
|
||||
return overlayRecipeClazz.equals(DefaultOverlayHandler.class)
|
||||
|| !transferRecipe.getDeclaringClass().equals(DefaultOverlayHandler.class);
|
||||
}
|
||||
|
||||
return !overlayHandler.getClass()
|
||||
.getMethod("transferRecipe", GuiContainer.class, IRecipeHandler.class, int.class, int.class)
|
||||
.isDefault();
|
||||
return !transferRecipe.isDefault();
|
||||
} catch (NoSuchMethodException e) {}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -7,14 +7,10 @@ import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.api.ShortcutInputHandler;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.BookmarksGridSlot;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
@@ -58,7 +54,9 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
|
||||
List<String> currenttip) {
|
||||
|
||||
if (itemstack != null) {
|
||||
final RecipeId recipeId = getHoveredRecipeId(gui, itemstack, mousex, mousey);
|
||||
final HoveredRecipe hovered = HoveredRecipe.of(gui, itemstack);
|
||||
final RecipeId recipeId = hovered != null && showRecipeTooltip(hovered, mousex, mousey) ? hovered.recipeId
|
||||
: null;
|
||||
|
||||
if (recipeId == null) {
|
||||
recipeTooltipLineHandler = null;
|
||||
@@ -76,49 +74,21 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
private RecipeId getHoveredRecipeId(GuiContainer gui, ItemStack itemstack, int mousex, int mousey) {
|
||||
private boolean showRecipeTooltip(HoveredRecipe hovered, int mousex, int mousey) {
|
||||
return switch (hovered.source) {
|
||||
case BOOKMARK -> !hovered.favorite && showRecipeTooltipInBookmarks(mousex, mousey);
|
||||
case ITEM_PANEL -> NEIClientConfig.showRecipeTooltipInPanel();
|
||||
case RECIPE_GUI -> hovered.favorite && NEIClientConfig.showRecipeTooltipInGui();
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
if (ItemPanels.bookmarkPanel.contains(mousex, mousey)) {
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (slot != null && slot.getRecipeId() != null
|
||||
&& slot.getType() != BookmarkItemType.INGREDIENT
|
||||
&& NEIClientConfig.getRecipeTooltipsMode() != 0) {
|
||||
final int tooltipMode = NEIClientConfig.getRecipeTooltipsMode();
|
||||
final BookmarkViewMode viewMode = slot.getGroup().viewMode;
|
||||
if (tooltipMode == 3 || viewMode == BookmarkViewMode.DEFAULT && tooltipMode == 1
|
||||
|| viewMode == BookmarkViewMode.TODO_LIST && tooltipMode == 2) {
|
||||
return slot.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showRecipeTooltipInPanel()) {
|
||||
ItemsGridSlot panelSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (panelSlot == null) {
|
||||
panelSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (panelSlot == null) {
|
||||
panelSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
if (panelSlot != null) {
|
||||
return panelSlot.getRecipeId();
|
||||
}
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe<?>guiRecipe
|
||||
&& new Rectangle4i(gui.guiLeft, gui.guiTop, gui.xSize, gui.ySize).contains(mousex, mousey)
|
||||
&& NEIClientConfig.showRecipeTooltipInGui()
|
||||
&& guiRecipe.getFocusedRecipe() == null) {
|
||||
return FavoriteRecipes.getFavorite(itemstack);
|
||||
}
|
||||
|
||||
return null;
|
||||
private boolean showRecipeTooltipInBookmarks(int mousex, int mousey) {
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
|
||||
final int tooltipMode = NEIClientConfig.getRecipeTooltipsMode();
|
||||
final BookmarkViewMode viewMode = slot.getGroup().viewMode;
|
||||
return tooltipMode == 3 || viewMode == BookmarkViewMode.DEFAULT && tooltipMode == 1
|
||||
|| viewMode == BookmarkViewMode.TODO_LIST && tooltipMode == 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,7 @@ import codechicken.nei.ItemStackAmount;
|
||||
import codechicken.nei.ItemsTooltipLineHandler;
|
||||
import codechicken.nei.ItemsTooltipLineHandler.StacksAmountRenderer;
|
||||
import codechicken.nei.ItemsTooltipLineHandler.TotalAmountRenderer;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.api.IGuiContainerOverlay;
|
||||
@@ -163,9 +164,9 @@ public class RecipeItemsTooltipLineHandler extends CompositeTooltipLineHandler {
|
||||
|
||||
protected void addResultLine(List<ItemStack> items, Set<NBTTagCompound> approximate) {
|
||||
final String label = NEIClientUtils.translate("recipe.items.results");
|
||||
final ItemsTooltipLineHandler line = items.size() == 1
|
||||
? ItemsTooltipLineHandler.list(label, items, maxLineRows())
|
||||
: ItemsTooltipLineHandler.grid(label, items, maxLineRows());
|
||||
final int maxRows = maxLineRows();
|
||||
final int maxNamedRows = items.size() == 1 ? NEIClientConfig.getMaxVerticalTooltipRows() : 0;
|
||||
final ItemsTooltipLineHandler line = ItemsTooltipLineHandler.of(label, items, maxRows, maxNamedRows);
|
||||
|
||||
if (line.isEmpty()) {
|
||||
return;
|
||||
@@ -188,7 +189,9 @@ public class RecipeItemsTooltipLineHandler extends CompositeTooltipLineHandler {
|
||||
|
||||
protected void addRequiredLine(List<ItemStack> items, Set<NBTTagCompound> approximate) {
|
||||
final String label = NEIClientUtils.translate("recipe.items.ingredients");
|
||||
final ItemsTooltipLineHandler line = ItemsTooltipLineHandler.list(label, items, maxLineRows());
|
||||
final int maxRows = maxLineRows();
|
||||
final int maxNamedRows = NEIClientConfig.getMaxVerticalTooltipRows();
|
||||
final ItemsTooltipLineHandler line = ItemsTooltipLineHandler.of(label, items, maxRows, maxNamedRows);
|
||||
|
||||
if (line.isEmpty()) {
|
||||
return;
|
||||
@@ -211,8 +214,9 @@ public class RecipeItemsTooltipLineHandler extends CompositeTooltipLineHandler {
|
||||
|
||||
protected void addNeededLine(List<ItemStack> items, Set<NBTTagCompound> approximate, boolean vertical) {
|
||||
final String label = NEIClientUtils.translate("recipe.items.ingredients_needed");
|
||||
final ItemsTooltipLineHandler line = vertical ? ItemsTooltipLineHandler.list(label, items, maxLineRows())
|
||||
: ItemsTooltipLineHandler.grid(label, items, maxLineRows());
|
||||
final int maxRows = maxLineRows();
|
||||
final int maxNamedRows = vertical ? NEIClientConfig.getMaxVerticalTooltipRows() : 0;
|
||||
final ItemsTooltipLineHandler line = ItemsTooltipLineHandler.of(label, items, maxRows, maxNamedRows);
|
||||
|
||||
if (line.isEmpty()) {
|
||||
return;
|
||||
|
||||
@@ -25,7 +25,13 @@ public class RecipeTooltipLineHandler implements ITooltipLineHandler {
|
||||
0,
|
||||
0,
|
||||
176 + TRANSPARENCY_BORDER * 2,
|
||||
166 + TRANSPARENCY_BORDER * 2).build();
|
||||
166 + TRANSPARENCY_BORDER * 2)
|
||||
.setSlices(
|
||||
BG_PADDING + TRANSPARENCY_BORDER,
|
||||
BG_PADDING + TRANSPARENCY_BORDER,
|
||||
BG_PADDING + TRANSPARENCY_BORDER,
|
||||
BG_PADDING + TRANSPARENCY_BORDER)
|
||||
.build();
|
||||
|
||||
protected long lastUpdate = System.currentTimeMillis();
|
||||
protected String recipeName = "";
|
||||
@@ -105,11 +111,7 @@ public class RecipeTooltipLineHandler implements ITooltipLineHandler {
|
||||
-TRANSPARENCY_BORDER,
|
||||
-TRANSPARENCY_BORDER,
|
||||
size.width + TRANSPARENCY_BORDER * 2,
|
||||
size.height + TRANSPARENCY_BORDER * 2,
|
||||
BG_PADDING + TRANSPARENCY_BORDER,
|
||||
BG_PADDING + TRANSPARENCY_BORDER,
|
||||
BG_PADDING + TRANSPARENCY_BORDER,
|
||||
BG_PADDING + TRANSPARENCY_BORDER);
|
||||
size.height + TRANSPARENCY_BORDER * 2);
|
||||
|
||||
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ import codechicken.nei.util.NBTHelper;
|
||||
|
||||
public class StackInfo {
|
||||
|
||||
/// Prefix of the MaterialLib reference form `ml:<MaterialName>:<shapeToken>`, which config entries carry in
|
||||
/// place of an id and metadata.
|
||||
public static final String MATERIALLIB_PREFIX = "ml:";
|
||||
|
||||
private static final FluidStack NULL_FLUID = new FluidStack(FluidRegistry.WATER, 0);
|
||||
public static final List<IStackStringifyHandler> stackStringifyHandlers = new ArrayList<>();
|
||||
private static final Map<String, HashMap<String, String[]>> guidfilters = new HashMap<>();
|
||||
|
||||
@@ -25,6 +25,7 @@ import codechicken.nei.ItemsTooltipLineHandler;
|
||||
import codechicken.nei.ItemsTooltipLineHandler.AmountRenderer;
|
||||
import codechicken.nei.ItemsTooltipLineHandler.StacksAmountRenderer;
|
||||
import codechicken.nei.ItemsTooltipLineHandler.TotalAmountRenderer;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.bookmark.BookmarkItem;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
@@ -354,8 +355,8 @@ public class RecipeChainTooltipLineHandler extends CompositeTooltipLineHandler {
|
||||
|
||||
protected void addLine(String label, List<ItemStack> items, boolean vertical, EnumChatFormatting labelColor,
|
||||
AmountRenderer amountRenderer) {
|
||||
final ItemsTooltipLineHandler line = vertical ? ItemsTooltipLineHandler.list(label, items, maxLineRows())
|
||||
: ItemsTooltipLineHandler.grid(label, items, maxLineRows());
|
||||
final int maxNamedRows = vertical ? NEIClientConfig.getMaxVerticalTooltipRows() : 0;
|
||||
final ItemsTooltipLineHandler line = ItemsTooltipLineHandler.of(label, items, maxLineRows(), maxNamedRows);
|
||||
|
||||
if (line.isEmpty()) {
|
||||
return;
|
||||
|
||||
@@ -25,6 +25,7 @@ public class CheckboxWidget extends Button implements IUpdatableWidget {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (this.state == 2) return false;
|
||||
this.value = !this.value;
|
||||
onChange.accept(this);
|
||||
return true;
|
||||
|
||||
@@ -30,19 +30,24 @@ import codechicken.nei.ClientHandler;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.Widget;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipeButton;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.HandlerInfo;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
import codechicken.nei.recipe.ShapedRecipeHandler;
|
||||
import codechicken.nei.recipe.TemplateRecipeHandler;
|
||||
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
|
||||
import codechicken.nei.recipe.widget.RecipeWidget;
|
||||
import codechicken.nei.scroll.ScrollContainer;
|
||||
|
||||
public class DebugHandlerWidget extends Widget {
|
||||
public class DebugHandlerWidget extends Widget implements IContainerTooltipHandler {
|
||||
|
||||
private static class HandlerInfoRecord {
|
||||
|
||||
@@ -152,6 +157,9 @@ public class DebugHandlerWidget extends Widget {
|
||||
private Map<String, HandlerInfoRecord> patches = new HashMap<>();
|
||||
|
||||
private HandlerInfoRecord record;
|
||||
private RecipeWidget hoveredRecipe;
|
||||
private boolean duplicatesOnly = false;
|
||||
private String duplicatesHandlerId;
|
||||
|
||||
private Point dragPoint = null;
|
||||
private boolean showWidget = false;
|
||||
@@ -162,11 +170,19 @@ public class DebugHandlerWidget extends Widget {
|
||||
0,
|
||||
0,
|
||||
176 + TRANSPARENCY_BORDER * 2,
|
||||
166 + TRANSPARENCY_BORDER * 2).build();
|
||||
166 + TRANSPARENCY_BORDER * 2)
|
||||
.setSlices(
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER)
|
||||
.build();
|
||||
private static final int BORDER_PADDING = 6;
|
||||
private static final int TRANSPARENCY_BORDER = 4;
|
||||
|
||||
public DebugHandlerWidget() {
|
||||
protected DebugHandlerWidget() {
|
||||
GuiContainerManager.addTooltipHandler(this);
|
||||
|
||||
this.w = WINDOW_WIDTH;
|
||||
this.x = 10;
|
||||
this.y = 50;
|
||||
@@ -242,6 +258,20 @@ public class DebugHandlerWidget extends Widget {
|
||||
saveHandlerInfoPatch();
|
||||
}, y);
|
||||
|
||||
if (Boolean.getBoolean("nei.recipeOrigins")) {
|
||||
y = addCheckboxWidget("DuplicatesOnly", button -> {
|
||||
this.duplicatesOnly = button.value;
|
||||
|
||||
if (NEIClientUtils.getGuiContainer() instanceof GuiRecipe<?>recipe) {
|
||||
this.duplicatesHandlerId = getHandlerID(recipe.getHandler());
|
||||
recipe.forceRefreshPage();
|
||||
}
|
||||
}, y + LINE_HEIGHT / 2);
|
||||
|
||||
// only the handler the checkbox was toggled on is filtered, so switching handlers does not pay for a rescan
|
||||
API.addRecipeFilter(() -> this.duplicatesOnly ? this::isDuplicate : null);
|
||||
}
|
||||
|
||||
this.h = 10 + LINE_HEIGHT + y;
|
||||
this.container.h = this.h - INLINE_PADDING * 2 - LINE_HEIGHT;
|
||||
}
|
||||
@@ -355,11 +385,7 @@ public class DebugHandlerWidget extends Widget {
|
||||
this.x - TRANSPARENCY_BORDER,
|
||||
this.y - TRANSPARENCY_BORDER,
|
||||
this.w + TRANSPARENCY_BORDER * 2,
|
||||
this.h + TRANSPARENCY_BORDER * 2,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER,
|
||||
BORDER_PADDING + TRANSPARENCY_BORDER);
|
||||
this.h + TRANSPARENCY_BORDER * 2);
|
||||
GuiDraw.drawRect(
|
||||
this.x + INLINE_PADDING,
|
||||
this.y + BORDER_PADDING,
|
||||
@@ -417,6 +443,11 @@ public class DebugHandlerWidget extends Widget {
|
||||
|
||||
updateOverride();
|
||||
|
||||
if (this.values.get("duplicatesonly") instanceof CheckboxWidget duplicates) {
|
||||
duplicates.state = handler instanceof ShapedRecipeHandler ? 0 : 2;
|
||||
resetDuplicatesOnly();
|
||||
}
|
||||
|
||||
this.container.removeIf(
|
||||
widget -> this.values.get("height") == widget || this.values.get("height_readonly") == widget);
|
||||
if (handler.getRecipeHeight(0) > 0) {
|
||||
@@ -430,11 +461,26 @@ public class DebugHandlerWidget extends Widget {
|
||||
} else {
|
||||
this.record = null;
|
||||
this.showWidget = false;
|
||||
resetDuplicatesOnly();
|
||||
}
|
||||
|
||||
this.container.update();
|
||||
}
|
||||
|
||||
private void resetDuplicatesOnly() {
|
||||
if (!this.duplicatesOnly) return;
|
||||
|
||||
this.duplicatesOnly = false;
|
||||
|
||||
if (this.values.get("duplicatesonly") instanceof CheckboxWidget duplicates) {
|
||||
duplicates.updateValue("false");
|
||||
}
|
||||
|
||||
if (NEIClientUtils.getGuiContainer() instanceof GuiRecipe<?>recipe) {
|
||||
recipe.forceRefreshPage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
|
||||
return this.record != null ? this.container.handleTooltip(mx, my, tooltip) : tooltip;
|
||||
@@ -532,9 +578,51 @@ public class DebugHandlerWidget extends Widget {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {
|
||||
final RecipeWidget widget = this.hoveredRecipe;
|
||||
this.hoveredRecipe = null;
|
||||
|
||||
if (widget == null || !this.showWidget || !tooltip.isEmpty()) {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
final RecipeHandlerRef ref = widget.getRecipeHandlerRef();
|
||||
|
||||
for (List<String> origin : RecipeOrigins.findOrigins(ref.handler, ref.recipeIndex)) {
|
||||
addOriginLines(tooltip, origin);
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
private static void addOriginLines(List<String> tooltip, List<String> lines) {
|
||||
tooltip.add(
|
||||
EnumChatFormatting.WHITE + NEIClientUtils.translate("debug.RecipeHandler.RegisteredBy", lines.get(0))
|
||||
+ GuiDraw.TOOLTIP_LINESPACE);
|
||||
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
tooltip.add(EnumChatFormatting.GRAY + lines.get(i));
|
||||
}
|
||||
|
||||
tooltip.add("");
|
||||
}
|
||||
|
||||
// only the handler the checkbox was toggled on is filtered
|
||||
private boolean isDuplicate(IRecipeHandler handler, int recipeIndex) {
|
||||
return !getHandlerID(handler).equals(this.duplicatesHandlerId)
|
||||
|| RecipeOrigins.hasDuplicates(handler, recipeIndex);
|
||||
}
|
||||
|
||||
public void drawGuiPlaceholder(RecipeWidget widget) {
|
||||
if (!this.showWidget) return;
|
||||
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
if (widget.getRecipeHandlerRef().handler instanceof ShapedRecipeHandler && widget.contains(mouse.x, mouse.y)
|
||||
&& widget.getStackMouseOver(mouse.x, mouse.y) == null) {
|
||||
this.hoveredRecipe = widget;
|
||||
}
|
||||
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
|
||||
// background
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
package codechicken.nei.recipe.debug;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.CraftingManager;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.ShapedRecipes;
|
||||
import net.minecraft.item.crafting.ShapelessRecipes;
|
||||
import net.minecraftforge.oredict.ShapedOreRecipe;
|
||||
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
||||
|
||||
import codechicken.nei.NEIServerUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.ShapedRecipeHandler;
|
||||
import codechicken.nei.recipe.ShapedRecipeHandler.CachedShapedRecipe;
|
||||
import codechicken.nei.recipe.TemplateRecipeHandler.CachedRecipe;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
/**
|
||||
* Tracks which mod registered each crafting recipe, so the recipe handler debug widget can show it in the recipe
|
||||
* tooltip. {@link TrackingList} is spliced in as the type of {@link CraftingManager}'s internal recipe list by
|
||||
* {@link codechicken.nei.asm.NEITransformer} (see the {@code <init>} transform there) in place of the plain
|
||||
* {@code ArrayList} vanilla constructs it with. Patching the constructor itself, rather than swapping the field later
|
||||
* on, means every single recipe is observed, including vanilla's own, which are added by that same constructor before
|
||||
* any mod code ever runs. Opt-in via {@code -Dnei.recipeOrigins=true}, since capturing a stack trace per recipe slows
|
||||
* down loading.
|
||||
*/
|
||||
public class RecipeOrigins {
|
||||
|
||||
private static final int MAX_FRAMES = 10;
|
||||
|
||||
private static final Map<IRecipe, List<String>> origins = Collections.synchronizedMap(new IdentityHashMap<>());
|
||||
|
||||
private static class OutputIndex {
|
||||
|
||||
final int size;
|
||||
final Map<Item, List<IRecipe>> byItem;
|
||||
|
||||
OutputIndex(int size, Map<Item, List<IRecipe>> byItem) {
|
||||
this.size = size;
|
||||
this.byItem = byItem;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<CachedRecipe, List<List<String>>> cache = new WeakHashMap<>();
|
||||
|
||||
private static volatile OutputIndex outputIndex = new OutputIndex(-1, Collections.emptyMap());
|
||||
|
||||
private RecipeOrigins() {}
|
||||
|
||||
public static List<List<String>> findOrigins(IRecipeHandler handler, int recipeIndex) {
|
||||
if (!(handler instanceof ShapedRecipeHandler shaped)) return Collections.emptyList();
|
||||
|
||||
final CachedRecipe recipe = shaped.arecipes.get(recipeIndex);
|
||||
List<List<String>> found;
|
||||
|
||||
synchronized (cache) {
|
||||
found = cache.get(recipe);
|
||||
}
|
||||
|
||||
if (found == null) {
|
||||
found = findOrigins(shaped, recipe.getResult(), recipe.getIngredients());
|
||||
|
||||
synchronized (cache) {
|
||||
cache.put(recipe, found);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
public static boolean hasDuplicates(IRecipeHandler handler, int recipeIndex) {
|
||||
return handler instanceof ShapedRecipeHandler shaped
|
||||
&& hasDuplicateCandidates(shaped.arecipes.get(recipeIndex).getResult())
|
||||
&& findOrigins(handler, recipeIndex).size() > 1;
|
||||
}
|
||||
|
||||
private static boolean hasDuplicateCandidates(PositionedStack result) {
|
||||
if (origins.isEmpty() || result == null || result.item == null) return false;
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (IRecipe recipe : getRecipesByOutput(result.item.getItem())) {
|
||||
if (origins.containsKey(recipe)
|
||||
&& NEIServerUtils.areStacksSameTypeCrafting(recipe.getRecipeOutput(), result.item)
|
||||
&& ++count > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<List<String>> findOrigins(ShapedRecipeHandler handler, PositionedStack result,
|
||||
List<PositionedStack> ingredients) {
|
||||
if (origins.isEmpty() || result == null || result.item == null) return Collections.emptyList();
|
||||
final List<List<String>> found = new ArrayList<>();
|
||||
|
||||
for (IRecipe recipe : getRecipesByOutput(result.item.getItem())) {
|
||||
final List<String> origin = origins.get(recipe);
|
||||
|
||||
if (origin != null && NEIServerUtils.areStacksSameTypeCrafting(recipe.getRecipeOutput(), result.item)
|
||||
&& matchesIngredients(handler, recipe, ingredients)) {
|
||||
final List<String> entry = new ArrayList<>(origin);
|
||||
entry.add(recipe.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(recipe)));
|
||||
found.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private static List<IRecipe> getRecipesByOutput(Item item) {
|
||||
final List<IRecipe> recipes = CraftingManager.getInstance().getRecipeList();
|
||||
OutputIndex index = outputIndex;
|
||||
|
||||
if (recipes.size() != index.size) {
|
||||
synchronized (RecipeOrigins.class) {
|
||||
index = outputIndex;
|
||||
|
||||
if (recipes.size() != index.size) {
|
||||
final Map<Item, List<IRecipe>> byItem = new HashMap<>();
|
||||
|
||||
for (IRecipe recipe : recipes) {
|
||||
final ItemStack output = recipe.getRecipeOutput();
|
||||
if (output != null)
|
||||
byItem.computeIfAbsent(output.getItem(), k -> new ArrayList<>()).add(recipe);
|
||||
}
|
||||
|
||||
outputIndex = index = new OutputIndex(recipes.size(), byItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index.byItem.getOrDefault(item, Collections.emptyList());
|
||||
}
|
||||
|
||||
private static boolean matchesIngredients(ShapedRecipeHandler handler, IRecipe recipe,
|
||||
List<PositionedStack> ingredients) {
|
||||
if (recipe instanceof ShapedRecipes shaped) {
|
||||
return matchesGrid(handler.new CachedShapedRecipe(shaped), ingredients);
|
||||
}
|
||||
if (recipe instanceof ShapedOreRecipe shaped)
|
||||
return matchesGrid(handler.forgeShapedRecipe(shaped), ingredients);
|
||||
if (recipe instanceof ShapelessRecipes shapeless) return matchesUnordered(shapeless.recipeItems, ingredients);
|
||||
if (recipe instanceof ShapelessOreRecipe shapeless) return matchesUnordered(shapeless.getInput(), ingredients);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean matchesGrid(CachedShapedRecipe reference, List<PositionedStack> ingredients) {
|
||||
if (reference == null || reference.ingredients.size() != ingredients.size()) return false;
|
||||
|
||||
for (PositionedStack expected : reference.ingredients) {
|
||||
final PositionedStack actual = ingredients.stream()
|
||||
.filter(stack -> stack.relx == expected.relx && stack.rely == expected.rely).findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (actual == null || !matchesItems(expected.items, actual.items)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean matchesItems(ItemStack[] expected, ItemStack[] actual) {
|
||||
for (ItemStack candidate : expected) {
|
||||
for (ItemStack item : actual) {
|
||||
if (NEIServerUtils.areStacksSameTypeCrafting(candidate, item)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean matchesUnordered(List<?> inputs, List<PositionedStack> ingredients) {
|
||||
final List<PositionedStack> remaining = new ArrayList<>(ingredients);
|
||||
|
||||
for (Object input : inputs) {
|
||||
if (input == null) continue;
|
||||
|
||||
final PositionedStack match = remaining.stream().filter(stack -> matchesInput(input, stack)).findFirst()
|
||||
.orElse(null);
|
||||
if (match == null) return false;
|
||||
remaining.remove(match);
|
||||
}
|
||||
|
||||
return remaining.isEmpty();
|
||||
}
|
||||
|
||||
private static boolean matchesInput(Object input, PositionedStack stack) {
|
||||
final List<?> candidates = input instanceof List<?>list ? list : Collections.singletonList(input);
|
||||
|
||||
for (Object candidate : candidates) {
|
||||
if (!(candidate instanceof ItemStack candidateStack)) continue;
|
||||
for (ItemStack item : stack.items) {
|
||||
if (NEIServerUtils.areStacksSameTypeCrafting(candidateStack, item)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class TrackingList extends ArrayList<IRecipe> {
|
||||
|
||||
@Override
|
||||
public boolean add(IRecipe recipe) {
|
||||
origins.put(recipe, captureOrigin());
|
||||
return super.add(recipe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, IRecipe recipe) {
|
||||
origins.put(recipe, captureOrigin());
|
||||
super.add(index, recipe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRecipe set(int index, IRecipe recipe) {
|
||||
origins.put(recipe, captureOrigin());
|
||||
return super.set(index, recipe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends IRecipe> recipes) {
|
||||
final List<String> origin = captureOrigin();
|
||||
for (IRecipe recipe : recipes) origins.put(recipe, origin);
|
||||
return super.addAll(recipes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends IRecipe> recipes) {
|
||||
final List<String> origin = captureOrigin();
|
||||
for (IRecipe recipe : recipes) origins.put(recipe, origin);
|
||||
return super.addAll(index, recipes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRecipe remove(int index) {
|
||||
final IRecipe removed = super.remove(index);
|
||||
origins.remove(removed);
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object recipe) {
|
||||
final boolean removed = super.remove(recipe);
|
||||
if (removed) origins.remove(recipe);
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
origins.clear();
|
||||
super.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> captureOrigin() {
|
||||
final List<StackTraceElement> frames = findCallerFrames();
|
||||
|
||||
if (frames.isEmpty()) return Collections.singletonList("Unknown");
|
||||
|
||||
final ModContainer container = Loader.instance().activeModContainer();
|
||||
final List<String> lines = new ArrayList<>(frames.size() + 1);
|
||||
|
||||
lines.add(container != null ? container.getName() : "Unknown");
|
||||
|
||||
for (int i = 0; i < frames.size(); i++) {
|
||||
lines.add(formatFrame(frames.get(i)));
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static String formatFrame(StackTraceElement frame) {
|
||||
return frame.getFileName() != null ? frame.getClassName() + "."
|
||||
+ frame.getMethodName()
|
||||
+ "("
|
||||
+ frame.getFileName()
|
||||
+ ":"
|
||||
+ frame.getLineNumber()
|
||||
+ ")" : frame.getClassName() + "." + frame.getMethodName();
|
||||
}
|
||||
|
||||
private static List<StackTraceElement> findCallerFrames() {
|
||||
final List<StackTraceElement> frames = new ArrayList<>(MAX_FRAMES);
|
||||
|
||||
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
|
||||
final String className = element.getClassName();
|
||||
|
||||
if (className.startsWith("java.") || className.startsWith("net.minecraft.")
|
||||
|| className.startsWith("net.minecraftforge.")
|
||||
|| className.startsWith("cpw.mods.fml.")
|
||||
|| className.startsWith("sun.")
|
||||
|| className.startsWith("jdk.")
|
||||
|| className.startsWith("org.spongepowered.")
|
||||
|| className.startsWith("codechicken.nei.recipe.debug.RecipeOrigins")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
frames.add(element);
|
||||
if (frames.size() >= MAX_FRAMES) break;
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
|
||||
protected static Method getFluidFromDisplayStack = null;
|
||||
protected static Class<?> gtMetaGeneratedTool = null;
|
||||
protected static Field playSound = null;
|
||||
private static boolean loggedNoNbtDisplay = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package codechicken.nei.recipe.stackinfo;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import com.ruling_0.materiallib.api.StackResolver;
|
||||
|
||||
import codechicken.nei.api.IStackStringifyHandler;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
/// Resolves config entries written in the MaterialLib reference form `ml:<MaterialName>:<shapeToken>` (see
|
||||
/// [StackInfo#MATERIALLIB_PREFIX]) through [StackResolver], so an entry keeps naming the same item across sessions
|
||||
/// that renumber item metadata. The resolved stack carries the metadata MaterialLib currently assigns, ignoring any
|
||||
/// `Damage` on the entry. Entries in any other form are left to the other handlers.
|
||||
///
|
||||
/// Registered only behind a `Loader.isModLoaded("materiallib")` gate, so this class never classloads without
|
||||
/// MaterialLib present.
|
||||
public class MaterialLibStackStringifyHandler implements IStackStringifyHandler {
|
||||
|
||||
@Override
|
||||
public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) {
|
||||
final String strId = nbtTag.getString("strId");
|
||||
|
||||
if (!strId.startsWith(StackInfo.MATERIALLIB_PREFIX)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String[] parts = strId.split(":");
|
||||
|
||||
if (parts.length != 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ItemStack stack = StackResolver.getStack(parts[1], parts[2], nbtTag.getInteger("Count"));
|
||||
|
||||
if (stack != null && nbtTag.hasKey("tag")) {
|
||||
stack.setTagCompound((NBTTagCompound) nbtTag.getCompoundTag("tag").copy());
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -745,7 +745,8 @@ public class RecipeWidget extends Widget {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !this.showAsWidget && contains(mouseX, mouseY)
|
||||
return NEIClientConfig.freezeCycleOnHover() && !this.showAsWidget
|
||||
&& contains(mouseX, mouseY)
|
||||
&& (getPositionedStackMouseOver(mouseX, mouseY) != null
|
||||
|| forEachButtons(button -> button.contains(mouseX, mouseY) ? true : null, false));
|
||||
}
|
||||
|
||||
@@ -53,28 +53,26 @@ public class ScrollBar {
|
||||
private int trackPaddingBottom = 0;
|
||||
|
||||
private DrawableResource thumbTexture;
|
||||
private int thumbSliceStart;
|
||||
private int thumbSliceEnd;
|
||||
|
||||
private DrawableResource trackTexture;
|
||||
private int trackSliceStart;
|
||||
private int trackSliceEnd;
|
||||
|
||||
public static ScrollBar defaultScrollBar() {
|
||||
return new ScrollBar();
|
||||
}
|
||||
|
||||
public static ScrollBar defaultVerticalBar() {
|
||||
return new ScrollBar().setTrackWidth(8)
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 29, 95, 8, 11).build(), 3, 4)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).build(), 3, 2)
|
||||
return new ScrollBar().setTrackWidth(8).setTrackTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 29, 95, 8, 11).setSlices(0, 0, 3, 4).build())
|
||||
.setThumbTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).setSlices(0, 0, 3, 2).build())
|
||||
.setThumbPadding(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
public static ScrollBar defaultHorizontalBar() {
|
||||
return new ScrollBar().setTrackWidth(8).setOverflowType(OverflowType.SCROLL)
|
||||
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 0, 97, 11, 8).build(), 3, 4)
|
||||
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 12, 98, 9, 6).build(), 3, 2)
|
||||
.setTrackTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 0, 97, 11, 8).setSlices(3, 4, 0, 0).build())
|
||||
.setThumbTexture(
|
||||
new DrawableBuilder("nei:textures/nei_sprites.png", 12, 98, 9, 6).setSlices(3, 2, 0, 0).build())
|
||||
.setThumbPadding(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
@@ -126,17 +124,13 @@ public class ScrollBar {
|
||||
return getTrackWidth();
|
||||
}
|
||||
|
||||
public ScrollBar setThumbTexture(DrawableResource texture, int sliceStart, int sliceEnd) {
|
||||
public ScrollBar setThumbTexture(DrawableResource texture) {
|
||||
this.thumbTexture = texture;
|
||||
this.thumbSliceStart = sliceStart;
|
||||
this.thumbSliceEnd = sliceEnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScrollBar setTrackTexture(DrawableResource texture, int sliceStart, int sliceEnd) {
|
||||
public ScrollBar setTrackTexture(DrawableResource texture) {
|
||||
this.trackTexture = texture;
|
||||
this.trackSliceStart = sliceStart;
|
||||
this.trackSliceEnd = sliceEnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -379,13 +373,13 @@ public class ScrollBar {
|
||||
final boolean disabled = getVisibleSize(container) >= getActualSize(container);
|
||||
|
||||
if (this.trackTexture != null) {
|
||||
drawTexture(this.trackTexture, this.trackSliceStart, this.trackSliceEnd, trackBounds, false, opacity);
|
||||
drawTexture(this.trackTexture, trackBounds, false, opacity);
|
||||
} else {
|
||||
drawTrackRect(container, trackBounds, opacity);
|
||||
}
|
||||
|
||||
if (this.thumbTexture != null) {
|
||||
drawTexture(this.thumbTexture, this.thumbSliceStart, this.thumbSliceEnd, thumbBounds, disabled, opacity);
|
||||
drawTexture(this.thumbTexture, thumbBounds, disabled, opacity);
|
||||
} else {
|
||||
drawThumbRect(container, thumbBounds, selected, opacity);
|
||||
}
|
||||
@@ -417,8 +411,7 @@ public class ScrollBar {
|
||||
NEIClientUtils.drawRect(bounds.x, bounds.y, bounds.w, bounds.h, thumbColor);
|
||||
}
|
||||
|
||||
private void drawTexture(DrawableResource texture, int sliceStart, int sliceEnd, Rectangle4i bounds,
|
||||
boolean disabled, float opacity) {
|
||||
private void drawTexture(DrawableResource texture, Rectangle4i bounds, boolean disabled, float opacity) {
|
||||
final float c = disabled ? 0.65f : 1f;
|
||||
|
||||
GL11.glColor4f(c, c, c, opacity);
|
||||
@@ -426,9 +419,9 @@ public class ScrollBar {
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (this.scrollType == ScrollType.HORIZONTAL) {
|
||||
texture.draw(bounds.x, bounds.y, bounds.w, texture.getHeight(), sliceStart, sliceEnd, 0, 0);
|
||||
texture.draw(bounds.x, bounds.y, bounds.w, texture.getHeight());
|
||||
} else {
|
||||
texture.draw(bounds.x, bounds.y, texture.getWidth(), bounds.h, 0, 0, sliceStart, sliceEnd);
|
||||
texture.draw(bounds.x, bounds.y, texture.getWidth(), bounds.h);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
@@ -249,6 +250,8 @@ public class ScrollContainer extends WidgetContainer {
|
||||
final boolean canScrollHorizontal = canScrollHorizontal();
|
||||
|
||||
if (canScrollVertical || canScrollHorizontal) {
|
||||
dragScrollBars(mousex, mousey, canScrollVertical, canScrollHorizontal);
|
||||
|
||||
GuiHelper.useScissor(
|
||||
this.x + this.paddingInlineStart,
|
||||
this.y + this.paddingBlockStart,
|
||||
@@ -273,6 +276,20 @@ public class ScrollContainer extends WidgetContainer {
|
||||
|
||||
}
|
||||
|
||||
private void dragScrollBars(int mousex, int mousey, boolean canScrollVertical, boolean canScrollHorizontal) {
|
||||
if (!Mouse.isButtonDown(0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (canScrollVertical) {
|
||||
this.verticalScrollBar.onMouseDragged(this, mousex, mousey, 0, 0);
|
||||
}
|
||||
|
||||
if (canScrollHorizontal) {
|
||||
this.horizontalScrollBar.onMouseDragged(this, mousex, mousey, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawContent(int mousex, int mousey) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushMatrix();
|
||||
|
||||
@@ -14,6 +14,9 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import codechicken.nei.ItemList.AllMultiItemFilter;
|
||||
import codechicken.nei.ItemList.AnyMultiItemFilter;
|
||||
import codechicken.nei.ItemList.NegatedItemFilter;
|
||||
@@ -197,9 +200,9 @@ public class ItemStackFilterParser {
|
||||
}
|
||||
|
||||
private static ItemFilter getStrictIdentifierFilter(String rule) {
|
||||
ItemStack item = NEIServerUtils.getModdedItem(rule, null);
|
||||
Supplier<ItemStack> item = Suppliers.memoize(() -> NEIServerUtils.getModdedItem(rule, null));
|
||||
|
||||
return stack -> OreDictionary.itemMatches(item, stack, false);
|
||||
return stack -> OreDictionary.itemMatches(item.get(), stack, false);
|
||||
}
|
||||
|
||||
protected static ItemFilter getStringIdentifierFilter(String rule) {
|
||||
|
||||
@@ -289,6 +289,7 @@ nei.options.inventory.bookmarks.showRecipeMarkerMode=Show Recipe Marker
|
||||
nei.options.inventory.bookmarks.showRecipeMarkerMode.0=None
|
||||
nei.options.inventory.bookmarks.showRecipeMarkerMode.1=Text
|
||||
nei.options.inventory.bookmarks.showRecipeMarkerMode.2=Background
|
||||
nei.options.inventory.bookmarks.maxVerticalTooltipRows=Max Vertical Tooltip Rows (0 - disable)
|
||||
nei.options.inventory.bookmarks.showRecipeHandlerIcon=Show Handler Icon
|
||||
nei.options.inventory.bookmarks.showRecipeHandlerIcon.true=Yes
|
||||
nei.options.inventory.bookmarks.showRecipeHandlerIcon.false=No
|
||||
@@ -427,6 +428,9 @@ nei.options.inventory.autocrafting.false=Disabled
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe=Require holding shift to move items when overlaying recipe
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe.true=Yes
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe.false=No
|
||||
nei.options.inventory.guirecipe.freezeCycleOnHover=Stop cycling the recipe while hovering over an ingredient or a button
|
||||
nei.options.inventory.guirecipe.freezeCycleOnHover.true=Yes
|
||||
nei.options.inventory.guirecipe.freezeCycleOnHover.false=No
|
||||
nei.options.inventory.widgetsenabled.true=NEI Enabled
|
||||
nei.options.inventory.widgetsenabled.false=NEI Disabled
|
||||
nei.options.inventory.cheatmode.0=Recipe Mode
|
||||
@@ -516,6 +520,13 @@ nei.options.inventory.itemzoom.neiOnly.tip=Zoom items only from the JEI ingredie
|
||||
nei.options.inventory.itemzoom.onlySolid=Show Only Solid Items
|
||||
nei.options.inventory.itemzoom.onlySolid.true=Enabled
|
||||
nei.options.inventory.itemzoom.onlySolid.false=Disabled
|
||||
nei.options.inventory.itemzoom.preferredSide=Preferred Side
|
||||
nei.options.inventory.itemzoom.preferredSide.0=Auto
|
||||
nei.options.inventory.itemzoom.preferredSide.1=Left
|
||||
nei.options.inventory.itemzoom.preferredSide.2=Right
|
||||
nei.options.inventory.itemzoom.preferredSide.0.tip=Prefer whichever side currently has fewer items in its panel.
|
||||
nei.options.inventory.itemzoom.preferredSide.1.tip=Always prefer the left side, unless the cursor is there.
|
||||
nei.options.inventory.itemzoom.preferredSide.2.tip=Always prefer the right side, unless the cursor is there.
|
||||
nei.options.inventory.itemzoom.helpText=Display Help Text
|
||||
nei.options.inventory.itemzoom.helpText.true=Enabled
|
||||
nei.options.inventory.itemzoom.helpText.false=Disabled
|
||||
@@ -617,6 +628,7 @@ nei.debug.RecipeHandler.Width=Width
|
||||
nei.debug.RecipeHandler.ShowFavorites=Show Favorites
|
||||
nei.debug.RecipeHandler.ShowOverlay=Show Overlays
|
||||
nei.debug.RecipeHandler.ShowBadge=Show Badge
|
||||
nei.debug.RecipeHandler.DuplicatesOnly=Duplicates Only
|
||||
nei.debug.RecipeHandler.AllowOverflowY=Allow Overflow Y
|
||||
nei.debug.RecipeHandler.AllowOverflowX=Allow Overflow X
|
||||
nei.debug.RecipeHandler.Override=Override
|
||||
@@ -625,6 +637,7 @@ nei.debug.RecipeHandler.checkbox.off=Off
|
||||
nei.debug.RecipeHandler.yes=Yes
|
||||
nei.debug.RecipeHandler.no=No
|
||||
nei.debug.RecipeHandler.reset=Reset
|
||||
nei.debug.RecipeHandler.RegisteredBy=Registered by: %s
|
||||
|
||||
nei.recipe.page=Page %s/%s
|
||||
nei.recipe.tooltip=Recipes
|
||||
@@ -693,6 +706,7 @@ nei.recipe.overlay.missing=Missing following
|
||||
nei.recipe.overlay.mismatch=Mismatch Crafting Grid
|
||||
nei.recipe.overlay.overlayRecipe=Overlay Recipe
|
||||
nei.recipe.overlay.fillCraftingGrid=Fill Crafting Grid
|
||||
nei.recipe.overlay.fillCraftingGridOnce=Fill Crafting Grid (single recipe)
|
||||
nei.recipe.overlay.bookmarkRecipe=Save with Recipe
|
||||
nei.recipe.overlay.bookmarkRecipeAndCount=Save with Recipe & Count
|
||||
nei.recipe.overlay.sendRecipeToChat=Send Recipe to Chat
|
||||
|
||||
@@ -265,6 +265,9 @@ nei.options.inventory.optimize_gui_overlap_computation.false=Нет
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe=Требовать удержание Shift для перемещения предметов при отображении рецепта
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe.true=Да
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe.false=Нет
|
||||
nei.options.inventory.guirecipe.freezeCycleOnHover=Останавливать перелистывание рецепта при наведении на предмет или кнопку
|
||||
nei.options.inventory.guirecipe.freezeCycleOnHover.true=Да
|
||||
nei.options.inventory.guirecipe.freezeCycleOnHover.false=Нет
|
||||
nei.options.inventory.widgetsenabled.true=NEI включен
|
||||
nei.options.inventory.widgetsenabled.false=NEI выключен
|
||||
nei.options.inventory.cheatmode.0=Режим рецептов
|
||||
@@ -332,6 +335,13 @@ nei.options.inventory.itemzoom.neiOnly.tip=Увеличивать предмет
|
||||
nei.options.inventory.itemzoom.onlySolid=Показывать только твердые предметы
|
||||
nei.options.inventory.itemzoom.onlySolid.true=Включено
|
||||
nei.options.inventory.itemzoom.onlySolid.false=Отключено
|
||||
nei.options.inventory.itemzoom.preferredSide=Предпочитаемая сторона
|
||||
nei.options.inventory.itemzoom.preferredSide.0=Авто
|
||||
nei.options.inventory.itemzoom.preferredSide.1=Слева
|
||||
nei.options.inventory.itemzoom.preferredSide.2=Справа
|
||||
nei.options.inventory.itemzoom.preferredSide.0.tip=Выбирать сторону, где сейчас меньше предметов в панели.
|
||||
nei.options.inventory.itemzoom.preferredSide.1.tip=Всегда предпочитать левую сторону, если там нет курсора.
|
||||
nei.options.inventory.itemzoom.preferredSide.2.tip=Всегда предпочитать правую сторону, если там нет курсора.
|
||||
nei.options.inventory.itemzoom.helpText=Показывать текст помощи
|
||||
nei.options.inventory.itemzoom.helpText.true=Включено
|
||||
nei.options.inventory.itemzoom.helpText.false=Отключено
|
||||
@@ -428,6 +438,7 @@ nei.recipe.overlay=отображение рецепта
|
||||
nei.recipe.overlay.missing=Отсутствует следующее
|
||||
nei.recipe.overlay.mismatch=Несоответствие сетки крафта
|
||||
nei.recipe.overlay.fillCraftingGrid=Заполнить сетку крафта
|
||||
nei.recipe.overlay.fillCraftingGridOnce=Заполнить сетку крафта (один рецепт)
|
||||
nei.recipe.overlay.bookmarkRecipe=Сохранить с рецептом
|
||||
nei.recipe.overlay.sendRecipeToChat=Отправить рецепт в чат
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ public class SearchTokenParserTest {
|
||||
new ModeValue(1, "Extended mode"), new ModeValue(2, "Regex mode"), new ModeValue(3, "Extended+ mode") };
|
||||
private static final ModeValue[] extendedPlusPatternMode = { patternModes[3] };
|
||||
private static final ModeValue[] extendedPatternModes = { patternModes[1], patternModes[3] };
|
||||
private static final ModeValue[] nonGrammarPatternModes = { patternModes[0], patternModes[1], patternModes[2] };
|
||||
|
||||
private static final SearchParserProvider defaultParserProvider = parserProvider(
|
||||
'\0',
|
||||
@@ -119,6 +120,10 @@ public class SearchTokenParserTest {
|
||||
|
||||
private static final List<Arguments> allModesTestProvider = combinationsProvider(spaceModes, patternModes);
|
||||
|
||||
private static final List<Arguments> nonGrammarAllSpaceModesTestProvider = combinationsProvider(
|
||||
spaceModes,
|
||||
nonGrammarPatternModes);
|
||||
|
||||
private static final List<Arguments> extendedPlusAllSpaceModesTestProvider = combinationsProvider(
|
||||
spaceModes,
|
||||
extendedPlusPatternMode);
|
||||
@@ -236,6 +241,36 @@ public class SearchTokenParserTest {
|
||||
assertTrue(matchedItems.contains(itemA));
|
||||
}
|
||||
|
||||
@DisplayName("Negated prefix (dash)")
|
||||
@ParameterizedTest(name = "{argumentsWithNames}")
|
||||
@FieldSource("allModesTestProvider")
|
||||
public void testNegatedPrefixDash(int spaceMode, int patternMode) {
|
||||
SearchTokenParser searchParser = new SearchTokenParser();
|
||||
searchParser.addProvider(defaultParserProvider);
|
||||
searchParser
|
||||
.addProvider(parserProvider('?', "custom", SearchTokenParser.SearchMode.PREFIX, customCreateFilter));
|
||||
|
||||
Set<ItemStack> matchedItems = testFilterAgainstAllItems(spaceMode, patternMode, searchParser, "-?A");
|
||||
|
||||
assertEquals(5, matchedItems.size());
|
||||
assertFalse(matchedItems.contains(itemA));
|
||||
}
|
||||
|
||||
@DisplayName("Negated prefix (bang)")
|
||||
@ParameterizedTest(name = "{argumentsWithNames}")
|
||||
@FieldSource("nonGrammarAllSpaceModesTestProvider")
|
||||
public void testNegatedPrefixBang(int spaceMode, int patternMode) {
|
||||
SearchTokenParser searchParser = new SearchTokenParser();
|
||||
searchParser.addProvider(defaultParserProvider);
|
||||
searchParser
|
||||
.addProvider(parserProvider('?', "custom", SearchTokenParser.SearchMode.PREFIX, customCreateFilter));
|
||||
|
||||
Set<ItemStack> matchedItems = testFilterAgainstAllItems(spaceMode, patternMode, searchParser, "!?A");
|
||||
|
||||
assertEquals(5, matchedItems.size());
|
||||
assertFalse(matchedItems.contains(itemA));
|
||||
}
|
||||
|
||||
@DisplayName("Space mode")
|
||||
@ParameterizedTest(name = "{argumentsWithNames}")
|
||||
@FieldSource("spaceIsSpaceAllModesTestProvider")
|
||||
|
||||
Reference in new issue
Block a user