diff --git a/resources/assets/nei/lang/en_US.lang b/resources/assets/nei/lang/en_US.lang index 8a6dd220..77a2abd7 100644 --- a/resources/assets/nei/lang/en_US.lang +++ b/resources/assets/nei/lang/en_US.lang @@ -117,6 +117,12 @@ nei.options.inventory.jei_style_tabs.false=No [Weirdo] nei.options.inventory.jei_style_item_presence_overlay=JEI Style Item Overlay on ?-Hover nei.options.inventory.jei_style_item_presence_overlay.true=Yes nei.options.inventory.jei_style_item_presence_overlay.false=No +nei.options.inventory.saveCurrentRecipeInBookmarksEnabled=Save Current Recipe in Bookmarks +nei.options.inventory.saveCurrentRecipeInBookmarksEnabled.true=Enabled +nei.options.inventory.saveCurrentRecipeInBookmarksEnabled.false=Disabled +nei.options.inventory.useNBTInBookmarks=Use NBT in Bookmarks +nei.options.inventory.useNBTInBookmarks.true=Yes +nei.options.inventory.useNBTInBookmarks.false=No nei.options.inventory.creative_tab_style=Creative or JEI tab style nei.options.inventory.creative_tab_style.true=Creative nei.options.inventory.creative_tab_style.false=JEI diff --git a/src/codechicken/nei/BookmarkPanel.java b/src/codechicken/nei/BookmarkPanel.java index e10c7c0f..5b4f8148 100644 --- a/src/codechicken/nei/BookmarkPanel.java +++ b/src/codechicken/nei/BookmarkPanel.java @@ -1,7 +1,11 @@ package codechicken.nei; import codechicken.nei.util.NBTJson; +import codechicken.nei.recipe.StackInfo; +import codechicken.nei.recipe.BookmarkRecipeId; import com.google.gson.JsonParser; +import com.google.gson.JsonObject; +import com.google.gson.JsonElement; import com.google.gson.JsonSyntaxException; import cpw.mods.fml.common.registry.GameData; import net.minecraft.client.gui.inventory.GuiContainer; @@ -23,6 +27,10 @@ import java.util.List; */ public class BookmarkPanel extends ItemPanel { + protected ArrayList _recipes = new ArrayList<>(); + protected boolean bookmarksIsLoaded = false; + public int sortedStackIndex = -1; + public void init() { super.init(); } @@ -36,55 +44,102 @@ public class BookmarkPanel extends ItemPanel { return super.getLabelText() + " [" + realItems.size() + "]"; } - public void addOrRemoveItem(ItemStack item) { - ItemStack normalized = normalize(item); - if(!remove(normalized)) { + public void addOrRemoveItem(ItemStack item) + { + addOrRemoveItem(item, null); + } + + public void addOrRemoveItem(ItemStack item, BookmarkRecipeId recipeId) + { + loadBookmarksIfNeeded(); + + ItemStack normalized = StackInfo.normalize(item); + + if (normalized != null && !remove(normalized)) { _items.add(normalized); + _recipes.add(recipeId); } + saveBookmarks(); } - public static NBTTagCompound itemStackToNBT(ItemStack stack, NBTTagCompound nbTag) + public BookmarkRecipeId getBookmarkRecipeId(ItemStack item) { - String strId = Item.itemRegistry.getNameForObject(stack.getItem()); - nbTag.setString("strId", strId); - nbTag.setByte("Count", (byte)stack.stackSize); - nbTag.setShort("Damage", (short)stack.getItemDamage()); + int index = findStackIndex(item); - if (stack.stackTagCompound != null) - { - nbTag.setTag("tag", stack.stackTagCompound); + if (index >= 0) { + return _recipes.get(index); } - return nbTag; + return null; } - public static ItemStack loadFromNBT(NBTTagCompound nbtTag) + public int findStackIndex(ItemStack stackA) { - if (!nbtTag.hasKey("id")) { - final short id = (short)GameData.getItemRegistry().getId(nbtTag.getString("strId")); - nbtTag.setShort("id", id); + boolean useNBT = NEIClientConfig.useNBTInBookmarks(); + int i = 0; + + for (ItemStack stackB : _items) { + + if (StackInfo.equalItemAndNBT(stackA, stackB, useNBT)) { + return i; + } + + i++; } - ItemStack stack = ItemStack.loadItemStackFromNBT(nbtTag); - return stack; + + return -1; } - public void saveBookmarks() { + public void saveBookmarks() + { List strings = new ArrayList<>(); - for (ItemStack item:_items) { - strings.add(NBTJson.toJson(itemStackToNBT(item, new NBTTagCompound()))); + int index = 0; + + for (ItemStack item: _items) { + try { + final NBTTagCompound nbTag = StackInfo.itemStackToNBT(item); + + if (nbTag != null) { + JsonObject row = new JsonObject(); + BookmarkRecipeId recipeId = _recipes.get(index); + + row.add("item", NBTJson.toJsonObject(nbTag)); + + if (recipeId != null) { + row.add("recipeId", recipeId.toJsonObject()); + } + + strings.add(NBTJson.toJson(row)); + } + + } catch (JsonSyntaxException e) { + NEIClientConfig.logger.error("Failed to stringify bookmarked ItemStack to json string"); + } + + index++; } + File file = NEIClientConfig.bookmarkFile; - if(file != null) { + if (file != null) { try(FileWriter writer = new FileWriter(file)) { IOUtils.writeLines(strings, "\n", writer); } catch (IOException e) { NEIClientConfig.logger.error("Filed to save bookmarks list to file {}", file, e); } } + } - public void loadBookmarks() { + public void loadBookmarksIfNeeded() + { + + if (bookmarksIsLoaded == true) { + return; + } + + bookmarksIsLoaded = true; + File file = NEIClientConfig.bookmarkFile; if (file == null || !file.exists()) { return; @@ -97,37 +152,57 @@ public class BookmarkPanel extends ItemPanel { NEIClientConfig.logger.error("Failed to load bookmarks from file {}", file, e); return; } + _items.clear(); JsonParser parser = new JsonParser(); for (String itemStr: itemStrings) { try { - NBTTagCompound itemStackNBT = (NBTTagCompound) NBTJson.toNbt(parser.parse(itemStr)); - ItemStack itemStack = loadFromNBT(itemStackNBT); + JsonObject jsonObject = parser.parse(itemStr).getAsJsonObject(); + NBTTagCompound itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject); + BookmarkRecipeId recipeId = null; + + if (jsonObject.get("item") != null) { + itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item")); + } else {//old format + itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject); + } + + if (jsonObject.get("recipeId") != null && jsonObject.get("recipeId") instanceof JsonObject) { + recipeId = new BookmarkRecipeId((JsonObject) jsonObject.get("recipeId")); + } + + ItemStack itemStack = StackInfo.loadFromNBT(itemStackNBT); + if (itemStack != null) { _items.add(itemStack); + _recipes.add(recipeId); } else { NEIClientConfig.logger.warn("Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}", itemStr); } + } catch (IllegalArgumentException | JsonSyntaxException e) { NEIClientConfig.logger.error("Failed to load bookmarked ItemStack from json string:\n{}", itemStr); } } } - protected ItemStack normalize(ItemStack item) { - ItemStack copy = item.copy(); - copy.stackSize = 1; - return copy; + @Override + public void draw(int mousex, int mousey) + { + loadBookmarksIfNeeded(); + super.draw(mousex, mousey); } - private boolean remove(ItemStack item) { - int i = 0; - for (ItemStack existing : _items) { - if (existing == item || existing.isItemEqual(item)) { - _items.remove(i); - return true; - } - i++; + + private boolean remove(ItemStack item) + { + int index = findStackIndex(item); + + if (index >= 0) { + _items.remove(index); + _recipes.remove(index); + return true; } + return false; } @@ -171,4 +246,51 @@ public class BookmarkPanel extends ItemPanel { return LayoutManager.getLeftSize(gui) - ( (gui.xSize + gui.width) / 2 + 3 ) - 16; } + @Override + public void mouseDragged(int mousex, int mousey, int button, long heldTime) + { + + if (button == 0 && NEIClientUtils.shiftKey() && mouseDownSlot >= 0) { + ItemPanelSlot mouseOverSlot = getSlotMouseOver(mousex, mousey); + + if (mouseOverSlot == null) { + return; + } + + if (sortedStackIndex == -1) { + ItemStack stack = _items.get(mouseDownSlot); + + if (stack != null && (mouseOverSlot == null || mouseOverSlot.slotIndex != mouseDownSlot || heldTime > 500)) { + sortedStackIndex = mouseDownSlot; + } + + } else if (mouseOverSlot != null && mouseOverSlot.slotIndex != sortedStackIndex) { + + int maxStackIndex = Math.max(mouseOverSlot.slotIndex, sortedStackIndex); + int slotIndex = mouseOverSlot.slotIndex; + + _items.add(slotIndex, _items.remove(sortedStackIndex)); + _recipes.add(slotIndex, _recipes.remove(sortedStackIndex)); + + sortedStackIndex = mouseOverSlot.slotIndex; + } + + return; + } + + super.mouseDragged(mousex, mousey, button, heldTime); + } + + @Override + public void mouseUp(int mousex, int mousey, int button) + { + if (sortedStackIndex >= 0) { + sortedStackIndex = -1; + mouseDownSlot = -1; + saveBookmarks(); + } else { + super.mouseUp(mousex, mousey, button); + } + } + } diff --git a/src/codechicken/nei/LayoutManager.java b/src/codechicken/nei/LayoutManager.java index e757c61a..33d1e082 100644 --- a/src/codechicken/nei/LayoutManager.java +++ b/src/codechicken/nei/LayoutManager.java @@ -265,7 +265,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH GL11.glEnable(GL11.GL_DEPTH_TEST); } } - + @Override public void postRenderObjects(GuiContainer gui, int mousex, int mousey) { if (!isHidden() && isEnabled()) { @@ -310,13 +310,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH VisiblityData visiblity = new VisiblityData(); if (isHidden()) visiblity.showNEI = false; - + if (isBookmarkPanelHidden()) visiblity.showBookmarkPanel = false; - + if (gui.height - gui.ySize <= 40) visiblity.showSearchSection = false; - + if (gui.guiLeft - 4 < 76) visiblity.showWidgets = false; try { @@ -325,7 +325,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH } finally { GuiInfo.readLock.unlock(); } - + visiblity.translateDependancies(); getLayoutStyle().layout(gui, visiblity); @@ -351,7 +351,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH this.icons[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 48, 0, 16, 16).build(); this.icons[2] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 64, 0, 16, 16).build(); } - + @Override public boolean onButtonPress(boolean rightclick) { if (!rightclick) { @@ -367,7 +367,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH } return false; } - + @Override public void addTooltips(List tooltip) { tooltip.add(translate("inventory.options.tip")); @@ -380,9 +380,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH String controlKeyLocalization = translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl"); tooltip.add(modeColor + translate("inventory.options.tip.cheatmode." + cheatMode)); tooltip.add(modeColor + translate("inventory.options.tip.cheatmode.disable", controlKeyLocalization)); - + } - + @Override public String getRenderLabel() { return translate("inventory.options"); @@ -396,7 +396,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH this.icons[0] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 0, 0, 16, 16).build(); this.icons[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 16, 0, 16, 16).build(); } - + @Override public boolean onButtonPress(boolean rightclick) { NEIClientConfig.toggleBooleanSetting("inventory.bookmarksEnabled"); @@ -619,7 +619,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH return true; } - + public static void markItemsDirty() { // If anything has modified data this depends on, we'll need to reload the item list itemsLoaded = false; @@ -683,7 +683,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH if (visiblity.showBookmarkPanel) { addWidget(bookmarkPanel); bookmarkPanel.setVisible(); - } + } if (visiblity.showSearchSection) { addWidget(searchField); @@ -707,7 +707,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH if (canPerformAction("delete")) addWidget(delete); } - + if (!visiblity.showBookmarkPanel) { // Bookmarks or Subset/dropdown addWidget(dropDown); @@ -761,7 +761,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH @Override public boolean shouldShowTooltip(GuiContainer gui) { - return itemPanel.draggedStack == null; + return itemPanel.draggedStack == null && bookmarkPanel.sortedStackIndex == -1; } /** Note: this method isn't actually used by this mod, but NEI add-ons might need it. */ @@ -799,16 +799,16 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH public static void drawIcon(int x, int y, Image image) { final boolean isDrawableResource = image instanceof DrawableResource; - + if (!isDrawableResource) changeTexture("nei:textures/nei_sprites.png"); - + GL11.glColor4f(1, 1, 1, 1); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); if(!isDrawableResource) drawTexturedModalRect(x, y, image.x, image.y, image.width, image.height); - else + else ((DrawableResource)image).draw(x, y); GL11.glDisable(GL11.GL_BLEND); } @@ -884,4 +884,3 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH } } - diff --git a/src/codechicken/nei/NEIClientConfig.java b/src/codechicken/nei/NEIClientConfig.java index 048d38cf..87c3e3eb 100644 --- a/src/codechicken/nei/NEIClientConfig.java +++ b/src/codechicken/nei/NEIClientConfig.java @@ -117,7 +117,7 @@ public class NEIClientConfig { tag.getTag("inventory.widgetsenabled").getBooleanValue(true); API.addOption(new OptionToggleButton("inventory.widgetsenabled")); - + tag.getTag("inventory.hidden").getBooleanValue(false); tag.getTag("inventory.cheatmode").getIntValue(2); tag.getTag("inventory.lockmode").setComment("For those who can't help themselves.\nSet this to a mode and you will be unable to change it ingame").getIntValue(-1); @@ -174,14 +174,20 @@ public class NEIClientConfig { API.addOption(new OptionTextField("command.rain")); tag.getTag("command.heal").setDefaultValue(""); API.addOption(new OptionTextField("command.heal")); - + tag.getTag("inventory.bookmarksEnabled").setComment("Enable/disable bookmarks").getBooleanValue(true); API.addOption(new OptionToggleButton("inventory.bookmarksEnabled", true)); + tag.getTag("inventory.saveCurrentRecipeInBookmarksEnabled").setComment("Save Current Recipe in Bookmarks").getBooleanValue(true); + API.addOption(new OptionToggleButton("inventory.saveCurrentRecipeInBookmarksEnabled", true)); + tag.getTag("inventory.useNBTInBookmarks").setComment("Use NBT in Bookmarks").getBooleanValue(true); + API.addOption(new OptionToggleButton("inventory.useNBTInBookmarks", true)); + tag.getTag("inventory.jei_style_tabs").setComment("Enable/disable JEI Style Tabs").getBooleanValue(true); API.addOption(new OptionToggleButtonBoubs("inventory.jei_style_tabs", true)); tag.getTag("inventory.jei_style_item_presence_overlay").setComment("Enable/disable JEI Style item presence overlay on ?-hover").getBooleanValue(true); API.addOption(new OptionToggleButton("inventory.jei_style_item_presence_overlay", true)); - + + tag.getTag("inventory.creative_tab_style").setComment("Creative or JEI style tabs").getBooleanValue(false); API.addOption(new OptionToggleButton("inventory.creative_tab_style", true)); @@ -308,7 +314,6 @@ public class NEIClientConfig { GuiInfo.load(); RecipeInfo.load(); LayoutManager.load(); - ItemPanels.bookmarkPanel.loadBookmarks(); NEIController.load(); configLoaded = true; @@ -357,6 +362,12 @@ public class NEIClientConfig { public static boolean isBookmarkPanelHidden() { return !getBooleanSetting("inventory.bookmarksEnabled"); } + public static boolean saveCurrentRecipeInBookmarksEnabled() { + return getBooleanSetting("inventory.saveCurrentRecipeInBookmarksEnabled"); + } + public static boolean useNBTInBookmarks() { + return getBooleanSetting("inventory.useNBTInBookmarks"); + } public static boolean areJEIStyleTabsVisible() { return getBooleanSetting("inventory.jei_style_tabs"); } @@ -370,7 +381,7 @@ public class NEIClientConfig { return enabledOverride && getBooleanSetting("inventory.widgetsenabled"); } public static boolean loadHandlersFromJar() { - return !getBooleanSetting("tools.handler_load_from_config"); + return !getBooleanSetting("tools.handler_load_from_config"); } public static void setEnabled(boolean flag) { @@ -441,7 +452,7 @@ public class NEIClientConfig { public static boolean shouldInvertMouseScrollTransfer() { return !getBooleanSetting("inventory.invertMouseScrollTransfer"); } - + public static boolean getMagnetMode() { return enabledActions.contains("magnet"); } @@ -528,5 +539,5 @@ public class NEIClientConfig { if (file.isDirectory() && !saveFileNames.contains(file.getName())) ObfuscationRun.deleteDir(file, true); } - + } diff --git a/src/codechicken/nei/api/API.java b/src/codechicken/nei/api/API.java index dc4544c5..f2d9d02b 100644 --- a/src/codechicken/nei/api/API.java +++ b/src/codechicken/nei/api/API.java @@ -20,6 +20,7 @@ import codechicken.nei.recipe.GuiUsageRecipe; import codechicken.nei.recipe.ICraftingHandler; import codechicken.nei.recipe.IUsageHandler; import codechicken.nei.recipe.RecipeInfo; +import codechicken.nei.recipe.StackInfo; import net.minecraft.block.Block; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.inventory.Slot; @@ -284,4 +285,10 @@ public class API ItemInfo.itemVariants.put(item, variant); LayoutManager.markItemsDirty(); } + + public static void registerStackStringifyHandler(IStackStringifyHandler handler) + { + StackInfo.stackStringifyHandlers.add(handler); + } + } diff --git a/src/codechicken/nei/api/IStackStringifyHandler.java b/src/codechicken/nei/api/IStackStringifyHandler.java new file mode 100644 index 00000000..03774349 --- /dev/null +++ b/src/codechicken/nei/api/IStackStringifyHandler.java @@ -0,0 +1,15 @@ +package codechicken.nei.api; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.item.ItemStack; + +public interface IStackStringifyHandler +{ + + public NBTTagCompound convertItemStackToNBT(ItemStack[] stacks); + + public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag); + + public ItemStack normalize(ItemStack item); + +} \ No newline at end of file diff --git a/src/codechicken/nei/recipe/BookmarkRecipeId.java b/src/codechicken/nei/recipe/BookmarkRecipeId.java new file mode 100644 index 00000000..c5fdaf7c --- /dev/null +++ b/src/codechicken/nei/recipe/BookmarkRecipeId.java @@ -0,0 +1,146 @@ +package codechicken.nei.recipe; + +import com.google.gson.JsonObject; +import com.google.gson.JsonElement; +import com.google.gson.JsonArray; +import com.google.gson.JsonPrimitive; +import codechicken.nei.util.NBTJson; +import codechicken.nei.PositionedStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; + + +public class BookmarkRecipeId +{ + public int position = -1; + public int recipetype = -1; + public String handlerName = null; + public List ingredients = new ArrayList<>(); + + public BookmarkRecipeId(String handlerName, List stacks, int recipetype, int position) + { + this.handlerName = handlerName; + + for (PositionedStack pStack : stacks) { + ingredients.add(getItemStackWithMinimumDamage(pStack.items)); + } + + this.ingredients = ingredients; + this.recipetype = recipetype; + this.position = position; + } + + public BookmarkRecipeId(String handlerName, List stacks) + { + this(handlerName, stacks, -1, -1); + } + + public BookmarkRecipeId(JsonObject json) + { + + if (json.get("handlerName") != null) { + handlerName = json.get("handlerName").getAsString(); + } + + if (json.get("ingredients") != null) { + JsonArray arr = (JsonArray) json.get("ingredients"); + List itemStacks = convertJsonArrayToIngredients(arr); + + if (itemStacks != null) { + ingredients = itemStacks; + } + + } + + } + + public boolean equalsIngredients(List stacks) + { + + if (ingredients.size() != stacks.size()) { + return false; + } + + Short idx = 0; + + for (PositionedStack pStack : stacks) { + final ItemStack stackA = getItemStackWithMinimumDamage(pStack.items); + final ItemStack stackB = ingredients.get(idx); + + if (stackB == null || !StackInfo.equalItemAndNBT(stackA, stackB, true)) { + return false; + } + + idx++; + } + + return true; + } + + protected ItemStack getItemStackWithMinimumDamage(ItemStack[] stacks) + { + int damage = Short.MAX_VALUE; + ItemStack result = stacks[0]; + + if (stacks.length > 1) { + for (ItemStack stack : stacks) { + if (stack.getItemDamage() < damage) { + damage = stack.getItemDamage(); + result = stack; + } + } + } + + return result.copy(); + } + + public JsonObject toJsonObject() + { + JsonObject json = new JsonObject(); + + if (handlerName != null) { + json.add("handlerName", new JsonPrimitive(handlerName)); + json.add("ingredients", convertIngredientsToJsonArray(ingredients)); + } + + return json; + } + + protected List convertJsonArrayToIngredients(JsonArray arr) + { + List ingredients = new ArrayList<>(); + + for (JsonElement elem : arr) { + final ItemStack stack = StackInfo.loadFromNBT((NBTTagCompound) NBTJson.toNbt(elem)); + + if (stack == null) { + return null; + } + + ingredients.add(stack); + } + + return ingredients; + } + + protected JsonArray convertIngredientsToJsonArray(List ingredients) + { + JsonArray arr = new JsonArray(); + + for (ItemStack stack : ingredients) { + final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack); + + if (nbTag == null) { + return null; + } + + arr.add(NBTJson.toJsonObject(nbTag)); + } + + return arr; + } + +} diff --git a/src/codechicken/nei/recipe/GuiCraftingRecipe.java b/src/codechicken/nei/recipe/GuiCraftingRecipe.java index 9526898e..75977e3e 100644 --- a/src/codechicken/nei/recipe/GuiCraftingRecipe.java +++ b/src/codechicken/nei/recipe/GuiCraftingRecipe.java @@ -6,6 +6,8 @@ import codechicken.nei.NEIClientConfig; import codechicken.nei.NEIClientUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.item.ItemStack; +import codechicken.nei.ItemPanels; import java.util.ArrayList; import java.util.concurrent.ExecutionException; @@ -46,9 +48,19 @@ public class GuiCraftingRecipe extends GuiRecipe handlers.sort(NEIClientConfig.HANDLER_COMPARATOR); mc.displayGuiScreen(new GuiCraftingRecipe(prevscreen, handlers)); + + if (NEIClientConfig.saveCurrentRecipeInBookmarksEnabled() && !NEIClientUtils.shiftKey() && outputId.equals("item") && mc.currentScreen instanceof GuiRecipe) { + GuiCraftingRecipe.openTargetRecipe((GuiRecipe)mc.currentScreen, (ItemStack)results[0]); + } + return true; } + protected static void openTargetRecipe(GuiRecipe currentScreen, ItemStack stackover) + { + currentScreen.openTargetRecipe(ItemPanels.bookmarkPanel.getBookmarkRecipeId(stackover)); + } + private GuiCraftingRecipe(GuiScreen prevgui, ArrayList handlers) { super(prevgui); currenthandlers = handlers; diff --git a/src/codechicken/nei/recipe/GuiRecipe.java b/src/codechicken/nei/recipe/GuiRecipe.java index 022ff6b0..f6f562a7 100644 --- a/src/codechicken/nei/recipe/GuiRecipe.java +++ b/src/codechicken/nei/recipe/GuiRecipe.java @@ -18,13 +18,16 @@ import codechicken.nei.guihook.GuiContainerManager; import codechicken.nei.guihook.IContainerTooltipHandler; import codechicken.nei.guihook.IGuiClientSide; import codechicken.nei.guihook.IGuiHandleMouseWheel; +import codechicken.nei.recipe.StackInfo; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; +import net.minecraft.item.Item; import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.GL11; @@ -193,20 +196,98 @@ public abstract class GuiRecipe extends GuiContainer implements IGuiContainerOve yShift = handlerInfo == null ? 0 : handlerInfo.getYShift(); } - public void setRecipePage(int idx) { + setRecipePage(idx, 0); + } + + public void setRecipePage(int idx, int position) { recipetype = idx; if (recipetype < 0) recipetype = currenthandlers.size() - 1; else if (recipetype >= currenthandlers.size()) recipetype = 0; handler = currenthandlers.get(recipetype); handlerInfo = getHandlerInfo(handler); - page = 0; + page = Math.min(Math.max(0, position), handler.numRecipes() - 1) / getRecipesPerPage(); recipeTabs.calcPageNumber(); checkYShift(); initOverlayButtons(); } + public void openTargetRecipe(BookmarkRecipeId recipeId) + { + + if (recipeId == null) { + return; + } + + if (recipeId.recipetype == -1 || recipeId.position == -1) { + recipeId.recipetype = 0; + recipeId.position = 0; + + if (recipeId.handlerName != null) { + + for (int j = 0; j < currenthandlers.size(); j++) { + IRecipeHandler localHandler = currenthandlers.get(j); + HandlerInfo localHandlerInfo = getHandlerInfo(localHandler); + + if (localHandlerInfo.getHandlerName().equals(recipeId.handlerName)) { + recipeId.recipetype = j; + + if (!recipeId.ingredients.isEmpty()) { + for (int i = 0; i < localHandler.numRecipes(); i++) { + + if (recipeId.equalsIngredients(localHandler.getIngredientStacks(i))) { + recipeId.position = i; + break; + } + + } + } + + break; + } + + } + + } + + } + + setRecipePage(recipeId.recipetype, recipeId.position); + } + + public BookmarkRecipeId getFocusedRecipeId() + { + String handlerName = handlerInfo.getHandlerName(); + Point mousePos = GuiDraw.getMousePosition(); + int recipesPerPage = getRecipesPerPage(); + + for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) { + if (recipeInFocus(i)) { + return new BookmarkRecipeId(handlerName, handler.getIngredientStacks(i), recipetype, i); + } + } + + return null; + } + + protected Boolean recipeInFocus(int idx) + { + PositionedStack result = handler.getResultStack(idx); + if (result != null && isMouseOver(result, idx)) { + return true; + } + + List stacks = handler.getOtherStacks(idx); + for (PositionedStack stack : stacks) { + if (isMouseOver(stack, idx)) { + return true; + } + } + + return false; + } + public IRecipeHandler getHandler() { return handler; } @@ -219,7 +300,6 @@ public abstract class GuiRecipe extends GuiContainer implements IGuiContainerOve return IntStream.range(minIndex, maxIndex).boxed().collect(Collectors.toList()); } - @Override public void keyTyped(char c, int i) { if (i == Keyboard.KEY_ESCAPE) //esc @@ -579,8 +659,12 @@ public abstract class GuiRecipe extends GuiContainer implements IGuiContainerOve return false; } } - + private int getRecipesPerPage() { + return getRecipesPerPage(handlerInfo); + } + + private int getRecipesPerPage(HandlerInfo handlerInfo) { if(handlerInfo != null) return Math.max(Math.min(((ySize - (buttonHeight*3)) / handlerInfo.getHeight()), handlerInfo.getMaxRecipesPerPage()), 1); else diff --git a/src/codechicken/nei/recipe/RecipeInfo.java b/src/codechicken/nei/recipe/RecipeInfo.java index eef9fde7..08ea2979 100644 --- a/src/codechicken/nei/recipe/RecipeInfo.java +++ b/src/codechicken/nei/recipe/RecipeInfo.java @@ -119,5 +119,8 @@ public class RecipeInfo API.registerRecipeHandler(new ProfilerRecipeHandler(true)); API.registerUsageHandler(new ProfilerRecipeHandler(false)); + + API.registerStackStringifyHandler(new StackStringifyHandler()); } + } diff --git a/src/codechicken/nei/recipe/RecipeItemInputHandler.java b/src/codechicken/nei/recipe/RecipeItemInputHandler.java index 094d0f15..77f359f8 100644 --- a/src/codechicken/nei/recipe/RecipeItemInputHandler.java +++ b/src/codechicken/nei/recipe/RecipeItemInputHandler.java @@ -25,7 +25,12 @@ public class RecipeItemInputHandler implements IContainerInputHandler if(keyCode == NEIClientConfig.getKeyBinding("gui.bookmark")) { NEIClientConfig.logger.debug("Adding or removing {} from bookmarks", stackover.getDisplayName()); - ItemPanels.bookmarkPanel.addOrRemoveItem(stackover.copy()); + BookmarkRecipeId recipeId = null; + + if (gui instanceof GuiRecipe && NEIClientConfig.saveCurrentRecipeInBookmarksEnabled()) + recipeId = ((GuiRecipe)gui).getFocusedRecipeId(); + + ItemPanels.bookmarkPanel.addOrRemoveItem(stackover.copy(), recipeId); } return false; @@ -42,27 +47,32 @@ public class RecipeItemInputHandler implements IContainerInputHandler if (!(gui instanceof GuiRecipe)) return false; + //disabled open recipe gui if hold shift (player have move recipe) + if (button == 0 && ItemPanels.bookmarkPanel.getStackMouseOver(mousex, mousey) != null && NEIClientUtils.shiftKey()) { + return false; + } + if(button == 0) return GuiCraftingRecipe.openRecipeGui("item", stackover.copy()); if(button == 1) return GuiUsageRecipe.openRecipeGui("item", stackover.copy()); - + return false; } @Override - public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) + public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) { } @Override - public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) + public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) { } @Override - public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) + public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) { } @@ -71,18 +81,18 @@ public class RecipeItemInputHandler implements IContainerInputHandler { return false; } - + @Override public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) { return false; } - + @Override public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) { } - + @Override public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) { diff --git a/src/codechicken/nei/recipe/StackInfo.java b/src/codechicken/nei/recipe/StackInfo.java new file mode 100644 index 00000000..c4edbe61 --- /dev/null +++ b/src/codechicken/nei/recipe/StackInfo.java @@ -0,0 +1,59 @@ +package codechicken.nei.recipe; + +import codechicken.nei.api.IStackStringifyHandler; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import java.util.ArrayList; + +public class StackInfo +{ + + public static final ArrayList stackStringifyHandlers = new ArrayList<>(); + + public static NBTTagCompound itemStackToNBT(ItemStack stack) + { + NBTTagCompound nbTag = null; + ItemStack[] stacks = new ItemStack[]{stack}; + + for (int i = stackStringifyHandlers.size() - 1; i >= 0 && nbTag == null; i--) { + nbTag = stackStringifyHandlers.get(i).convertItemStackToNBT(stacks); + } + + return nbTag; + } + + public static ItemStack loadFromNBT(NBTTagCompound nbtTag) + { + ItemStack stack = null; + + for (int i = stackStringifyHandlers.size() - 1; i >= 0 && stack == null; i--) { + stack = stackStringifyHandlers.get(i).convertNBTToItemStack(nbtTag); + } + + return stack; + } + + public static ItemStack normalize(ItemStack item) { + ItemStack copy = null; + + for (int i = stackStringifyHandlers.size() - 1; i >= 0 && copy == null; i--) { + copy = stackStringifyHandlers.get(i).normalize(item); + } + + return copy; + } + + public static boolean equalItemAndNBT(ItemStack stackA, ItemStack stackB, boolean useNBT) + { + if (stackA.isItemEqual(stackB)) { + NBTTagCompound tagCompoundA = stackA.getTagCompound(); + NBTTagCompound tagCompoundB = stackB.getTagCompound(); + + return !useNBT || (tagCompoundA == null && tagCompoundB == null) || (tagCompoundA != null && tagCompoundB != null && tagCompoundA.equals(tagCompoundB)); + } + + return false; + } + +} diff --git a/src/codechicken/nei/recipe/StackStringifyHandler.java b/src/codechicken/nei/recipe/StackStringifyHandler.java new file mode 100644 index 00000000..8fca7a33 --- /dev/null +++ b/src/codechicken/nei/recipe/StackStringifyHandler.java @@ -0,0 +1,69 @@ +package codechicken.nei.recipe; + +import codechicken.nei.api.IStackStringifyHandler; +import cpw.mods.fml.common.registry.GameData; +import net.minecraft.nbt.NBTTagCompound; +import codechicken.nei.NEIClientConfig; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Item; + +public class StackStringifyHandler implements IStackStringifyHandler +{ + + public NBTTagCompound convertItemStackToNBT(ItemStack[] stacks) + { + ItemStack stack = getItemStackWithMinimumDamage(stacks); + NBTTagCompound nbTag = new NBTTagCompound(); + String strId = Item.itemRegistry.getNameForObject(stack.getItem()); + + nbTag.setString("strId", strId); + nbTag.setShort("Damage", (short)stack.getItemDamage()); + + if (stack.hasTagCompound()) { + nbTag.setTag("tag", stack.getTagCompound()); + } + + return nbTag; + } + + public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) + { + + if (!nbtTag.hasKey("strId")) { + return null; + } + + String strId = nbtTag.getString("strId"); + + nbtTag = (NBTTagCompound)nbtTag.copy(); + nbtTag.setByte("Count", (byte)1); + nbtTag.setShort("id", (short)GameData.getItemRegistry().getId(strId)); + + return ItemStack.loadItemStackFromNBT(nbtTag); + } + + public ItemStack normalize(ItemStack item) + { + ItemStack copy = item.copy(); + copy.stackSize = 1; + return copy; + } + + protected static ItemStack getItemStackWithMinimumDamage(ItemStack[] stacks) + { + int damage = Short.MAX_VALUE; + ItemStack result = stacks[0]; + + if (stacks.length > 1) { + for (ItemStack stack : stacks) { + if (stack.getItemDamage() < damage) { + damage = stack.getItemDamage(); + result = stack; + } + } + } + + return result; + } + +} \ No newline at end of file diff --git a/src/codechicken/nei/util/NBTJson.java b/src/codechicken/nei/util/NBTJson.java index c3e407fd..b734264d 100644 --- a/src/codechicken/nei/util/NBTJson.java +++ b/src/codechicken/nei/util/NBTJson.java @@ -34,7 +34,11 @@ public class NBTJson { private static final Gson gson = new GsonBuilder().create(); public static String toJson(NBTTagCompound tag) { - final String jsonString = toJsonObject(tag).toString(); + return toJson(toJsonObject(tag)); + } + + public static String toJson(JsonElement json) { + final String jsonString = json.toString(); return gson.toJson(parser.parse(jsonString)); } @@ -50,6 +54,24 @@ public class NBTJson { root.add(nbtEntry.getKey(), toJsonObject(nbtEntry.getValue())); } return root; + } else if (nbt instanceof NBTTagByte) { + // Number (byte) + return new JsonPrimitive(Byte.toString(((NBTTagByte) nbt).func_150290_f()) + 'B'); + } else if (nbt instanceof NBTTagShort) { + // Number (short) + return new JsonPrimitive(Short.toString(((NBTTagShort) nbt).func_150289_e()) + 'S'); + } else if (nbt instanceof NBTTagInt) { + // Number (int) + return new JsonPrimitive(((NBTTagInt) nbt).func_150287_d()); + } else if (nbt instanceof NBTTagLong) { + // Number (long) + return new JsonPrimitive(Long.toString(((NBTTagLong) nbt).func_150291_c()) + 'L'); + } else if (nbt instanceof NBTTagFloat) { + // Number (float) + return new JsonPrimitive(Float.toString(((NBTTagFloat) nbt).func_150288_h()) + 'F'); + } else if (nbt instanceof NBTTagDouble) { + // Number (double) + return new JsonPrimitive(Double.toString(((NBTTagDouble) nbt).func_150286_g()) + 'D'); } else if (nbt instanceof NBTBase.NBTPrimitive) { // Number return new JsonPrimitive(((NBTBase.NBTPrimitive) nbt).func_150286_g());