Add ore dictionary support for Inscriber recipes in JEI (#430)

This commit is contained in:
zeng-git
2024-05-24 18:51:37 +08:00
committed by GitHub
parent 08a7aff600
commit 59edb38208
10 changed files with 127 additions and 108 deletions
@@ -19,12 +19,11 @@
package appeng.api.features; package appeng.api.features;
import java.util.List; import net.minecraft.item.ItemStack;
import java.util.Optional;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.List;
import net.minecraft.item.ItemStack; import java.util.Optional;
/** /**
@@ -57,21 +56,35 @@ public interface IInscriberRecipe
@Nonnull @Nonnull
ItemStack getOutput(); ItemStack getOutput();
@Nonnull
List<ItemStack> getTopInputs();
/** /**
* gets the top optional * gets the top optional
* *
* @return item which is used top * @return item which is used top
*/ */
@Deprecated
@Nonnull @Nonnull
Optional<ItemStack> getTopOptional(); default Optional<ItemStack> getTopOptional(){
return getTopInputs().isEmpty() ? Optional.empty() : Optional.of(getTopInputs().get(0));
}
@Nonnull
List<ItemStack> getBottomInputs();
/** /**
* gets the bottom optional * gets the bottom optional
* *
* @return item which is used bottom * @return item which is used bottom
*/ */
@Deprecated
@Nonnull @Nonnull
Optional<ItemStack> getBottomOptional(); default Optional<ItemStack> getBottomOptional() {
return getBottomInputs().isEmpty() ? Optional.empty() : Optional.of(getBottomInputs().get(0));
}
/** /**
* type of inscriber process * type of inscriber process
@@ -19,11 +19,11 @@
package appeng.api.features; package appeng.api.features;
import java.util.Collection; import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Collection;
import net.minecraft.item.ItemStack; import java.util.Collections;
/** /**
@@ -66,7 +66,7 @@ public interface IInscriberRecipeBuilder
* @return currently used builder * @return currently used builder
*/ */
@Nonnull @Nonnull
IInscriberRecipeBuilder withTopOptional( @Nonnull ItemStack topOptional ); IInscriberRecipeBuilder withTopOptional(@Nonnull Collection<ItemStack> topOptional );
/** /**
* Creates an inscriber recipe with bot. * Creates an inscriber recipe with bot.
@@ -77,7 +77,7 @@ public interface IInscriberRecipeBuilder
* @return currently used builder * @return currently used builder
*/ */
@Nonnull @Nonnull
IInscriberRecipeBuilder withBottomOptional( @Nonnull ItemStack bottomOptional ); IInscriberRecipeBuilder withBottomOptional( @Nonnull Collection<ItemStack> bottomOptional );
/** /**
* Creates an inscriber recipe with type. * Creates an inscriber recipe with type.
@@ -104,4 +104,14 @@ public interface IInscriberRecipeBuilder
*/ */
@Nonnull @Nonnull
IInscriberRecipe build(); IInscriberRecipe build();
@Deprecated
default IInscriberRecipeBuilder withTopOptional(@Nonnull ItemStack topOptional){
return withTopOptional(Collections.singleton(topOptional));
}
@Deprecated
default IInscriberRecipeBuilder withBottomOptional(@Nonnull ItemStack bottomOptional){
return withBottomOptional(Collections.singleton(bottomOptional));
}
} }
@@ -116,15 +116,19 @@ public class ContainerInscriber extends ContainerUpgradeable implements IProgres
boolean matches = false; boolean matches = false;
for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) { for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) {
final boolean matchA = !top // Check if plateA matches any item in the list of top components of the recipe
.isEmpty() && (Platform.itemComparisons().isSameItem(top, recipe.getTopOptional().orElse(ItemStack.EMPTY)) || Platform final boolean matchA = top.isEmpty() && recipe.getTopInputs().isEmpty() ||
.itemComparisons() recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(top, topItem)) &&
.isSameItem(top, recipe.getBottomOptional().orElse(ItemStack.EMPTY))); (bot.isEmpty() && recipe.getBottomInputs().isEmpty() ||
final boolean matchB = !bot recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(bot, bottomItem)));
.isEmpty() && (Platform.itemComparisons().isSameItem(bot, recipe.getTopOptional().orElse(ItemStack.EMPTY)) || Platform
.itemComparisons()
.isSameItem(bot, recipe.getBottomOptional().orElse(ItemStack.EMPTY)));
// Check if plateB matches any item in the list of top components of the recipe
final boolean matchB = bot.isEmpty() && recipe.getTopInputs().isEmpty() ||
recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(bot, topItem)) &&
(top.isEmpty() && recipe.getBottomInputs().isEmpty() ||
recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(top, bottomItem)));
// If either matchA or matchB is true, iterate through the recipe's inputs
if (matchA || matchB) { if (matchA || matchB) {
matches = true; matches = true;
for (final ItemStack option : recipe.getInputs()) { for (final ItemStack option : recipe.getInputs()) {
@@ -152,10 +156,22 @@ public class ContainerInscriber extends ContainerUpgradeable implements IProgres
// everything else // everything else
for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) { for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) {
boolean isValid = false; boolean isValid = false;
if (Platform.itemComparisons().isSameItem(otherSlot, recipe.getTopOptional().orElse(ItemStack.EMPTY))) { // Check if otherSlot matches any item in the top component list
isValid = Platform.itemComparisons().isSameItem(is, recipe.getBottomOptional().orElse(ItemStack.EMPTY)); boolean matchTop = recipe.getTopInputs().stream()
} else if (Platform.itemComparisons().isSameItem(otherSlot, recipe.getBottomOptional().orElse(ItemStack.EMPTY))) { .anyMatch(topItem -> Platform.itemComparisons().isSameItem(otherSlot, topItem));
isValid = Platform.itemComparisons().isSameItem(is, recipe.getTopOptional().orElse(ItemStack.EMPTY));
// Check if otherSlot matches any item in the bottom component list
boolean matchBottom = recipe.getBottomInputs().stream()
.anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(otherSlot, bottomItem));
if (matchTop) {
// If otherSlot matches a top component, check if 'is' matches any item in the bottom component list
isValid = recipe.getBottomInputs().stream()
.anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(is, bottomItem));
} else if (matchBottom) {
// If otherSlot matches a bottom component, check if 'is' matches any item in the top component list
isValid = recipe.getTopInputs().stream()
.anyMatch(topItem -> Platform.itemComparisons().isSameItem(is, topItem));
} }
if (isValid) { if (isValid) {
@@ -25,6 +25,7 @@ import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
@@ -35,7 +36,7 @@ import java.util.Collection;
* @since rv2 * @since rv2
*/ */
public class InscriberInscribeRecipe extends InscriberRecipe { public class InscriberInscribeRecipe extends InscriberRecipe {
InscriberInscribeRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final ItemStack top, @Nullable final ItemStack bot) { InscriberInscribeRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final List<ItemStack> top, @Nullable final List<ItemStack> bot) {
super(inputs, output, top, bot, InscriberProcessType.INSCRIBE); super(inputs, output, top, bot, InscriberProcessType.INSCRIBE);
} }
} }
@@ -28,7 +28,6 @@ import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
@@ -46,21 +45,21 @@ public class InscriberRecipe implements IInscriberRecipe {
private final ItemStack output; private final ItemStack output;
@Nonnull @Nonnull
private final Optional<ItemStack> maybeTop; private final List<ItemStack> maybeTop;
@Nonnull @Nonnull
private final Optional<ItemStack> maybeBot; private final List<ItemStack> maybeBot;
@Nonnull @Nonnull
private final InscriberProcessType type; private final InscriberProcessType type;
InscriberRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final ItemStack top, @Nullable final ItemStack bot, @Nonnull final InscriberProcessType type) { InscriberRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final List<ItemStack> top, @Nullable final List<ItemStack> bot, @Nonnull final InscriberProcessType type) {
this.inputs = new ArrayList<>(inputs.size()); this.inputs = new ArrayList<>(inputs.size());
this.inputs.addAll(inputs); this.inputs.addAll(inputs);
this.output = output; this.output = output;
this.maybeTop = Optional.ofNullable(top); this.maybeTop = top;
this.maybeBot = Optional.ofNullable(bot); this.maybeBot = bot;
this.type = type; this.type = type;
} }
@@ -79,13 +78,13 @@ public class InscriberRecipe implements IInscriberRecipe {
@Nonnull @Nonnull
@Override @Override
public final Optional<ItemStack> getTopOptional() { public final List<ItemStack> getTopInputs() {
return this.maybeTop; return this.maybeTop;
} }
@Nonnull @Nonnull
@Override @Override
public final Optional<ItemStack> getBottomOptional() { public final List<ItemStack> getBottomInputs() {
return this.maybeBot; return this.maybeBot;
} }
@@ -112,10 +111,10 @@ public class InscriberRecipe implements IInscriberRecipe {
if (!this.output.equals(that.getOutput())) { if (!this.output.equals(that.getOutput())) {
return false; return false;
} }
if (!this.maybeTop.equals(that.getTopOptional())) { if (!this.maybeTop.equals(that.getTopInputs())) {
return false; return false;
} }
if (!this.maybeBot.equals(that.getBottomOptional())) { if (!this.maybeBot.equals(that.getBottomInputs())) {
return false; return false;
} }
return this.type == that.getProcessType(); return this.type == that.getProcessType();
@@ -130,4 +129,6 @@ public class InscriberRecipe implements IInscriberRecipe {
result = 31 * result + this.type.hashCode(); result = 31 * result + this.type.hashCode();
return result; return result;
} }
} }
@@ -75,9 +75,8 @@ public final class InscriberRegistry implements IInscriberRegistry {
Preconditions.checkNotNull(recipe, "Tried to add (null) as inscriber recipe to the registry."); Preconditions.checkNotNull(recipe, "Tried to add (null) as inscriber recipe to the registry.");
if (this.recipes.add(recipe)) { if (this.recipes.add(recipe)) {
recipe.getTopOptional().ifPresent(this.optionals::add); this.optionals.addAll(recipe.getTopInputs());
recipe.getBottomOptional().ifPresent(this.optionals::add); this.optionals.addAll(recipe.getBottomInputs());
this.inputs.addAll(recipe.getInputs()); this.inputs.addAll(recipe.getInputs());
return true; return true;
@@ -110,8 +109,8 @@ public final class InscriberRegistry implements IInscriberRegistry {
private static final class Builder implements IInscriberRecipeBuilder { private static final class Builder implements IInscriberRecipeBuilder {
private List<ItemStack> inputs; private List<ItemStack> inputs;
private ItemStack output; private ItemStack output;
private ItemStack topOptional; private List<ItemStack> topOptional;
private ItemStack bottomOptional; private List<ItemStack> bottomOptional;
private InscriberProcessType type; private InscriberProcessType type;
@Nonnull @Nonnull
@@ -139,22 +138,22 @@ public final class InscriberRegistry implements IInscriberRegistry {
@Nonnull @Nonnull
@Override @Override
public Builder withTopOptional(@Nonnull final ItemStack topOptional) { public Builder withTopOptional(@Nonnull final Collection<ItemStack> topOptional) {
Preconditions.checkNotNull(topOptional); Preconditions.checkNotNull(topOptional);
Preconditions.checkArgument(!topOptional.isEmpty());
this.topOptional = topOptional; this.topOptional = new ArrayList<>(topOptional.size());
this.topOptional.addAll(topOptional);
return this; return this;
} }
@Nonnull @Nonnull
@Override @Override
public Builder withBottomOptional(@Nonnull final ItemStack bottomOptional) { public Builder withBottomOptional(@Nonnull final Collection<ItemStack> bottomOptional) {
Preconditions.checkNotNull(bottomOptional); Preconditions.checkNotNull(bottomOptional);
Preconditions.checkArgument(!bottomOptional.isEmpty());
this.bottomOptional = bottomOptional; this.bottomOptional = new ArrayList<>(bottomOptional.size());
this.bottomOptional.addAll(bottomOptional);
return this; return this;
} }
@@ -31,9 +31,7 @@ import net.minecraft.item.ItemStack;
import stanhebben.zenscript.annotations.ZenClass; import stanhebben.zenscript.annotations.ZenClass;
import stanhebben.zenscript.annotations.ZenMethod; import stanhebben.zenscript.annotations.ZenMethod;
import java.util.Collection; import java.util.*;
import java.util.Collections;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -49,25 +47,15 @@ public class InscriberRecipes {
return; return;
} }
Collection<ItemStack> topList = CTModule.toStacks(top).orElse(Collections.singleton(ItemStack.EMPTY)); List<ItemStack> topList = new ArrayList<>(CTModule.toStacks(top).orElse(Collections.singleton(ItemStack.EMPTY)));
Collection<ItemStack> bottomList = CTModule.toStacks(bottom).orElse(Collections.singleton(ItemStack.EMPTY)); List<ItemStack> bottomList = new ArrayList<>(CTModule.toStacks(bottom).orElse(Collections.singleton(ItemStack.EMPTY)));
final IInscriberRecipeBuilder builder = AEApi.instance().registries().inscriber().builder();
for (ItemStack topStack : topList) { builder.withProcessType(inscribe ? InscriberProcessType.INSCRIBE : InscriberProcessType.PRESS).
for (ItemStack bottomStack : bottomList) { withTopOptional(topList).
final IInscriberRecipeBuilder builder = AEApi.instance().registries().inscriber().builder(); withBottomOptional(bottomList).
builder.withProcessType(inscribe ? InscriberProcessType.INSCRIBE : InscriberProcessType.PRESS) withOutput(CTModule.toStack(output))
.withOutput(CTModule.toStack(output)) .withInputs(inStacks.get());
.withInputs(inStacks.get()); CTModule.MODIFICATIONS.add(new Add(builder.build()));
if (!topStack.isEmpty()) {
builder.withTopOptional(topStack);
}
if (!bottomStack.isEmpty()) {
builder.withBottomOptional(bottomStack);
}
CTModule.MODIFICATIONS.add(new Add(builder.build()));
}
}
} }
@ZenMethod @ZenMethod
@@ -21,11 +21,11 @@ package appeng.integration.modules.jei;
import appeng.api.features.IInscriberRecipe; import appeng.api.features.IInscriberRecipe;
import mezz.jei.api.ingredients.IIngredients; import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.ingredients.VanillaTypes;
import mezz.jei.api.recipe.IRecipeWrapper; import mezz.jei.api.recipe.IRecipeWrapper;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
@@ -40,11 +40,10 @@ class InscriberRecipeWrapper implements IRecipeWrapper {
@Override @Override
public void getIngredients(IIngredients ingredients) { public void getIngredients(IIngredients ingredients) {
List<List<ItemStack>> inputSlots = new ArrayList<>(3); List<List<ItemStack>> inputSlots = new ArrayList<>(3);
inputSlots.add(Collections.singletonList(this.recipe.getTopOptional().orElse(ItemStack.EMPTY))); inputSlots.add(this.recipe.getTopInputs());
inputSlots.add(this.recipe.getInputs()); inputSlots.add(this.recipe.getInputs());
inputSlots.add(Collections.singletonList(this.recipe.getBottomOptional().orElse(ItemStack.EMPTY))); inputSlots.add(this.recipe.getBottomInputs());
ingredients.setInputLists(ItemStack.class, inputSlots); ingredients.setInputLists(VanillaTypes.ITEM, inputSlots);
ingredients.setOutput(VanillaTypes.ITEM, this.recipe.getOutput());
ingredients.setOutput(ItemStack.class, this.recipe.getOutput());
} }
} }
@@ -14,6 +14,7 @@ import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.common.crafting.JsonContext; import net.minecraftforge.common.crafting.JsonContext;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
@@ -27,34 +28,25 @@ public class InscriberHandler implements IAERecipeFactory {
JsonObject ingredients = JsonUtils.getJsonObject(json, "ingredients"); JsonObject ingredients = JsonUtils.getJsonObject(json, "ingredients");
List<ItemStack> middle = Arrays.asList(CraftingHelper.getIngredient(ingredients.get("middle"), ctx).getMatchingStacks()); List<ItemStack> middle = Arrays.asList(CraftingHelper.getIngredient(ingredients.get("middle"), ctx).getMatchingStacks());
ItemStack[] top = new ItemStack[]{null}; List<ItemStack> top = Collections.emptyList();
if (ingredients.has("top")) { if (ingredients.has("top")) {
top = CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "top"), ctx).getMatchingStacks(); top = Arrays.asList(CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "top"), ctx).getMatchingStacks());
} }
ItemStack[] bottom = new ItemStack[]{null}; List<ItemStack> bottom = Collections.emptyList();
if (ingredients.has("bottom")) { if (ingredients.has("bottom")) {
bottom = CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "bottom"), ctx).getMatchingStacks(); bottom = Arrays.asList(CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "bottom"), ctx).getMatchingStacks());
} }
final IInscriberRegistry reg = AEApi.instance().registries().inscriber(); final IInscriberRegistry reg = AEApi.instance().registries().inscriber();
for (int i = 0; i < top.length; ++i) { if (!top.isEmpty() || !bottom.isEmpty()) {
for (int j = 0; j < bottom.length; ++j) { final IInscriberRecipeBuilder builder = reg.builder();
final IInscriberRecipeBuilder builder = reg.builder(); builder.withOutput(result);
builder.withOutput(result); builder.withProcessType("press".equals(mode) ? InscriberProcessType.PRESS : InscriberProcessType.INSCRIBE);
builder.withProcessType("press".equals(mode) ? InscriberProcessType.PRESS : InscriberProcessType.INSCRIBE); builder.withTopOptional(top);
builder.withInputs(middle); builder.withInputs(middle);
builder.withBottomOptional(bottom);
if (top[i] != null) { reg.addRecipe(builder.build());
builder.withTopOptional(top[i]);
}
if (bottom[j] != null) {
builder.withBottomOptional(bottom[j]);
}
reg.addRecipe(builder.build());
}
} }
} }
} }
@@ -65,6 +65,7 @@ import net.minecraftforge.items.IItemHandlerModifiable;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
@@ -281,20 +282,19 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) { for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) {
final boolean matchA = (plateA.isEmpty() && !recipe.getTopOptional().isPresent()) || (Platform.itemComparisons() // Check if plateA matches any item in the list of top components of the recipe
.isSameItem(plateA, final boolean matchA = plateA.isEmpty() && recipe.getTopInputs().isEmpty() ||
recipe.getTopOptional().orElse(ItemStack.EMPTY))) && // and... recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(plateA, topItem)) &&
((plateB.isEmpty() && !recipe.getBottomOptional().isPresent()) || (Platform.itemComparisons() (plateB.isEmpty() && recipe.getBottomInputs().isEmpty() ||
.isSameItem(plateB, recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(plateB, bottomItem)));
recipe.getBottomOptional().orElse(ItemStack.EMPTY))));
final boolean matchB = (plateB.isEmpty() && !recipe.getTopOptional().isPresent()) || (Platform.itemComparisons() // Check if plateB matches any item in the list of top components of the recipe
.isSameItem(plateB, final boolean matchB = plateB.isEmpty() && recipe.getTopInputs().isEmpty() ||
recipe.getTopOptional().orElse(ItemStack.EMPTY))) && // and... recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(plateB, topItem)) &&
((plateA.isEmpty() && !recipe.getBottomOptional().isPresent()) || (Platform.itemComparisons() (plateA.isEmpty() && recipe.getBottomInputs().isEmpty() ||
.isSameItem(plateA, recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(plateA, bottomItem)));
recipe.getBottomOptional().orElse(ItemStack.EMPTY))));
// If either matchA or matchB is true, iterate through the recipe's inputs
if (matchA || matchB) { if (matchA || matchB) {
for (final ItemStack option : recipe.getInputs()) { for (final ItemStack option : recipe.getInputs()) {
if (Platform.itemComparisons().isSameItem(input, option)) { if (Platform.itemComparisons().isSameItem(input, option)) {
@@ -476,11 +476,11 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
builder.withInputs(inputs).withOutput(renamedItem).withProcessType(type); builder.withInputs(inputs).withOutput(renamedItem).withProcessType(type);
if (!plateA.isEmpty()) { if (!plateA.isEmpty()) {
builder.withTopOptional(plateA); builder.withTopOptional(Collections.singletonList(plateA));
} }
if (!plateB.isEmpty()) { if (!plateB.isEmpty()) {
builder.withBottomOptional(plateB); builder.withBottomOptional(Collections.singletonList(plateB));
} }
return builder.build(); return builder.build();