Compare commits

...
17 Commits
Author SHA1 Message Date
Dream Master 43c12cd5c8 Merge remote-tracking branch 'slprime/recipeid_command' into dev 2025-08-08 19:07:52 +07:00
Dream Master 2c3f2cf5ec Merge remote-tracking branch 'slprime/items_loading' into dev 2025-08-08 19:07:40 +07:00
Dream Master 0714c185a3 Merge remote-tracking branch 'slprime/panel_positions' into dev 2025-08-08 19:07:23 +07:00
Dream Master 03c84a5e16 Merge remote-tracking branch 'slprime/chain_custom_values' into dev 2025-08-08 19:07:09 +07:00
Dream Master 6f3ae8b464 Merge remote-tracking branch 'slprime/favorite_hotkey' into dev 2025-08-08 19:06:50 +07:00
Dream Master 897b7ca60e Merge remote-tracking branch 'slprime/hotkeys_option' into dev 2025-08-08 19:06:30 +07:00
Dream Master 679ed6dd53 Merge remote-tracking branch 'slprime/custom_subsets' into dev 2025-08-08 19:06:13 +07:00
slprime d5c3552a9a optimization; command translations; recipeid ingr sorting 2025-08-06 13:37:54 +03:00
slprime 167d6fdec5 restore ctrl modifier 2025-08-03 21:55:11 +03:00
slprime 080e49e2bb Optimization 2025-08-02 22:56:03 +03:00
slprime 85d6247e13 Custom Subsets in config; RecipeId Command 2025-08-02 19:02:33 +03:00
slprime 06e72d4f2a Loading items after the player to ensure the hint cache works correctly in some mods 2025-07-29 20:25:14 +03:00
slprime a0c5afdbd4 Change panel position algorithm 2025-07-26 11:46:04 +03:00
slprime 983e921f04 Add the ability to create a chain of items with zero 2025-07-26 11:07:06 +03:00
slprime b207292894 Add Favorite Hotkey 2025-07-26 01:26:41 +03:00
slprime 4c58e88577 Add OPtion to Disable Hotkeys Tooltip 2025-07-26 00:07:46 +03:00
slprime b1178879c7 Presets: Custom Subsets Mode 2025-07-12 21:45:11 +03:00
34 changed files with 773 additions and 157 deletions

No files matched your search

@@ -207,11 +207,11 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
return false;
}
public boolean addRecipe(Recipe recipe, int groupId) {
public boolean addRecipe(Recipe recipe, int multiplier, int groupId) {
final RecipeId recipeId = recipe.getRecipeId();
if (recipe != null && this.grid.getGroup(groupId) != null && !this.grid.existsRecipe(recipeId, groupId)) {
this.grid.addRecipe(recipe, groupId);
this.grid.addRecipe(recipe, multiplier, groupId);
return true;
}
@@ -234,7 +234,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (item instanceof Recipe recipe) {
if (uniqueRecipe.add(recipe.getRecipeId())) {
this.grid.addRecipe(recipe, groupId);
this.grid.addRecipe(recipe, 1, groupId);
}
} else if (item instanceof RecipeId recipeId) {
@@ -305,18 +305,20 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
final RecipeId recipeId = slot.getRecipeId();
final BookmarkGroup group = slot.getGroup();
if (recipeId == null || !removeFullRecipe) {
this.grid.removeRecipe(slot.itemIndex, removeFullRecipe);
if (group.crafting != null && group.collapsed) {
if (!removeFullRecipe) {
return true;
}
this.grid.removeGroup(groupId);
return true;
}
if (group.crafting != null && group.collapsed && removeFullRecipe) {
this.grid.removeGroup(groupId);
return true;
} else if (group.crafting != null) {
if (recipeId != null && group.crafting != null) {
Set<RecipeId> recipes = group.crafting.recipeRelations.getOrDefault(recipeId, Collections.emptySet());
if (removeFullRecipe && recipes.isEmpty()) {
if (recipes.isEmpty()) {
for (Map.Entry<RecipeId, Set<RecipeId>> entry : group.crafting.recipeRelations.entrySet()) {
if (entry.getValue().contains(recipeId)) {
recipes = entry.getValue();
@@ -326,8 +328,12 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
if (!recipes.isEmpty()) {
boolean removed = false;
if (!removeFullRecipe) {
return true;
}
boolean removed = false;
for (RecipeId relRecipeId : recipes) {
removed = this.grid.removeRecipe(relRecipeId, groupId) || removed;
}
@@ -336,6 +342,11 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
}
if (recipeId == null || !removeFullRecipe) {
this.grid.removeRecipe(slot.itemIndex, removeFullRecipe);
return true;
}
return this.grid.removeRecipe(recipeId, groupId);
}
@@ -435,7 +446,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
protected int resizeHeader(GuiContainer gui) {
final LayoutStyleMinecraft layout = (LayoutStyleMinecraft) LayoutManager.getLayoutStyle();
final int rows = (int) Math.ceil((double) layout.buttonCount / layout.numButtons);
final int diff = rows * 19 + getMarginTop(gui) - y;
final int diff = rows * 19 + PADDING - y;
if (diff > 0) {
y += diff;
@@ -493,24 +504,31 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
}
protected String getPositioningSettingName() {
return "world.panels.bookmarks";
}
public Rectangle4i calculateBounds() {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final int width = (gui.width - gui.xSize) / 2 - PADDING * 2;
final Rectangle4i bounds = new Rectangle4i(
PADDING,
PADDING,
(gui.width - 176) / 2 - PADDING * 2,
gui.height - PADDING * 2);
public int getMarginLeft(GuiContainer gui) {
return PADDING;
}
int paddingLeft = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.bookmarks.left").getIntValue() / 100000.0);
int paddingTop = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.bookmarks.top").getIntValue() / 100000.0);
int paddingRight = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.bookmarks.right").getIntValue() / 100000.0);
int paddingBottom = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.bookmarks.bottom").getIntValue() / 100000.0);
public int getMarginTop(GuiContainer gui) {
return PADDING;
}
bounds.h = Math.max(ItemsGrid.SLOT_SIZE, bounds.h - paddingTop - paddingBottom);
bounds.y = bounds.y + Math.min(paddingTop, bounds.h - ItemsGrid.SLOT_SIZE);
public int getWidth(GuiContainer gui) {
return gui.width - (gui.xSize + gui.width) / 2 - PADDING * 2;
}
bounds.w = Math.max(ItemsGrid.SLOT_SIZE, Math.min(bounds.w - paddingLeft - paddingRight, width - paddingLeft));
bounds.x = bounds.x + Math.min(paddingLeft, bounds.w - ItemsGrid.SLOT_SIZE);
public int getHeight(GuiContainer gui) {
return gui.height - getMarginTop(gui) - PADDING;
return bounds;
}
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
@@ -1195,7 +1213,10 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
&& !handlerName.isEmpty()
&& ingredients != null
&& !ingredients.isEmpty()) {
addRecipe(Recipe.of(Arrays.asList(stack), handlerName, ingredients), BookmarkGrid.DEFAULT_GROUP_ID);
addRecipe(
Recipe.of(Arrays.asList(stack), handlerName, ingredients),
saveSize ? 1 : 0,
BookmarkGrid.DEFAULT_GROUP_ID);
} else {
addItem(stack, saveSize);
}
@@ -1209,7 +1230,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
@Deprecated
public void addRecipe(BookmarkRecipe recipe, boolean saveSize, int groupId) {
addRecipe(recipe.getRecipe(), groupId);
addRecipe(recipe.getRecipe(), saveSize ? 1 : 0, groupId);
}
@Deprecated
@@ -244,7 +244,7 @@ public class FavoriteRecipes {
try (FileOutputStream output = new FileOutputStream(favoriteFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save favorites list to file {}", favoriteFile, e);
NEIClientConfig.logger.error("Failed to save favorites list to file {}", favoriteFile, e);
}
}
+1 -1
View File
@@ -293,7 +293,7 @@ public class ItemList {
@Override
@SuppressWarnings("unchecked")
public void execute() {
if (!NEIClientConfig.isEnabled()) return;
if (!NEIClientConfig.isEnabled() || NEIClientUtils.mc().thePlayer == null) return;
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
LayoutManager.itemsLoaded = true;
+22 -14
View File
@@ -8,6 +8,7 @@ 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.ItemsPanelGrid.ItemsPanelGridSlot;
import codechicken.nei.util.NEIMouseUtils;
@@ -108,24 +109,31 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
}
protected String getPositioningSettingName() {
return "world.panels.items";
}
public Rectangle4i calculateBounds() {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final int width = (gui.width - gui.xSize) / 2 - PADDING * 2;
final Rectangle4i bounds = new Rectangle4i(
(gui.width + gui.xSize) / 2 + PADDING,
PADDING,
(gui.width - 176) / 2 - PADDING * 2,
gui.height - PADDING * 2);
public int getMarginLeft(GuiContainer gui) {
return (gui.width + gui.xSize) / 2 + PADDING;
}
int paddingLeft = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.items.left").getIntValue() / 100000.0);
int paddingTop = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.items.top").getIntValue() / 100000.0);
int paddingRight = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.items.right").getIntValue() / 100000.0);
int paddingBottom = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.items.bottom").getIntValue() / 100000.0);
public int getMarginTop(GuiContainer gui) {
return PADDING;
}
bounds.h = Math.max(ItemsGrid.SLOT_SIZE, bounds.h - paddingTop - paddingBottom);
bounds.y = bounds.y + Math.min(paddingTop, bounds.h - ItemsGrid.SLOT_SIZE);
public int getWidth(GuiContainer gui) {
return gui.width - (gui.xSize + gui.width) / 2 - PADDING * 2;
}
bounds.w = Math.max(ItemsGrid.SLOT_SIZE, Math.min(bounds.w - paddingLeft - paddingRight, width - paddingRight));
bounds.x = bounds.x + Math.max(0, width - bounds.w - paddingRight);
public int getHeight(GuiContainer gui) {
return gui.height - getMarginTop(gui) - PADDING;
return bounds;
}
@Override
@@ -4,6 +4,8 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;
import org.lwjgl.input.Keyboard;
/**
* Good old down/held/up keystate tracker
*/
@@ -26,7 +28,7 @@ public class KeyManager {
public static void tickKeyStates() {
for (Entry<String, KeyState> entry : keyStates.entrySet()) {
final boolean down = NEIClientConfig.isKeyHashDown(entry.getKey());
final boolean down = Keyboard.isKeyDown(NEIClientConfig.getKeyBinding(entry.getKey()));
final KeyState state = entry.getValue();
if (down) {
@@ -52,7 +52,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
public void layout(GuiContainer gui, VisiblityData visiblity) {
reset();
leftSize = ItemPanels.bookmarkPanel.getWidth(gui);
leftSize = (gui.width - gui.xSize) / 2 - 4;
numButtons = Math.max(leftSize / 20, 1);
LayoutManager.delete.state = 0x4;
@@ -390,6 +390,8 @@ public class NEIClientConfig {
});
tag.getTag("inventory.hotkeysHelpText").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.hotkeysHelpText", true));
tag.getTag("inventory.showHotkeys").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.showHotkeys", true));
tag.getTag("loadPluginsInParallel").getBooleanValue(true);
tag.getTag("itemLoadingTimeout").getIntValue(500);
@@ -743,6 +745,7 @@ public class NEIClientConfig {
API.addHashBind("gui.hide", Keyboard.KEY_O);
API.addHashBind("gui.search", Keyboard.KEY_F);
API.addKeyBind("gui.bookmark", Keyboard.KEY_A);
API.addHashBind("gui.favorite", Keyboard.KEY_F + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.remove_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.bookmark_pull_items", Keyboard.KEY_V);
API.addKeyBind("gui.overlay", Keyboard.KEY_S);
@@ -857,7 +860,7 @@ public class NEIClientConfig {
final int hash = getKeyBinding(string);
if (hash != Keyboard.CHAR_NONE && Keyboard.getEventKeyState()) {
return KeyManager.keyStates.containsKey(string) ? hash == Keyboard.getEventKey()
return KeyManager.keyStates.containsKey(string) ? Keyboard.isKeyDown(hash)
: hash == NEIClientUtils.getKeyHash();
}
@@ -921,6 +924,7 @@ public class NEIClientConfig {
});
RecipeCatalysts.loadCatalystInfo();
SubsetWidget.loadCustomSubsets();
SubsetWidget.loadHidden();
CollapsibleItems.load();
ItemSorter.loadConfig();
@@ -20,6 +20,7 @@ import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.commands.CommandBookmarkAdd;
import codechicken.nei.commands.CommandRecipeId;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerSlotClickHandler;
@@ -66,6 +67,7 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
@SideOnly(Side.CLIENT)
public static void registerClientCommands() {
ClientCommandHandler.instance.registerCommand(new CommandBookmarkAdd());
ClientCommandHandler.instance.registerCommand(new CommandRecipeId());
}
public static void updateUnlimitedItems(InventoryPlayer inventory) {
+6 -35
View File
@@ -84,44 +84,15 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
public abstract String getLabelText();
protected abstract String getPositioningSettingName();
public abstract int getMarginLeft(GuiContainer gui);
public abstract int getMarginTop(GuiContainer gui);
public abstract int getWidth(GuiContainer gui);
public abstract int getHeight(GuiContainer gui);
public abstract Rectangle4i calculateBounds();
public void resize(GuiContainer gui) {
final Rectangle4i margin = new Rectangle4i(
getMarginLeft(gui),
getMarginTop(gui),
getWidth(gui),
getHeight(gui));
final Rectangle4i bounds = calculateBounds();
final String settingName = getPositioningSettingName();
int paddingLeft = (int) Math
.ceil(margin.w * NEIClientConfig.getSetting(settingName + ".left").getIntValue() / 100000.0);
int paddingTop = (int) Math
.ceil(margin.h * NEIClientConfig.getSetting(settingName + ".top").getIntValue() / 100000.0);
int paddingRight = (int) Math
.ceil(margin.w * NEIClientConfig.getSetting(settingName + ".right").getIntValue() / 100000.0);
int paddingBottom = (int) Math
.ceil(margin.h * NEIClientConfig.getSetting(settingName + ".bottom").getIntValue() / 100000.0);
int deltaHeight = Math.min(0, margin.h - paddingTop - paddingBottom - ItemsGrid.SLOT_SIZE) / 2;
paddingLeft = Math.min(paddingLeft, Math.max(0, margin.w - paddingRight - ItemsGrid.SLOT_SIZE));
paddingRight = Math.min(paddingRight, Math.max(0, margin.w - paddingLeft - ItemsGrid.SLOT_SIZE));
paddingTop = Math.min(margin.h - ItemsGrid.SLOT_SIZE, Math.max(0, paddingTop + deltaHeight));
paddingBottom = Math.min(margin.h - paddingTop - ItemsGrid.SLOT_SIZE, Math.max(0, paddingBottom - deltaHeight));
x = margin.x + paddingLeft;
y = margin.y + paddingTop;
w = margin.w - paddingLeft - paddingRight;
h = margin.h - paddingTop - paddingBottom;
x = bounds.x;
y = bounds.y;
w = bounds.w;
h = bounds.h;
final int header = resizeHeader(gui);
final int footer = resizeFooter(gui);
+20 -1
View File
@@ -21,6 +21,7 @@ import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.SubsetWidget.SubsetTag;
import codechicken.nei.api.API;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
@@ -33,6 +34,7 @@ import codechicken.nei.util.NBTJson;
public class PresetsList {
public enum PresetMode {
SUBSET,
HIDE,
REMOVE,
GROUP;
@@ -216,6 +218,8 @@ public class PresetsList {
if (!preset.items.isEmpty()) {
presets.add(preset);
}
updateSubsets();
}
public static void savePresets() {
@@ -236,14 +240,29 @@ public class PresetsList {
try (FileOutputStream output = new FileOutputStream(presetsFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets list to file {}", presetsFile, e);
NEIClientConfig.logger.error("Failed to save presets list to file {}", presetsFile, e);
}
recipeFilter.cache = null;
itemFilter.cache = null;
updateSubsets();
CollapsibleItems.saveStates();
CollapsibleItems.load();
LayoutManager.markItemsDirty();
}
private static void updateSubsets() {
SubsetWidget.removeTag("Presets");
for (Preset preset : PresetsList.presets) {
if (preset.enabled && preset.mode == PresetMode.SUBSET) {
SubsetWidget.addTag(
new SubsetTag(
"Presets." + preset.name,
stack -> preset.items.contains(Preset.getIdentifier(stack))));
}
}
}
}
@@ -1,6 +1,7 @@
package codechicken.nei;
import java.awt.Point;
import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
@@ -13,6 +14,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
@@ -23,6 +25,9 @@ import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import codechicken.core.gui.GuiScrollSlot;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
@@ -35,6 +40,12 @@ import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
import codechicken.nei.util.NEIMouseUtils;
public class SubsetWidget extends Button implements ItemFilterProvider, IContainerTooltipHandler {
@@ -415,6 +426,17 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
}
}
public static void removeTag(String path) {
updateState.stop();
synchronized (tags) {
tags.keySet().removeIf(
parentpath -> parentpath.equals(path.toLowerCase())
|| parentpath.startsWith(path.toLowerCase() + "."));
updateHiddenItems();
}
}
public static boolean isHidden(ItemStack item) {
try {
if (hiddenReadLock.tryLock(5, TimeUnit.SECONDS)) {
@@ -535,6 +557,60 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
}
}
public static void loadCustomSubsets() {
File dir = new File(NEIClientConfig.configDir, "subsets");
if (!dir.exists() || !dir.isDirectory()) {
return;
}
Stream.of(dir.listFiles()).filter(file -> !file.isDirectory()).forEach(file -> {
ClientHandler.loadSettingsFile(
"subsets/" + file.getName(),
lines -> parseFile(file.getName(), lines.collect(Collectors.toList())));
});
}
private static void parseFile(String resource, List<String> itemStrings) {
final JsonParser parser = new JsonParser();
final String subsetNamespace = resource.substring(0, resource.lastIndexOf('.'));
SubsetTag processedTag = new SubsetTag(subsetNamespace, new ItemStackSet());
for (String itemStr : itemStrings) {
try {
if (itemStr.startsWith("; ")) {
final String handlerName = itemStr.substring(2);
String recipeName = handlerName;
addTag(processedTag);
IRecipeHandler recipeHandler = GuiCraftingRecipe.craftinghandlers.stream()
.filter(handler -> handlerName.equals(getHandlerName(handler))).findAny().orElse(null);
if (recipeHandler == null) {
recipeHandler = GuiCraftingRecipe.serialCraftingHandlers.stream()
.filter(handler -> handlerName.equals(getHandlerName(handler))).findAny().orElse(null);
}
if (recipeHandler != null) {
recipeName = recipeHandler.getRecipeName().trim();
}
processedTag = new SubsetTag(
subsetNamespace + "." + recipeName.replace(".", ""),
new ItemStackSet());
} else {
((ItemStackSet) processedTag.filter)
.add(StackInfo.loadFromNBT((NBTTagCompound) NBTJson.toNbt(parser.parse(itemStr))));
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load collapsible items from json string:\n{}", itemStr);
}
}
}
private static String getHandlerName(ICraftingHandler handler) {
return GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
}
public static void loadHidden() {
final List<ItemStack> itemList = new LinkedList<>();
@@ -24,10 +24,12 @@ import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.SearchField;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkGroup;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiFavoriteButton;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.Recipe;
@@ -112,6 +114,10 @@ public abstract class ShortcutInputHandler {
return GuiUsageRecipe.openRecipeGui("item", stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.favorite")) {
return saveFavoriteTree(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark")) {
return saveRecipeInBookmark(stackover, NEIClientUtils.shiftKey(), NEIClientUtils.controlKey());
}
@@ -247,6 +253,25 @@ public abstract class ShortcutInputHandler {
return false;
}
private static boolean saveFavoriteTree(ItemStack stackover) {
final Point mouse = GuiDraw.getMousePosition();
if (ItemPanels.itemPanel.contains(mouse.x, mouse.y)
|| ItemPanels.itemPanel.historyPanel.contains(mouse.x, mouse.y)) {
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(FavoriteRecipes.getFavorite(stackover));
if (handlerRef != null) {
final GuiFavoriteButton button = new GuiFavoriteButton(handlerRef, 0, 0);
button.saveRecipeInBookmark();
return true;
}
return true;
}
return false;
}
private static boolean saveRecipeInBookmark(ItemStack stackover, boolean saveIngredients, boolean saveStackSize) {
final Point mousePos = GuiDraw.getMousePosition();
@@ -262,7 +287,8 @@ public abstract class ShortcutInputHandler {
recipe.getIngredients());
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
ItemPanels.bookmarkPanel.addRecipe(singleRecipe, BookmarkGrid.DEFAULT_GROUP_ID);
ItemPanels.bookmarkPanel
.addRecipe(singleRecipe, saveStackSize ? 1 : 0, BookmarkGrid.DEFAULT_GROUP_ID);
}
} else {
@@ -378,15 +404,56 @@ public abstract class ShortcutInputHandler {
final RecipeId recipeId = getHotkeyRecipeId(gui, mousex, mousey, stack, slot);
if (slot != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate(slot.isIngredient() ? "bookmark.remove_item" : "bookmark.remove_recipe"));
final BookmarkGroup group = slot.getGroup();
if (slot.isIngredient()) {
if (group.crafting != null && group.collapsed) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
}
NEIClientUtils.translate("bookmark.group.remove_recipe"));
} else if (slot.getRecipeId() == null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
} else if (group.crafting != null && group.crafting.recipeRelations.entrySet().stream().anyMatch(
entry -> entry.getKey().equals(slot.getRecipeId())
|| entry.getValue().contains(slot.getRecipeId()))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
if (slot.isIngredient()) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
final BookmarkItem item = slot.getBookmarkItem();
if (ItemPanels.bookmarkPanel.getGrid().createChainItems(groupId).values().stream()
.noneMatch(
m -> !m.isIngredient && !m.equals(item) && item.equalsRecipe(m))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
}
}
}
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
@@ -407,11 +474,22 @@ public abstract class ShortcutInputHandler {
}
if (recipeId != null) {
hotkeys.put(
NEIClientConfig
.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe_and_count"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe"));
}
if ((ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) && FavoriteRecipes.contains(stack)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.favorite"),
NEIClientUtils.translate("recipe.favorite.bookmark_recipe"));
}
}
hotkeys.put(NEIClientConfig.getKeyName("gui.recipe"), NEIClientUtils.translate("itempanel.open_crafting"));
@@ -866,7 +866,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
onItemsChanged();
}
public void addRecipe(Recipe recipe, int groupId) {
public void addRecipe(Recipe recipe, int multiplier, int groupId) {
final RecipeId recipeId = recipe.getRecipeId();
final List<ItemStack> results = recipe.getResults().stream().map(res -> res.getItemStack())
.collect(Collectors.toList());
@@ -874,15 +874,19 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
.collect(Collectors.toList());
for (ItemStack stack : ItemStackAmount.of(results).values()) {
this.addItem(BookmarkItem.of(groupId, stack, StackInfo.getAmount(stack), recipeId, false), true);
long factor = StackInfo.getAmount(stack);
this.addItem(
BookmarkItem.of(groupId, StackInfo.withAmount(stack, factor * multiplier), factor, recipeId, false),
true);
}
for (ItemStack stack : ItemStackAmount.of(ingredients).values()) {
long factor = StackInfo.getAmount(stack);
this.addItem(
BookmarkItem.of(
groupId,
stack,
StackInfo.getAmount(stack),
StackInfo.withAmount(stack, factor * multiplier),
factor,
recipeId,
true,
BookmarkItem.generatePermutations(stack, recipe)),
@@ -904,7 +908,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (item.recipeId != null && removeFullRecipe) {
removeRecipe(item.recipeId, item.groupId);
} else {
} else if (itemIndex >= 0) {
this.bookmarkItems.remove(itemIndex);
onItemsChanged();
}
@@ -1116,16 +1120,16 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (item.factor > 0
&& outputRecipes.stream().anyMatch(recipeId -> item.equalsRecipe(recipeId, targetGroupId))) {
final long multiplier = recipeMultipliers.getOrDefault(item.recipeId, (long) Integer.MAX_VALUE);
final boolean isOutputRecipe = group.crafting != null
&& !group.crafting.recipeInMiddle.contains(item.recipeId);
final boolean recipeInMiddle = group.crafting != null
&& group.crafting.recipeInMiddle.contains(item.recipeId);
recipeMultipliers.put(
item.recipeId,
Math.min(
shiftMultiplier(
Math.max(isOutputRecipe ? 1 : 0, item.getMultiplier()),
Math.max(recipeInMiddle ? 1 : 0, item.getMultiplier()),
shift,
isOutputRecipe ? 1 : 0),
recipeInMiddle ? 1 : 0),
multiplier));
items.add(item);
}
@@ -1148,16 +1152,16 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
} else if (targetItem.recipeId != null) {
final RecipeId recipeId = this.gridGenerator.itemToRecipe
.getOrDefault(targetItemIndex, targetItem.recipeId);
final boolean isOutputRecipe = group.crafting != null && !group.crafting.recipeInMiddle.contains(recipeId);
final boolean recipeInMiddle = group.crafting != null && group.crafting.recipeInMiddle.contains(recipeId);
long multiplier = Integer.MAX_VALUE;
for (BookmarkItem item : this.bookmarkItems) {
if (item.equalsRecipe(recipeId, targetItem.groupId) && item.factor > 0) {
multiplier = Math.min(
shiftMultiplier(
Math.max(isOutputRecipe ? 1 : 0, item.getMultiplier()),
Math.max(recipeInMiddle ? 1 : 0, item.getMultiplier()),
shift,
isOutputRecipe ? 1 : 0),
recipeInMiddle ? 1 : 0),
multiplier);
}
}
@@ -359,7 +359,7 @@ public class BookmarkStorage {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
NEIClientConfig.world.nbt.setTag("bookmark", navigation);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save bookmarks list to file {}", bookmarkFile, e);
NEIClientConfig.logger.error("Failed to save bookmarks list to file {}", bookmarkFile, e);
}
}
@@ -179,9 +179,10 @@ public class RecipeChainDetails {
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
final BookmarkItem item = entry.getValue();
if (this.recipeInMiddle.contains(item.recipeId)) {
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
this.calculatedItems.get(itemIndex)
.setRealAmount(Math.max(0, item.factor * (item.getMultiplier() - 1)));
} else {
this.calculatedItems.get(itemIndex).setRealAmount(Math.max(item.factor, item.amount));
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
}
}
}
@@ -1,7 +1,6 @@
package codechicken.nei.commands;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
@@ -12,7 +11,7 @@ import net.minecraft.util.ChatComponentTranslation;
import codechicken.nei.ItemPanels;
public class CommandBookmarkAdd extends CommandBase implements ICommand {
public class CommandBookmarkAdd extends CommandBase {
@Override
public String getCommandName() {
@@ -0,0 +1,298 @@
package codechicken.nei.commands;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.ChatStyle;
import net.minecraft.util.EnumChatFormatting;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonParser;
import codechicken.core.CommonUtils;
import codechicken.nei.ClientHandler;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.RecipeHandlerQuery;
import codechicken.nei.util.NBTJson;
public class CommandRecipeId extends CommandBase {
protected static class ProcessDiffThread extends Thread {
protected final ICommandSender sender;
protected final File prevFile;
protected final File currFile;
protected final File diffFile;
public ProcessDiffThread(ICommandSender sender, File prevFile, File currFile, File diffFile) {
this.sender = sender;
this.prevFile = prevFile;
this.currFile = currFile;
this.diffFile = diffFile;
}
@Override
public void run() {
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.start");
final Set<String> prevRecipes = loadFileContent(this.prevFile);
final Set<String> currRecipes = loadFileContent(this.currFile);
final Set<String> notAllowedRecipes = prevRecipes.stream().filter(recipe -> !currRecipes.contains(recipe))
.collect(Collectors.toSet());
final List<String> subsetsList = new ArrayList<>();
for (Map.Entry<String, Set<String>> entry : generateSubsets(notAllowedRecipes).entrySet()) {
subsetsList.add("; " + entry.getKey());
subsetsList.addAll(entry.getValue());
}
saveFile(this.diffFile, subsetsList);
saveFile(getFile("not-allowed-recipes"), new ArrayList<>(notAllowedRecipes));
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.finish");
}
private Set<String> loadFileContent(File file) {
try (FileReader reader = new FileReader(file)) {
return new HashSet<>(IOUtils.readLines(reader));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load '{}' file {}", file.getName(), file, e);
}
return new HashSet<>();
}
private Map<String, Set<String>> generateSubsets(Set<String> notAllowedRecipes) {
final JsonParser parser = new JsonParser();
final Map<String, Set<String>> subsetsBuilder = new HashMap<>();
for (String recipeStr : notAllowedRecipes) {
try {
final NBTTagCompound nbtRecipe = (NBTTagCompound) NBTJson.toNbt(parser.parse(recipeStr));
if (nbtRecipe.hasKey("result")) {
final NBTTagCompound nbtStack = nbtRecipe.getCompoundTag("result");
nbtStack.removeTag("Count");
subsetsBuilder.computeIfAbsent(nbtRecipe.getString("handlerName"), rn -> new HashSet<>())
.add(NBTJson.toJson(nbtStack));
} else {
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr);
}
} catch (Exception ex) {
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr, ex);
}
}
return subsetsBuilder;
}
private void saveFile(File file, List<String> content) {
try (FileOutputStream output = new FileOutputStream(file)) {
IOUtils.writeLines(content, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save recipeid diff list to file {}", file, e);
}
}
}
protected static class ProcessDumpThread extends Thread {
private ArrayList<ICraftingHandler> craftinghandlers = new ArrayList<>();
private ArrayList<ICraftingHandler> serialCraftingHandlers = new ArrayList<>();
protected final ICommandSender sender;
protected final File currFile;
public ProcessDumpThread(ICommandSender sender, File currFile) {
this.sender = sender;
this.currFile = currFile;
ClientHandler.loadSettingsFile("recipeidblacklist.cfg", lines -> {
final Set<String> names = lines.collect(Collectors.toSet());
this.craftinghandlers = GuiCraftingRecipe.craftinghandlers.stream()
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
.collect(Collectors.toCollection(ArrayList::new));
this.serialCraftingHandlers = GuiCraftingRecipe.serialCraftingHandlers.stream()
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
.collect(Collectors.toCollection(ArrayList::new));
});
}
@Override
public void run() {
NEIClientConfig.logger.info("Start processing recipe handlers!");
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.start");
try {
if (!this.currFile.exists()) this.currFile.createNewFile();
final PrintWriter recipes = new PrintWriter(this.currFile);
int total = ItemList.items.size();
int count = 0;
for (ItemStack stack : ItemList.items) {
if ((count % 100) == 0) {
NEIClientConfig.logger.info(
"({}/{}). Processing {} crafting recipes...",
count++,
total,
stack.getDisplayName());
}
count++;
for (ICraftingHandler handler : getCraftingHandlers(stack)) {
for (int index = 0; index < handler.numRecipes(); index++) {
try {
final Recipe recipe = Recipe.of(handler, index);
if (recipe != null
&& (!recipe.getIngredients().isEmpty() && !recipe.getResults().isEmpty())) {
recipes.println(NBTJson.toJson(recipe.getRecipeId().toJsonObject()));
}
} catch (Exception ex) {
NEIClientConfig.logger.error(
"Found Broken RecipeId {}:{}",
GuiRecipeTab.getHandlerInfo(handler).getHandlerName(),
stack,
ex);
}
}
}
}
recipes.close();
} catch (Exception e) {
NEIClientConfig.logger.error("Error dumping RecipeId", e);
}
NEIClientConfig.logger.info("Finished processing recipe handlers!");
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.finish");
}
private ArrayList<ICraftingHandler> getCraftingHandlers(Object... results) {
return new RecipeHandlerQuery<>(
h -> h.getRecipeHandler("item", results),
this.craftinghandlers,
this.serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: item",
"results: " + Arrays.toString(results))
.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
}
}
@Override
public String getCommandName() {
return "recipeid";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/recipeid dump <filename> OR /recipeid diff <prev-filename> <curr-filename> [subset name]";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
final String command = args.length == 0 ? null : args[0];
if ("dump".equals(command)) {
processDumpCommand(sender, args);
} else if ("diff".equals(command)) {
processDiffCommand(sender, args);
} else {
sendChatErrorMessage(sender, getCommandUsage(sender));
}
}
protected void processDiffCommand(ICommandSender sender, String[] args) {
if (args.length > 4) {
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
return;
}
if (args.length < 3) {
sendChatErrorMessage(sender, getCommandUsage(sender));
return;
}
final File prevFilename = getFile(args[1]);
final File currFilename = getFile(args[2]);
final File diffFilename = getFile(args.length > 3 ? args[3] : "changelog");
if (!prevFilename.exists()) {
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", prevFilename.getName());
return;
}
if (!currFilename.exists()) {
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", currFilename.getName());
return;
}
(new ProcessDiffThread(sender, prevFilename, currFilename, diffFilename)).start();
}
protected void processDumpCommand(ICommandSender sender, String[] args) {
if (args.length > 2) {
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
return;
}
final File dir = new File(CommonUtils.getMinecraftDir(), "recipeid");
final String currFilename = args.length == 2 ? args[1] : "recipeId";
if (!dir.exists()) dir.mkdirs();
(new ProcessDumpThread(sender, getFile(currFilename))).start();
}
private static File getFile(String filename) {
return new File(CommonUtils.getMinecraftDir(), "recipeid/" + filename + ".json");
}
private static void sendChatInfoMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)));
}
private static void sendChatErrorMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)));
}
}
@@ -160,8 +160,8 @@ public class GuiPanelSettings extends GuiScreenWidget {
}
protected void drawItems() {
final int columns = w / ItemsGrid.SLOT_SIZE;
final int rows = (h - (PANEL_SIZE + 2) * 2) / ItemsGrid.SLOT_SIZE;
final int columns = (w - 2) / ItemsGrid.SLOT_SIZE;
final int rows = (h - (PANEL_SIZE + 2) * 2 - 2) / ItemsGrid.SLOT_SIZE;
final int paddingLeft = (w % ItemsGrid.SLOT_SIZE) / 2;
final List<ItemStack> items = ItemPanels.itemPanel.getItems();
if (items.isEmpty()) return;
@@ -97,7 +97,7 @@ public class HandlerDumper extends DataDumper {
}
writer.close();
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save dump handler list to file {}", file, e);
NEIClientConfig.logger.error("Failed to save dump handler list to file {}", file, e);
}
}
@@ -207,6 +207,10 @@ public class GuiPresetList extends GuiOptionPane {
modeName = EnumChatFormatting.GOLD + NEIClientUtils.translate("presets.mode.hide.char")
+ EnumChatFormatting.RESET;
break;
case SUBSET:
modeName = EnumChatFormatting.DARK_PURPLE + NEIClientUtils.translate("presets.mode.subset.char")
+ EnumChatFormatting.RESET;
break;
case REMOVE:
modeName = EnumChatFormatting.RED + NEIClientUtils.translate("presets.mode.remove.char")
+ EnumChatFormatting.RESET;
@@ -86,6 +86,7 @@ public class LeftPanel extends GuiWidget {
protected Label modeLabel = new Label(NEIClientUtils.translate("presets.mode"), false);
protected CheckboxButton modeHide;
protected CheckboxButton modeSubset;
protected CheckboxButton modeRemove;
protected CheckboxButton modeGroup;
@@ -114,6 +115,19 @@ public class LeftPanel extends GuiWidget {
}
};
modeSubset = new CheckboxButton(NEIClientUtils.translate("presets.mode.subset")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.SUBSET;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.SUBSET : null;
}
};
modeRemove = new CheckboxButton(NEIClientUtils.translate("presets.mode.remove")) {
@Override
@@ -164,6 +178,10 @@ public class LeftPanel extends GuiWidget {
modeHide.handleClick(x, y, button);
}
if (modeSubset.contains(x, y)) {
modeSubset.handleClick(x, y, button);
}
if (modeRemove.contains(x, y)) {
modeRemove.handleClick(x, y, button);
}
@@ -248,7 +266,7 @@ public class LeftPanel extends GuiWidget {
@Override
public void update() {
int CHECKBOX_WIDTH = (this.width - 12) / 3;
int CHECKBOX_WIDTH = (this.width - 12) / 4;
nameLabel.x = this.x + 2;
nameLabel.y = this.y + 4;
nameLabel.w = this.width;
@@ -269,12 +287,13 @@ public class LeftPanel extends GuiWidget {
modeLabel.w = this.width;
modeLabel.h = 10;
modeHide.w = modeRemove.w = modeGroup.w = CHECKBOX_WIDTH;
modeHide.h = modeRemove.h = modeGroup.h = INPUT_HEIGHT;
modeHide.y = modeRemove.y = modeGroup.y = modeLabel.y + modeLabel.h;
modeHide.w = modeSubset.w = modeRemove.w = modeGroup.w = CHECKBOX_WIDTH;
modeHide.h = modeSubset.h = modeRemove.h = modeGroup.h = INPUT_HEIGHT;
modeHide.y = modeSubset.y = modeRemove.y = modeGroup.y = modeLabel.y + modeLabel.h;
modeHide.x = this.x + 1;
modeRemove.x = modeHide.x + modeHide.w + 6;
modeSubset.x = modeHide.x + modeHide.w + 6;
modeRemove.x = modeSubset.x + modeSubset.w + 6;
modeGroup.x = modeRemove.x + modeRemove.w + 6;
grid.setGridSize(
@@ -292,6 +311,7 @@ public class LeftPanel extends GuiWidget {
modeLabel.draw(mousex, mousey);
modeHide.draw(mousex, mousey);
modeSubset.draw(mousex, mousey);
modeRemove.draw(mousex, mousey);
modeGroup.draw(mousex, mousey);
@@ -326,6 +346,8 @@ public class LeftPanel extends GuiWidget {
} else if (modeHide.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.hide.tip"));
} else if (modeSubset.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.subset.tip"));
} else if (modeRemove.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.remove.tip"));
} else if (modeGroup.contains(mousex, mousey)) {
@@ -592,7 +592,7 @@ public class GuiContainerManager {
if (!tooltip.isEmpty()) tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
if (showTooltip) {
if (showTooltip && NEIClientConfig.getBooleanSetting("inventory.showHotkeys")) {
List<String> hotkeystips = collectHotkeyTips(mousex, mousey);
if (!hotkeystips.isEmpty()) {
@@ -119,7 +119,7 @@ public class GuiFavoriteButton extends GuiRecipeButton {
public void lastKeyTyped(GuiRecipe<?> gui, char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.bookmark") && NEIClientUtils.shiftKey()) {
ItemPanels.bookmarkPanel.addGroup(getRecipesTree(getRecipe()), BookmarkViewMode.TODO_LIST, true);
saveRecipeInBookmark();
}
}
@@ -180,6 +180,10 @@ public class GuiFavoriteButton extends GuiRecipeButton {
return true;
}
public void saveRecipeInBookmark() {
ItemPanels.bookmarkPanel.addGroup(getRecipesTree(getRecipe()), BookmarkViewMode.TODO_LIST, true);
}
private List<Recipe> getRecipesTree(Recipe mainRecipe) {
int depth = NEIClientConfig.getIntSetting("inventory.favorites.depth");
final ItemStackSet items = new ItemStackSet();
@@ -155,6 +155,10 @@ public class GuiOverlayButton extends GuiRecipeButton {
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("recipe.overlay.bookmarkRecipe"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("recipe.overlay.bookmarkRecipeAndCount"));
return hotkeys;
}
@@ -309,7 +313,8 @@ public class GuiOverlayButton extends GuiRecipeButton {
final Recipe recipe = getRecipe();
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
ItemPanels.bookmarkPanel.addRecipe(recipe, BookmarkGrid.DEFAULT_GROUP_ID);
ItemPanels.bookmarkPanel
.addRecipe(recipe, NEIClientUtils.controlKey() ? 1 : 0, BookmarkGrid.DEFAULT_GROUP_ID);
}
}
@@ -2,9 +2,12 @@ package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidContainerRegistry;
@@ -36,10 +39,15 @@ public class Recipe {
this.result = result != null ? StackInfo.withAmount(result, 0) : null;
this.handlerName = handlerName;
this.ingredients = ingredients;
if (!isSharpedRecipe()) {
// sort to ignore ingredients position in shapeless recipes
Collections.sort(this.ingredients, Comparator.comparing(StackInfo::getItemStackGUID));
}
}
public static RecipeId of(Object result, String handlerName, Iterable<?> ingredients) {
return new RecipeId(extractItem(result), handlerName, extractItems(ingredients));
return new RecipeId(extractItem(result), handlerName, extractIngredients(ingredients));
}
public static RecipeId of(JsonObject json) {
@@ -74,14 +82,14 @@ public class Recipe {
return new ArrayList<>(this.ingredients);
}
protected static List<ItemStack> extractItems(Iterable<?> items) {
protected static List<ItemStack> extractIngredients(Iterable<?> items) {
final List<ItemStack> list = new ArrayList<>();
for (Object item : items) {
ItemStack stack = extractItem(item);
final ItemStack stack = extractItem(item);
if (stack != null) {
list.add(stack.copy());
list.add(prepareIngredient(stack.copy()));
}
}
@@ -115,15 +123,56 @@ public class Recipe {
return false;
}
for (int index = 0; index < stacks.size(); index++) {
if (!stacks.get(index).containsWithNBT(ingredients.get(index))) {
return false;
if (isSharpedRecipe()) {
for (int index = 0; index < stacks.size(); index++) {
if (!containsWithNBT(stacks.get(index), Arrays.asList(this.ingredients.get(index)))) {
return false;
}
}
} else {
for (PositionedStack pStack : stacks) {
if (!containsWithNBT(pStack, this.ingredients)) {
return false;
}
}
}
return true;
}
private static boolean containsWithNBT(PositionedStack pStack, List<ItemStack> ingrStacks) {
for (ItemStack item : pStack.items) {
final ItemStack pItem = prepareIngredient(item);
if (ingrStacks.stream().anyMatch(stack -> StackInfo.equalItemAndNBT(pItem, stack, true))) {
return true;
}
}
return false;
}
private static ItemStack prepareIngredient(ItemStack stack) {
// hack: remove metadata for "Data Stick"
if (stack.hasTagCompound() && stack.getItemDamage() == 32708
&& "gregtech:gt.metaitem.01".equals(Item.itemRegistry.getNameForObject(stack.getItem()))) {
return new ItemStack(stack.getItem(), stack.getItemDamage());
}
// hack: remove metadata for "Circuit Imprint"
if (stack.hasTagCompound() && stack.getItemDamage() == 0
&& "bartworks:gt.bwMetaGeneratedItem0"
.equals(Item.itemRegistry.getNameForObject(stack.getItem()))) {
return new ItemStack(stack.getItem(), stack.getItemDamage());
}
return stack;
}
public boolean isSharpedRecipe() {
return this.handlerName.equals("codechicken.nei.recipe.ShapedRecipeHandler")
|| this.handlerName.equals("fox.spiteful.avaritia.compat.nei.ExtremeShapedRecipeHandler");
}
public JsonObject toJsonObject() {
final JsonObject json = new JsonObject();
@@ -142,8 +191,8 @@ public class Recipe {
protected JsonArray convertItemsToJsonArray(List<ItemStack> items) {
final JsonArray arr = new JsonArray();
for (ItemStack nbTag : items) {
arr.add(NBTJson.toJsonObject(StackInfo.itemStackToNBT(nbTag)));
for (ItemStack stack : items) {
arr.add(NBTJson.toJsonObject(StackInfo.itemStackToNBT(stack)));
}
return arr;
@@ -17,7 +17,7 @@ import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.util.AsyncTaskProfiler;
class RecipeHandlerQuery<T extends IRecipeHandler> {
public class RecipeHandlerQuery<T extends IRecipeHandler> {
private final Function<T, T> recipeHandlerFunction;
private final List<T> recipeHandlers;
@@ -25,15 +25,15 @@ class RecipeHandlerQuery<T extends IRecipeHandler> {
private final String[] errorMessage;
private boolean error = false;
RecipeHandlerQuery(Function<T, T> recipeHandlerFunction, List<T> recipeHandlers, List<T> serialRecipeHandlers,
String... errorMessage) {
public RecipeHandlerQuery(Function<T, T> recipeHandlerFunction, List<T> recipeHandlers,
List<T> serialRecipeHandlers, String... errorMessage) {
this.recipeHandlerFunction = recipeHandlerFunction;
this.recipeHandlers = recipeHandlers;
this.serialRecipeHandlers = serialRecipeHandlers;
this.errorMessage = errorMessage;
}
ArrayList<T> runWithProfiling(String profilerSection) {
public ArrayList<T> runWithProfiling(String profilerSection) {
TaskProfiler profiler = ProfilerRecipeHandler.getProfiler();
// Save the current config state here, as it may be altered
@@ -30,7 +30,7 @@ public class RecipeHandlerRef {
public static RecipeHandlerRef of(RecipeId recipeId) {
if (recipeId.getResult() != null && !recipeId.getIngredients().isEmpty()) {
if (recipeId != null && recipeId.getResult() != null && !recipeId.getIngredients().isEmpty()) {
return recipeRefCache.computeIfAbsent(recipeId, ri -> {
final List<ICraftingHandler> handlers = GuiCraftingRecipe
.getCraftingHandlers("recipeId", recipeId.getResult(), recipeId);
@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
@@ -22,6 +23,7 @@ import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.stackinfo.DefaultStackStringifyHandler;
import codechicken.nei.recipe.stackinfo.GTFluidStackStringifyHandler;
import codechicken.nei.util.ItemStackKey;
import codechicken.nei.util.NBTHelper;
public class StackInfo {
@@ -144,7 +146,7 @@ public class StackInfo {
final NBTTagCompound nbTag = itemStackToNBT(stack, false);
if (nbTag == null) {
return null;
return "unknown";
}
nbTag.removeTag("Count");
@@ -157,9 +159,11 @@ public class StackInfo {
nbTag.removeTag("tag");
}
if (nbTag.hasKey("strId") && guidfilters.containsKey(nbTag.getString("strId"))) {
if (nbTag.hasKey("strId") && (guidfilters.containsKey(nbTag.getString("strId"))
|| guidfilters.containsKey(nbTag.getString("strId") + "&" + nbTag.getShort("Damage")))) {
final String strId = nbTag.getString("strId")
+ (guidfilters.containsKey(nbTag.getString("strId")) ? "" : "&" + nbTag.getShort("Damage"));
final ArrayList<String> keys = new ArrayList<>();
final String strId = nbTag.getString("strId");
keys.add(strId);
@@ -184,7 +188,7 @@ public class StackInfo {
}
if (local instanceof NBTBase item) {
keys.add(item.toString());
keys.add(NBTHelper.toString(item));
} else if (local != null) {
keys.add(String.valueOf(local));
}
@@ -195,7 +199,7 @@ public class StackInfo {
}
} else {
synchronized (guidcache) {
guidcache.put(stack, nbTag.toString());
guidcache.put(stack, NBTHelper.toString(nbTag));
}
}
@@ -218,13 +222,17 @@ public class StackInfo {
}
public static ItemStack getItemStackWithMinimumDamage(ItemStack[] stacks) {
int damage = Short.MAX_VALUE;
ItemStack result = stacks[0];
if (stacks.length > 1) {
for (ItemStack stack : stacks) {
if (stack.getItem() != null && !ItemInfo.isHidden(stack) && stack.getItemDamage() < damage) {
damage = stack.getItemDamage();
// to optimize compare recipes from permutation, an item with a minimum strId and damage is taken so as
// not to check everything permutation items
if (stack.getItem() != null && !ItemInfo.isHidden(stack)
&& (stack.getItemDamage() < result.getItemDamage()
|| stack.getItemDamage() == result.getItemDamage()
&& Item.itemRegistry.getNameForObject(stack.getItem()).compareTo(
Item.itemRegistry.getNameForObject(result.getItem())) == -1)) {
result = stack;
}
}
@@ -116,18 +116,18 @@ public class RecipeChainMath {
}
for (Map.Entry<RecipeId, Long> entry : multipliers.entrySet()) {
if (!this.outputRecipes.containsKey(entry.getKey()) && this.preferredItems.values().stream()
.noneMatch(resItem -> resItem.recipeId.equals(entry.getKey()))) {
this.outputRecipes.put(entry.getKey(), entry.getValue());
final RecipeId recipeId = entry.getKey();
final boolean isOutputRecipe = this.outputRecipes.containsKey(recipeId);
final boolean recipeInMiddle = this.preferredItems.values().stream()
.anyMatch(resItem -> resItem.recipeId.equals(recipeId));
if (!isOutputRecipe && !recipeInMiddle) {
this.outputRecipes.put(recipeId, entry.getValue());
} else if (isOutputRecipe && recipeInMiddle) {
this.outputRecipes.put(recipeId, Math.max(0, entry.getValue() - 1));
}
}
for (Map.Entry<RecipeId, Long> entry : this.outputRecipes.entrySet()) {
if (entry.getValue() == 0 && this.preferredItems.values().stream()
.noneMatch(prefItem -> prefItem.recipeId.equals(entry.getKey()))) {
entry.setValue(1L);
}
}
}
private void collectPreferredItems(RecipeId recipeId, Map<BookmarkItem, BookmarkItem> preferredItems,
@@ -1,5 +1,9 @@
package codechicken.nei.util;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.nbt.NBTBase;
@@ -52,4 +56,26 @@ public class NBTHelper {
private static NBTBase get(NBTTagList tag, int idx) {
return idx >= 0 && idx < tag.tagList.size() ? (NBTBase) tag.tagList.get(idx) : null;
}
public static String toString(NBTBase nbt) {
if (nbt instanceof NBTTagCompound nbtTagCompound) {
final Map<String, NBTBase> tagMap = (Map<String, NBTBase>) nbtTagCompound.tagMap;
return "{" + tagMap.entrySet().stream().sorted(Map.Entry.<String, NBTBase>comparingByKey())
.map(nbtEntry -> nbtEntry.getKey() + ":" + toString(nbtEntry.getValue()))
.collect(Collectors.joining(",")) + "}";
} else if (nbt instanceof NBTTagList list) {
if (list.tagList.isEmpty()) {
return "[]";
} else {
final StringJoiner arr = new StringJoiner(",");
list.tagList.forEach(c -> arr.add(toString((NBTBase) c)));
return "[" + arr.toString() + "]";
}
} else {
return nbt.toString();
}
}
}
@@ -43,12 +43,10 @@ public class NBTJson {
// NBTTagCompound
final NBTTagCompound nbtTagCompound = (NBTTagCompound) nbt;
final Map<String, NBTBase> tagMap = (Map<String, NBTBase>) nbtTagCompound.tagMap;
final JsonObject root = new JsonObject();
JsonObject root = new JsonObject();
for (Map.Entry<String, NBTBase> nbtEntry : tagMap.entrySet()) {
root.add(nbtEntry.getKey(), toJsonObject(nbtEntry.getValue()));
}
tagMap.entrySet().stream().sorted(Map.Entry.<String, NBTBase>comparingByKey())
.forEach(nbtEntry -> { root.add(nbtEntry.getKey(), toJsonObject(nbtEntry.getValue())); });
return root;
} else if (nbt instanceof NBTTagByte) {
@@ -54,4 +54,5 @@ miscutils:personalHealingDevice
tectech:item.em.debugContainer,tag.symbols
tinkersdefense:Heater Shield,tag.InfiTool
tinkersdefense:Round Shield,tag.InfiTool
miscutils:itemCustomMetaCover.miscutils.GtMachineCasings,Damage
miscutils:itemCustomMetaCover.miscutils.GtMachineCasings,Damage
gregtech:gt.metaitem.01&32708,tag.output
@@ -0,0 +1,3 @@
# Each line in this file should either be a comment (line starts with '#'), handler name or handler id.
# If you delete this file, it will be regenerated with the default handlers list.
Unknown
+15 -2
View File
@@ -37,6 +37,7 @@ nei.bookmark.remove_recipe=Remove Recipe
nei.bookmark.remove_item=Remove Item
nei.bookmark.add_item=Add Bookmark
nei.bookmark.add_item_with_recipe=Add Bookmark with Recipe
nei.bookmark.add_item_with_recipe_and_count=Add Bookmark with Recipe & Count
nei.bookmark.add_item_with_count=Add Bookmark with Count
nei.bookmark.change_quantity=Change Quantity
nei.bookmark.change_quantity_step=Change Quantity with Multiplier
@@ -138,6 +139,13 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
nei.chat.item_link.text=<%s> §6Click to add bookmark: %s
nei.chat.bookmark_added.text=Bookmark added!
nei.chat.recipeid.many_params=Too many parameters! Usage: %s
nei.chat.recipeid.not_found=File %s not found!
nei.chat.recipeid.diff.start=Start processing recipe diff!
nei.chat.recipeid.diff.finish=Finished processing recipe diff!
nei.chat.recipeid.dump.start=Start processing recipe handlers!
nei.chat.recipeid.dump.finish=Finished processing recipe handlers!
nei.options=NEI Options
nei.options.back=Back
nei.options.save=Save
@@ -166,8 +174,6 @@ nei.options.keys.gui.prev_machine=Prev Machine
nei.options.keys.gui.search=Focus Search Bar
nei.options.keys.gui.bookmark=Add Bookmark
nei.options.keys.gui.remove_recipe=Remove Group from Bookmarks
nei.options.keys.gui.bookmark_recipe=Add Bookmark with Recipe
nei.options.keys.gui.bookmark_count=Add Bookmark with Count
nei.options.keys.gui.bookmark_pull_items=Pull all Bookmarked Items
nei.options.keys.gui.hide_bookmarks=Toggle Bookmark Panel Visibility
nei.options.keys.gui.overlay=Fill/Overlay Crafting Grid
@@ -242,6 +248,9 @@ nei.options.inventory.favorites.depth=Depth
nei.options.inventory.hotkeysHelpText=Show Hotkeys Help Text
nei.options.inventory.hotkeysHelpText.true=Yes
nei.options.inventory.hotkeysHelpText.false=No
nei.options.inventory.showHotkeys=Show Hotkeys
nei.options.inventory.showHotkeys.true=Yes
nei.options.inventory.showHotkeys.false=No
nei.options.inventory.guirecipe=Recipes GUI
nei.options.inventory.guirecipe.jeiStyleTabs=JEI Style Tabs
nei.options.inventory.guirecipe.jeiStyleTabs.true=Yes
@@ -508,6 +517,7 @@ nei.recipe.overlay.mismatch=Mismatch Crafting Grid
nei.recipe.overlay.overlayRecipe=Overlay Recipe
nei.recipe.overlay.fillCraftingGrid=Fill Crafting Grid
nei.recipe.overlay.bookmarkRecipe=Save with Recipe
nei.recipe.overlay.bookmarkRecipeAndCount=Save with Recipe & Count
nei.recipe.favorite=Favorite
nei.recipe.favorite.bookmark_recipe=Save Recipe Tree
@@ -572,6 +582,9 @@ nei.presets.mode=Mode
nei.presets.mode.hide=Hide
nei.presets.mode.hide.char=H
nei.presets.mode.hide.tip=Hide items in panel
nei.presets.mode.subset=Subset
nei.presets.mode.subset.char=S
nei.presets.mode.subset.tip=Create custom subsets
nei.presets.mode.remove=Remove
nei.presets.mode.remove.tip=Hide items in panel and their recipes
nei.presets.mode.remove.char=R