Add Favorite Item Support (#880)

This commit is contained in:
slprime authored and GitHub committed 2026-03-07 16:34:41 +02:00
1 parent 2782f8252e
commit 8b45a1757f
9 files changed
+153 -36

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.19'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.21'
}
@@ -135,6 +135,7 @@ public class FavoriteRecipes {
};
public static final String FAVORITE_ITEM = "FavoriteItem";
private static final FavoriteStorage manualFavorites = new FavoriteStorage();
private static FavoriteStorage autoFavorites = new FavoriteStorage();
private static File favoriteFile;
@@ -224,7 +225,7 @@ public class FavoriteRecipes {
continue;
}
if (RecipeHandlerRef.of(recipeId) != null) {
if (FAVORITE_ITEM.equals(recipeId.getHandleName()) || RecipeHandlerRef.of(recipeId) != null) {
manualFavorites.add(stack, recipeId);
} else {
hasErrors = true;
@@ -256,6 +257,20 @@ public class FavoriteRecipes {
loadAutoGeneratedRecipes();
}
public static RecipeId getGeneratedFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
return autoFavorites.getRecipeId(stack);
}
return null;
}
public static ItemStack getGeneratedFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
return autoFavorites.getItemStack(recipeId);
}
return null;
}
public static RecipeId getManualFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
return manualFavorites.getRecipeId(stack);
+3 -1
View File
@@ -31,6 +31,7 @@ import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.search.TooltipFilter;
import codechicken.nei.util.ItemUntranslator;
import cpw.mods.fml.common.FMLLog;
@@ -432,7 +433,8 @@ public class ItemList {
loadFinished = true;
FavoriteRecipes.loadAutoGeneratedRecipes();
RecipeHandlerRef.clearCache();
FavoriteRecipes.reload();
SubsetWidget.updateHiddenItems();
ItemPanels.bookmarkPanel.load();
updateFilter.restart();
@@ -827,6 +827,7 @@ public class NEIClientConfig {
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.addKeyBind("gui.favorite_item", Keyboard.KEY_F);
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);
@@ -1009,7 +1010,6 @@ public class NEIClientConfig {
SubsetWidget.loadHidden();
CollapsibleItems.load();
ItemSorter.loadConfig();
FavoriteRecipes.load();
// Set pluginNEIConfigLoaded here before posting the NEIConfigsLoadedEvent. This used to be the
// other way around, but apparently if your modpack includes 800 mods the event poster might not
@@ -205,29 +205,47 @@ public class GuiFavoriteButton extends GuiRecipeButton {
if (stack == null) {
stack = ingr.getItemStack();
RecipeId recipeId = FavoriteRecipes.getFavorite(stack);
RecipeId recipeId = FavoriteRecipes.getManualFavorite(stack);
if (recipeId == null) {
for (ItemStack permStack : permutations) {
if ((recipeId = FavoriteRecipes.getFavorite(permStack)) != null) {
if ((recipeId = FavoriteRecipes.getManualFavorite(permStack)) != null) {
stack = permStack;
break;
}
}
}
Recipe recipe = Recipe.of(recipeId);
if (recipeId == null) {
recipeId = FavoriteRecipes.getGeneratedFavorite(stack);
}
if (recipe == null) {
stack = null;
} else {
items.add(stack);
if (depth >= 0) {
result.add(recipe);
localLoop.add(recipe);
if (recipeId == null) {
for (ItemStack permStack : permutations) {
if ((recipeId = FavoriteRecipes.getGeneratedFavorite(permStack)) != null) {
stack = permStack;
break;
}
}
}
if (recipeId != null && FavoriteRecipes.FAVORITE_ITEM.contains(recipeId.getHandleName())) {
items.add(stack);
} else {
Recipe recipe = Recipe.of(recipeId);
if (recipe == null) {
stack = null;
} else {
items.add(stack);
if (depth >= 0) {
result.add(recipe);
localLoop.add(recipe);
}
}
}
}
if (stack != null) {
@@ -13,6 +13,7 @@ import java.util.stream.Stream;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
@@ -31,12 +32,14 @@ import codechicken.nei.api.IGuiContainerOverlay;
import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.GuiRecipeButton.UpdateRecipeButtonsEvent;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.util.NEIMouseUtils;
public class NEIRecipeWidget extends Widget {
protected AcceptsFollowingTooltipLineHandler acceptsFollowingTooltipLineHandler;
protected final WeakHashMap<PositionedStack, List<ItemStack>> permutations = new WeakHashMap<>();
protected final Map<PositionedStack, Integer> favoriteIndexes = new WeakHashMap<>();
protected final Map<PositionedStack, List<ItemStack>> permutations = new WeakHashMap<>();
protected int favoriteRevision = -1;
protected boolean update = true;
protected int cycleticks = 0;
@@ -188,6 +191,11 @@ public class NEIRecipeWidget extends Widget {
GuiContainerManager.enableMatrixStackLogging();
for (PositionedStack pStack : getInputs()) {
if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
}
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
@@ -196,6 +204,11 @@ public class NEIRecipeWidget extends Widget {
}
for (PositionedStack pStack : getCatalysts()) {
if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
}
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
@@ -244,6 +257,38 @@ public class NEIRecipeWidget extends Widget {
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
if (NEIClientConfig.favoritesEnabled() && NEIClientUtils.shiftKey()
&& NEIClientConfig.isKeyHashDown("gui.favorite_item")) {
final Point mouse = GuiDraw.getMousePosition();
final int yShift = this.handlerInfo.getYShift();
PositionedStack pStackOver = null;
for (PositionedStack pStack : getInputs()) {
if (pStack.contains(mouse.x - this.x, mouse.y - this.y - yShift)) {
pStackOver = pStack;
break;
}
}
if (pStackOver != null) {
if (FavoriteRecipes.containsManual(pStackOver.item)) {
FavoriteRecipes.setFavorite(pStackOver.item, null);
} else {
FavoriteRecipes.setFavorite(
pStackOver.item,
RecipeId.of(
pStackOver.item,
FavoriteRecipes.FAVORITE_ITEM,
Arrays.asList(new ItemStack(Blocks.fire, 1), pStackOver.item)));
}
return true;
}
}
return false;
}
@@ -342,10 +387,11 @@ public class NEIRecipeWidget extends Widget {
if (hovered == null || hovered.items.length <= 1) {
this.acceptsFollowingTooltipLineHandler = null;
} else if (this.acceptsFollowingTooltipLineHandler == null
|| this.acceptsFollowingTooltipLineHandler.tooltipGUID != hovered) {
} else if ((this.acceptsFollowingTooltipLineHandler == null
|| this.acceptsFollowingTooltipLineHandler.tooltipGUID != hovered)
&& this.permutations.getOrDefault(hovered, Collections.emptyList()).size() > 1) {
this.acceptsFollowingTooltipLineHandler = AcceptsFollowingTooltipLineHandler
.of(hovered, hovered.getFilteredPermutations(), hovered.item);
.of(hovered, this.permutations.get(hovered), hovered.item);
}
} else if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler = null;
@@ -360,6 +406,7 @@ public class NEIRecipeWidget extends Widget {
@Override
public Map<String, String> handleHotkeys(int mouseX, int mouseY, Map<String, String> hotkeys) {
final int yShift = this.handlerInfo.getYShift();
final Map<String, String> buttonHotkeys = forEachButtons(
button -> button.contains(mouseX, mouseY) ? button.handleHotkeys(mouseX, mouseY, hotkeys) : null,
hotkeys);
@@ -372,6 +419,14 @@ public class NEIRecipeWidget extends Widget {
NEIClientUtils.translate("recipe.accepts.scroll"));
}
if (getInputs().stream().anyMatch(
pStack -> this.permutations.getOrDefault(pStack, Collections.emptyList()).size() > 1
&& pStack.contains(mouseX - this.x, mouseY - this.y - yShift))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.favorite_item", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("recipe.favorite.toggle"));
}
return buttonHotkeys;
}
@@ -396,8 +451,8 @@ public class NEIRecipeWidget extends Widget {
if (!NEIClientUtils.shiftKey()) return false;
final PositionedStack overStack = getPositionedStackMouseOver(mx, my);
if (overStack != null && overStack.items.length > 1) {
final List<ItemStack> items = overStack.getFilteredPermutations();
if (overStack != null && this.permutations.getOrDefault(overStack, Collections.emptyList()).size() > 1) {
final List<ItemStack> items = this.permutations.get(overStack);
final int stackIndex = indexOf(items, overStack.item);
final ItemStack stack = items.get((items.size() - scroll + stackIndex) % items.size());
@@ -506,29 +561,21 @@ public class NEIRecipeWidget extends Widget {
}
protected void updatePermutations() {
final int rev = FavoriteRecipes.getRevision();
if (this.favoriteRevision != FavoriteRecipes.getRevision()) {
this.favoriteRevision = FavoriteRecipes.getRevision();
if (this.favoriteRevision != rev) {
this.favoriteRevision = rev;
this.acceptsFollowingTooltipLineHandler = null;
this.favoriteIndexes.clear();
this.permutations.clear();
}
for (PositionedStack pStack : getInputs()) {
if (pStack.items.length > 1) {
final List<ItemStack> permutations = this.permutations.computeIfAbsent(
pStack,
stack -> stack.getFilteredPermutations(FavoriteRecipes::containsManual));
pStack.setPermutationToRender(permutations.get(this.lastcycle % permutations.size()));
}
updatePermutationsFor(pStack);
}
for (PositionedStack pStack : getCatalysts()) {
if (pStack.items.length > 1) {
final List<ItemStack> permutations = this.permutations.computeIfAbsent(
pStack,
stack -> stack.getFilteredPermutations(FavoriteRecipes::containsManual));
pStack.setPermutationToRender(permutations.get(this.lastcycle % permutations.size()));
}
updatePermutationsFor(pStack);
}
if (this.acceptsFollowingTooltipLineHandler != null) {
@@ -538,6 +585,34 @@ public class NEIRecipeWidget extends Widget {
}
private void updatePermutationsFor(PositionedStack pStack) {
List<ItemStack> perms = this.permutations.get(pStack);
int favoriteIndex = this.favoriteIndexes.getOrDefault(pStack, -1);
if (perms == null) {
perms = pStack.getFilteredPermutations();
favoriteIndex = -1;
if (perms.size() > 1) {
for (ItemStack item : perms) {
if (!FavoriteRecipes.containsManual(item)) break;
favoriteIndex++;
}
}
this.permutations.put(pStack, perms);
this.favoriteIndexes.put(pStack, favoriteIndex);
}
if (perms.size() > 1) {
final int size = favoriteIndex != -1 ? favoriteIndex + 1 : perms.size();
if (size > 0) {
pStack.setPermutationToRender(perms.get(this.lastcycle % size));
}
}
}
protected List<PositionedStack> getInputs() {
return this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex);
}
@@ -52,6 +52,11 @@ public class RecipeHandlerRef {
return null;
}
public static void clearCache() {
recipeRefCache.clear();
transferAlghoritmCache.clear();
}
private GuiContainer prepareGui(GuiContainer firstGui) {
if (firstGui instanceof GuiRecipe gui) {
@@ -202,6 +202,7 @@ nei.options.keys.gui.itemzoom_hold=Hold to Display Item Zoom
nei.options.keys.gui.itemzoom_zoom_in=Item Zoom In
nei.options.keys.gui.itemzoom_zoom_out=Item Zoom Out
nei.options.keys.gui.favorite=Add Favorite
nei.options.keys.gui.favorite_item=Toggle Favorite
nei.options.keys.world=World
nei.options.keys.world.chunkoverlay=Chunk Boundary Overlay
nei.options.keys.world.moboverlay=Mob Spawn Overlay
@@ -574,6 +575,7 @@ nei.recipe.overlay.bookmarkRecipeAndCount=Save with Recipe & Count
nei.recipe.favorite=Favorite
nei.recipe.favorite.bookmark_recipe=Save Recipe Tree
nei.recipe.favorite.change_result_index=Change Output
nei.recipe.favorite.toggle=Toggle Favorite
nei.recipe.information=Information