Skip to content
5 changes: 2 additions & 3 deletions src/main/java/codechicken/nei/FavoriteRecipes.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -129,8 +128,8 @@ public void execute() {
}

protected List<PositionedStack> getOutputs(IRecipeHandler handler, int recipeIndex) {
final PositionedStack pStackResult = handler.getResultStack(recipeIndex);
return pStackResult != null ? Collections.singletonList(pStackResult) : handler.getOtherStacks(recipeIndex);
final List<PositionedStack> pStackResults = handler.getResultStacks(recipeIndex);
return !pStackResults.isEmpty() ? pStackResults : handler.getOtherStacks(recipeIndex);
}

};
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/codechicken/nei/PresetsList.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ public boolean matches(IRecipeHandler handler, int recipeIndex) {
return false;
}

final PositionedStack result = handler.getResultStack(recipeIndex);
final List<PositionedStack> results = handler.getResultStacks(recipeIndex);

if (result != null && matchPositionedStack(result)) {
if (!results.isEmpty() && matchPositionedStack(results, true)) {
return true;
}

Expand All @@ -101,7 +101,13 @@ public boolean matches(IRecipeHandler handler, int recipeIndex) {
return true;
}

return result == null && others.isEmpty();
final List<PositionedStack> extraInputs = handler.getCatalystStacks(recipeIndex);

if (!extraInputs.isEmpty() && matchPositionedStack(extraInputs, true)) {
return true;
}

return results.isEmpty() && others.isEmpty();
}

private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ public boolean matches(IRecipeHandler handler, int recipeIndex) {
}
}

for (PositionedStack pStack : handler.getCatalystStacks(recipeIndex)) {
if (!match(pStack)) {
return false;
}
}

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ public boolean matches(IRecipeHandler handler, int recipeIndex) {
}
}

for (PositionedStack pStack : handler.getCatalystStacks(recipeIndex)) {
if (match(pStack)) {
return true;
}
}

return false;
}

Expand Down
8 changes: 5 additions & 3 deletions src/main/java/codechicken/nei/filter/RecipeFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,18 @@ && matchPositionedStack(handler.getIngredientStacks(recipeIndex), this.anyMatch)
}

if (this.context == FilterContext.ANY || this.context == FilterContext.OUTPUT) {
final PositionedStack result = handler.getResultStack(recipeIndex);

if (result != null && matchPositionedStack(result) == this.anyMatch) {
if (matchPositionedStack(handler.getResultStacks(recipeIndex), this.anyMatch)) {
return this.anyMatch;
}

if (matchPositionedStack(handler.getOtherStacks(recipeIndex), this.anyMatch)) {
return this.anyMatch;
}

if (matchPositionedStack(handler.getCatalystStacks(recipeIndex), this.anyMatch)) {
return this.anyMatch;
}

}

return !this.anyMatch;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/codechicken/nei/recipe/FuelRecipeHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public PositionedStack getResult() {
public PositionedStack getOtherStack() {
return fuel.stack;
}

@Override
public PositionedStack getCatalyst() {
return fuel.stack;
}
}

private final ArrayList<SmeltingPair> mfurnace = new ArrayList<>();
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/codechicken/nei/recipe/IRecipeHandler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package codechicken.nei.recipe;

import java.util.Collections;
import java.util.List;

import net.minecraft.client.gui.inventory.GuiContainer;
Expand Down Expand Up @@ -82,15 +83,38 @@ default int getRecipeHeight(int recipe) {
* @return A list of the other {@link PositionedStack}s in this recipe relative to the top left corner of your
* recipe drawing space. For example fuel in furnaces.
*/
default List<PositionedStack> getCatalystStacks(int recipe) {
return Collections.emptyList();
}

/**
* Legacy API, define either {@link #getCatalystStacks(int)} or {@link #getResultStacks(int)}
*
* @param recipe The recipe index to get items for.
* @return A list of the other {@link PositionedStack}s in this recipe relative to the top left corner of your
* recipe drawing space. For example fuel in furnaces.
*/
List<PositionedStack> getOtherStacks(int recipe);

/**
* Legacy API, use {@link #getResultStacks(int) getResultStacks.get(0)} if you want the primary result
*
* @param recipe The recipe index to get the result for.
* @return The recipe result {@link PositionedStack} relative to the top left corner of your recipe drawing space.
*/
PositionedStack getResultStack(int recipe);

/**
*
* @param recipe The recipe index to get the result for.
* @return A list of the result {@link PositionedStack}s relative to the top left corner of your recipe drawing
* space.
*/
default List<PositionedStack> getResultStacks(int recipe) {
final PositionedStack result = getResultStack(recipe);
return result != null ? Collections.singletonList(result) : Collections.emptyList();
}

/**
* A tick function called for updating progress bars and cycling damage items.
*/
Expand Down
45 changes: 36 additions & 9 deletions src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Function;
import java.util.stream.Stream;
Expand Down Expand Up @@ -36,6 +37,7 @@
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.debug.DebugHandlerWidget;
import codechicken.nei.util.NEIMouseUtils;
import it.unimi.dsi.fastutil.longs.LongArraySet;

public class NEIRecipeWidget extends Widget {

Expand All @@ -54,6 +56,9 @@ public class NEIRecipeWidget extends Widget {
protected boolean showAsWidget = false;
protected List<GuiRecipeButton> recipeButtons = null;

// Handles re-draws for catalysts-outputs duplication to preserve full backward compatibility for otherStacks
private final Set<Long> drawnSlots = new LongArraySet();

public NEIRecipeWidget(RecipeHandlerRef handlerRef) {
this.handlerRef = handlerRef;
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.handlerRef.handler);
Expand Down Expand Up @@ -193,7 +198,20 @@ public void draw(int mouseX, int mouseY) {

GuiContainerManager.enableMatrixStackLogging();

for (PositionedStack pStack : getInputs()) {
final List<PositionedStack> inputs = getInputs();
final List<PositionedStack> catalysts = getCatalysts();
final List<PositionedStack> outputs = getOutputs();

drawnSlots.clear();
for (PositionedStack pStack : inputs) {
drawnSlots.add(slotKey(pStack));
drawItem(pStack, mouseX, mouseY, yShift, false);
}

for (PositionedStack pStack : catalysts) {
if (!drawnSlots.add(slotKey(pStack))) {
continue;
}

if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
Expand All @@ -202,7 +220,10 @@ public void draw(int mouseX, int mouseY) {
drawItem(pStack, mouseX, mouseY, yShift, true);
}

for (PositionedStack pStack : getCatalysts()) {
for (PositionedStack pStack : outputs) {
if (!drawnSlots.add(slotKey(pStack))) {
continue;
}

if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
Expand All @@ -211,10 +232,6 @@ public void draw(int mouseX, int mouseY) {
drawItem(pStack, mouseX, mouseY, yShift, true);
}

for (PositionedStack pStack : getOutputs()) {
drawItem(pStack, mouseX, mouseY, yShift, false);
}

GuiContainerManager.disableMatrixStackLogging();

this.handlerRef.handler.drawForeground(this.handlerRef.recipeIndex);
Expand Down Expand Up @@ -246,6 +263,10 @@ public void draw(int mouseX, int mouseY) {
DebugHandlerWidget.instance.drawGuiPlaceholder(this);
}

private static long slotKey(PositionedStack pStack) {
return ((long) pStack.relx << 32) ^ (pStack.rely & 0xFFFFFFFFL);
}

protected void drawItem(PositionedStack pStack, int mouseX, int mouseY, int yShift, boolean input) {
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);

Expand Down Expand Up @@ -656,13 +677,19 @@ protected List<PositionedStack> getInputs() {
}

protected List<PositionedStack> getOutputs() {
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
return pStackResult != null ? Arrays.asList(pStackResult)
final List<PositionedStack> pStackResults = this.handlerRef.handler
.getResultStacks(this.handlerRef.recipeIndex);
return !pStackResults.isEmpty() ? pStackResults
: this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
}

protected List<PositionedStack> getCatalysts() {
if (this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex) == null) {
List<PositionedStack> catalysts = this.handlerRef.handler.getCatalystStacks(this.handlerRef.recipeIndex);
if (!catalysts.isEmpty()) {
return catalysts;
}

if (this.handlerRef.handler.getResultStacks(this.handlerRef.recipeIndex).isEmpty()) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this use getResultStack for maintaining the old behavior? I know this falls back to getResult if the multi-output is not defined, but idk if it would break something in the case of GT (result == null, but result stacks is not)

return Collections.emptyList();
}
return this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
Expand Down
23 changes: 17 additions & 6 deletions src/main/java/codechicken/nei/recipe/Recipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,26 @@ public static RecipeId of(Object result, String handlerName, Iterable<?> ingredi
public static RecipeId of(IRecipeHandler handler, int recipeIndex) {
final List<PositionedStack> ingredients = handler.getIngredientStacks(recipeIndex);
final String handlerName = GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
PositionedStack pStackResult = handler.getResultStack(recipeIndex);
// Use getResultStacks even though getResult could work because if a handler, like GT for example, doesn't
// return anything from getResult, but will define all the outputs in getResultStacks we can still pick up
// the results here. If a handler still doesn't define getResultStacks, then it will naturally fall back to
// getResult anyway
List<PositionedStack> pStackResults = handler.getResultStacks(recipeIndex);

if (pStackResult == null) {
if (pStackResults.isEmpty()) {
for (PositionedStack otherStack : handler.getOtherStacks(recipeIndex)) {
if (!FluidContainerRegistry.isContainer(otherStack.items[0])
|| StackInfo.getFluid(otherStack.items[0]) != null) {
pStackResult = otherStack;
pStackResults.add(otherStack);
break;
}
}
}

return new RecipeId(extractItem(pStackResult), handlerName, extractIngredients(ingredients));
return new RecipeId(
extractItem(!pStackResults.isEmpty() ? pStackResults.get(0) : null),
handlerName,
extractIngredients(ingredients));
}

public static RecipeId of(JsonObject json) {
Expand Down Expand Up @@ -389,8 +396,12 @@ public static Recipe of(IRecipeHandler handler, int recipeIndex) {
ingredients.add(RecipeIngredient.of(positionedStack));
}

if (handler.getResultStack(recipeIndex) != null) {
results.add(RecipeIngredient.of(handler.getResultStack(recipeIndex)));
final List<PositionedStack> resultStacks = handler.getResultStacks(recipeIndex);
Comment thread
sbancuz marked this conversation as resolved.

if (!resultStacks.isEmpty()) {
for (PositionedStack positionedStack : resultStacks) {
results.add(RecipeIngredient.of(positionedStack));
}
} else {
for (PositionedStack positionedStack : handler.getOtherStacks(recipeIndex)) {
results.add(RecipeIngredient.of(positionedStack));
Expand Down
60 changes: 57 additions & 3 deletions src/main/java/codechicken/nei/recipe/TemplateRecipeHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -132,7 +133,48 @@ public abstract class CachedRecipe {
public abstract PositionedStack getResult();

/**
* The ingredients required to produce the result Use this if you have more than one ingredient
* The multiple items produced by this recipe, with position
*
* @return A list of positioned ingredient items.
*/
public List<PositionedStack> getResults() {
ArrayList<PositionedStack> stacks = new ArrayList<>();
try {
PositionedStack stack = getResult();
if (stack != null) stacks.add(stack);
} catch (ArithmeticException e) {
NEIClientConfig.logger.error("Error in getOtherStacks: " + e);
}
return stacks;
}

/**
* Return extra items that are not directly involved in the ingredient->result relationship. Eg fuels.
*
* @return A list of positioned ingredient items.
*/
public List<PositionedStack> getCatalysts() {
ArrayList<PositionedStack> stacks = new ArrayList<>();
try {
PositionedStack stack = getCatalyst();
if (stack != null) stacks.add(stack);
} catch (ArithmeticException e) {
NEIClientConfig.logger.error("Error in getCatalysts: " + e);
}
return stacks;
}

/**
* Simple utility
*
* @return The another positioned stack
*/
public PositionedStack getCatalyst() {
return null;
}

/**
* The ingredients required to produce the result. Use this if you have more than one ingredient
*
* @return A list of positioned ingredient items.
*/
Expand All @@ -151,6 +193,8 @@ public PositionedStack getIngredient() {
}

/**
* Legacy API
*
* Return extra items that are not directly involved in the ingredient->result relationship. Eg fuels. Use this
* if you have more than one other stack
*
Expand Down Expand Up @@ -625,13 +669,23 @@ public List<PositionedStack> getIngredientStacks(int recipe) {
}

public PositionedStack getResultStack(int recipe) {
List<PositionedStack> results = getResultStacks(recipe);
if (results == null || results.isEmpty()) return null;
return results.get(0);
}

public List<PositionedStack> getResultStacks(int recipe) {
try {
return arecipes.get(recipe).getResult();
return arecipes.get(recipe).getResults();
} catch (ArrayIndexOutOfBoundsException ignored) {
return null;
return Collections.emptyList();
}
}

public List<PositionedStack> getCatalystStacks(int recipe) {
return arecipes.get(recipe).getCatalysts();
}

public List<PositionedStack> getOtherStacks(int recipe) {
return arecipes.get(recipe).getOtherStacks();
}
Expand Down