Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow recycling recipes to generate from assembler #2012

Merged
merged 1 commit into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 6 additions & 94 deletions src/main/java/gregtech/api/recipes/ModHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import gregtech.api.items.toolitem.ToolHelper;
import gregtech.api.recipes.recipes.DummyRecipe;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.material.MarkerMaterial;
import gregtech.api.unification.material.Material;
import gregtech.api.unification.material.Materials;
import gregtech.api.unification.material.properties.PropertyKey;
Expand All @@ -26,10 +25,6 @@
import gregtech.common.crafting.GTShapedOreRecipe;
import gregtech.common.crafting.GTShapelessOreRecipe;
import gregtech.common.crafting.ShapedOreEnergyTransferRecipe;
import it.unimi.dsi.fastutil.chars.Char2IntFunction;
import it.unimi.dsi.fastutil.chars.Char2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
Expand All @@ -48,6 +43,7 @@
import net.minecraftforge.registries.IForgeRegistry;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.ApiStatus;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -290,7 +286,7 @@ public static void addShapedRecipe(boolean withUnificationData, @Nonnull String
addRecipe(regName, result, isNBTClearing, isMirrored, recipe);

if (withUnificationData) {
OreDictUnifier.registerOre(result, getRecyclingIngredients(result.getCount(), recipe));
OreDictUnifier.registerOre(result, RecyclingHandler.getRecyclingIngredients(result.getCount(), recipe));
}
}

Expand Down Expand Up @@ -437,97 +433,13 @@ public static Object finalizeIngredient(@Nonnull Object ingredient) {
* @param outputCount the amount of outputs the recipe has
* @param recipe the recipe to retrieve from
* @return the recycling ingredients for a recipe
* @deprecated Use {@link RecyclingHandler#getRecyclingIngredients(int, Object...)}. Will be removed in 2.9
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.9")
@Nullable
public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @Nonnull Object... recipe) {
Char2IntOpenHashMap inputCountMap = new Char2IntOpenHashMap();
Object2LongMap<Material> materialStacksExploded = new Object2LongOpenHashMap<>();

int itr = 0;
while (recipe[itr] instanceof String s) {
for (char c : s.toCharArray()) {
if (ToolHelper.getToolFromSymbol(c) != null) continue; // skip tools
int count = inputCountMap.getOrDefault(c, 0);
inputCountMap.put(c, count + 1);
}
itr++;
}

char lastChar = ' ';
for (int i = itr; i < recipe.length; i++) {
Object ingredient = recipe[i];

// Track the current working ingredient symbol
if (ingredient instanceof Character) {
lastChar = (char) ingredient;
continue;
}

// Should never happen if recipe is formatted correctly
// In the case that it isn't, this error should be handled
// by an earlier method call parsing the recipe.
if (lastChar == ' ') return null;

ItemStack stack;
if (ingredient instanceof MetaItem.MetaValueItem) {
stack = ((MetaItem<?>.MetaValueItem) ingredient).getStackForm();
} else if (ingredient instanceof UnificationEntry) {
stack = OreDictUnifier.get((UnificationEntry) ingredient);
} else if (ingredient instanceof ItemStack) {
stack = (ItemStack) ingredient;
} else if (ingredient instanceof Item) {
stack = new ItemStack((Item) ingredient, 1);
} else if (ingredient instanceof Block) {
stack = new ItemStack((Block) ingredient, 1);
} else if (ingredient instanceof String) {
stack = OreDictUnifier.get((String) ingredient);
} else continue; // throw out bad entries

// First try to get ItemMaterialInfo
ItemMaterialInfo info = OreDictUnifier.getMaterialInfo(stack);
if (info != null) {
for (MaterialStack ms : info.getMaterials()) {
if (!(ms.material instanceof MarkerMaterial)) {
addMaterialStack(materialStacksExploded, inputCountMap, ms, lastChar);
}
}
continue;
}

// Then try to get a single Material (UnificationEntry needs this, for example)
MaterialStack materialStack = OreDictUnifier.getMaterial(stack);
if (materialStack != null && !(materialStack.material instanceof MarkerMaterial)) {
addMaterialStack(materialStacksExploded, inputCountMap, materialStack, lastChar);
}

// Gather any secondary materials if this item has an OrePrefix
OrePrefix prefix = OreDictUnifier.getPrefix(stack);
if (prefix != null && !prefix.secondaryMaterials.isEmpty()) {
for (MaterialStack ms : prefix.secondaryMaterials) {
addMaterialStack(materialStacksExploded, inputCountMap, ms, lastChar);
}
}
}

return new ItemMaterialInfo(materialStacksExploded.entrySet().stream()
.map(e -> new MaterialStack(e.getKey(), e.getValue() / outputCount))
.sorted(Comparator.comparingLong(m -> -m.amount))
.collect(Collectors.toList())
);
}

/**
* Adds a MaterialStack to a map of {@code <Material, Quantity>}
*
* @param materialStacksExploded the map to add to
* @param inputCountMap the map supplying quantities by char
* @param ms the stack to add
* @param c the char for quantities
*/
private static void addMaterialStack(@Nonnull Object2LongMap<Material> materialStacksExploded,
@Nonnull Char2IntFunction inputCountMap, @Nonnull MaterialStack ms, char c) {
long amount = materialStacksExploded.getOrDefault(ms.material, 0L);
materialStacksExploded.put(ms.material, (ms.amount * inputCountMap.get(c)) + amount);
return RecyclingHandler.getRecyclingIngredients(outputCount, recipe);
}

/**
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/gregtech/api/recipes/RecipeMaps.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
import gregtech.api.recipes.builders.*;
import gregtech.api.recipes.ingredients.GTRecipeInput;
import gregtech.api.recipes.machines.*;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.material.Materials;
import gregtech.api.unification.stack.ItemMaterialInfo;
import gregtech.api.util.AssemblyLineManager;
import gregtech.core.sound.GTSoundEvents;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import stanhebben.zenscript.annotations.ZenClass;
import stanhebben.zenscript.annotations.ZenProperty;

Expand Down Expand Up @@ -111,6 +114,15 @@ public class RecipeMaps {

recipeBuilder.copy().clearFluidInputs().fluidInputs(Materials.Tin.getFluid(amount * 2)).buildAndRegister();
}

if (recipeBuilder.isWithRecycling()) {
// ignore input fluids for recycling
ItemStack outputStack = recipeBuilder.getOutputs().get(0);
ItemMaterialInfo info = RecyclingHandler.getRecyclingIngredients(recipeBuilder.getInputs(), outputStack.getCount());
if (info != null) {
OreDictUnifier.registerOre(outputStack, info);
}
}
});

/**
Expand Down
139 changes: 139 additions & 0 deletions src/main/java/gregtech/api/recipes/RecyclingHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package gregtech.api.recipes;

import gregtech.api.items.metaitem.MetaItem;
import gregtech.api.items.toolitem.ToolHelper;
import gregtech.api.recipes.ingredients.GTRecipeInput;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.material.MarkerMaterial;
import gregtech.api.unification.material.Material;
import gregtech.api.unification.ore.OrePrefix;
import gregtech.api.unification.stack.ItemMaterialInfo;
import gregtech.api.unification.stack.MaterialStack;
import gregtech.api.unification.stack.UnificationEntry;
import it.unimi.dsi.fastutil.chars.Char2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class RecyclingHandler {

public static @Nullable ItemMaterialInfo getRecyclingIngredients(int outputCount, @NotNull Object... recipe) {
Char2IntOpenHashMap inputCountMap = new Char2IntOpenHashMap();
Object2LongMap<Material> materialStacksExploded = new Object2LongOpenHashMap<>();

int itr = 0;
while (recipe[itr] instanceof String s) {
for (char c : s.toCharArray()) {
if (ToolHelper.getToolFromSymbol(c) != null) continue; // skip tools
int count = inputCountMap.getOrDefault(c, 0);
inputCountMap.put(c, count + 1);
}
itr++;
}

char lastChar = ' ';
for (int i = itr; i < recipe.length; i++) {
Object ingredient = recipe[i];

// Track the current working ingredient symbol
if (ingredient instanceof Character) {
lastChar = (char) ingredient;
continue;
}

// Should never happen if recipe is formatted correctly
// In the case that it isn't, this error should be handled
// by an earlier method call parsing the recipe.
if (lastChar == ' ') return null;

ItemStack stack;
if (ingredient instanceof MetaItem.MetaValueItem) {
stack = ((MetaItem<?>.MetaValueItem) ingredient).getStackForm();
} else if (ingredient instanceof UnificationEntry) {
stack = OreDictUnifier.get((UnificationEntry) ingredient);
} else if (ingredient instanceof ItemStack) {
stack = (ItemStack) ingredient;
} else if (ingredient instanceof Item) {
stack = new ItemStack((Item) ingredient, 1);
} else if (ingredient instanceof Block) {
stack = new ItemStack((Block) ingredient, 1);
} else if (ingredient instanceof String) {
stack = OreDictUnifier.get((String) ingredient);
} else continue; // throw out bad entries

addItemStackToMaterialStacks(stack, materialStacksExploded, inputCountMap.get(lastChar));
}

return new ItemMaterialInfo(materialStacksExploded.entrySet().stream()
.map(e -> new MaterialStack(e.getKey(), e.getValue() / outputCount))
.sorted(Comparator.comparingLong(m -> -m.amount))
.collect(Collectors.toList())
);
}

public static @Nullable ItemMaterialInfo getRecyclingIngredients(List<GTRecipeInput> inputs, int outputCount) {
Object2LongMap<Material> materialStacksExploded = new Object2LongOpenHashMap<>();
for (GTRecipeInput input : inputs) {
if (input == null) continue;
ItemStack[] inputStacks = input.getInputStacks();
if (inputStacks == null || inputStacks.length == 0) continue;
ItemStack inputStack = inputStacks[0];
addItemStackToMaterialStacks(inputStack, materialStacksExploded, inputStack.getCount());
}

return new ItemMaterialInfo(materialStacksExploded.entrySet().stream()
.map(e -> new MaterialStack(e.getKey(), e.getValue() / outputCount))
.sorted(Comparator.comparingLong(m -> -m.amount))
.collect(Collectors.toList()));
}

private static void addItemStackToMaterialStacks(@NotNull ItemStack itemStack,
@NotNull Object2LongMap<Material> materialStacksExploded,
int inputCount) {
// First try to get ItemMaterialInfo
ItemMaterialInfo info = OreDictUnifier.getMaterialInfo(itemStack);
if (info != null) {
for (MaterialStack ms : info.getMaterials()) {
if (!(ms.material instanceof MarkerMaterial)) {
addMaterialStack(materialStacksExploded, inputCount, ms);
}
}
return;
}

// Then try to get a single Material (UnificationEntry needs this, for example)
MaterialStack materialStack = OreDictUnifier.getMaterial(itemStack);
if (materialStack != null && !(materialStack.material instanceof MarkerMaterial)) {
addMaterialStack(materialStacksExploded, inputCount, materialStack);
}

// Gather any secondary materials if this item has an OrePrefix
OrePrefix prefix = OreDictUnifier.getPrefix(itemStack);
if (prefix != null && !prefix.secondaryMaterials.isEmpty()) {
for (MaterialStack ms : prefix.secondaryMaterials) {
addMaterialStack(materialStacksExploded, inputCount, ms);
}
}
}

/**
* Adds a MaterialStack to a map of {@code <Material, Quantity>}
*
* @param materialStacksExploded the map to add to
* @param inputCount the number of items in the stack
* @param ms the stack to add
*/
private static void addMaterialStack(@NotNull Object2LongMap<Material> materialStacksExploded,
int inputCount, @NotNull MaterialStack ms) {
long amount = materialStacksExploded.getOrDefault(ms.material, 0L);
materialStacksExploded.put(ms.material, (ms.amount * inputCount) + amount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

public class AssemblerRecipeBuilder extends RecipeBuilder<AssemblerRecipeBuilder> {

private boolean withRecycling;

public AssemblerRecipeBuilder() {/**/}

@SuppressWarnings("unused")
Expand All @@ -15,10 +17,26 @@ public AssemblerRecipeBuilder(Recipe recipe, RecipeMap<AssemblerRecipeBuilder> r

public AssemblerRecipeBuilder(AssemblerRecipeBuilder recipeBuilder) {
super(recipeBuilder);
if (recipeBuilder.isWithRecycling()) {
this.withRecycling = true;
}
}

@Override
public AssemblerRecipeBuilder copy() {
return new AssemblerRecipeBuilder(this);
var builder = new AssemblerRecipeBuilder(this);
if (withRecycling) {
return builder.withRecycling();
}
return builder;
}

public AssemblerRecipeBuilder withRecycling() {
withRecycling = true;
return this;
}

public boolean isWithRecycling() {
return withRecycling;
}
}
5 changes: 5 additions & 0 deletions src/main/java/gregtech/loaders/recipe/ComponentRecipes.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ public static void register() {
.outputs(FLUID_REGULATOR_LV.getStackForm())
.EUt(VA[LV])
.duration(400)
.withRecycling()
.buildAndRegister();

ASSEMBLER_RECIPES.recipeBuilder()
Expand All @@ -361,6 +362,7 @@ public static void register() {
.outputs(FLUID_REGULATOR_MV.getStackForm())
.EUt(VA[MV])
.duration(350)
.withRecycling()
.buildAndRegister();

ASSEMBLER_RECIPES.recipeBuilder()
Expand All @@ -370,6 +372,7 @@ public static void register() {
.outputs(FLUID_REGULATOR_HV.getStackForm())
.EUt(VA[HV])
.duration(300)
.withRecycling()
.buildAndRegister();

ASSEMBLER_RECIPES.recipeBuilder()
Expand All @@ -379,6 +382,7 @@ public static void register() {
.outputs(FLUID_REGULATOR_EV.getStackForm())
.EUt(VA[EV])
.duration(250)
.withRecycling()
.buildAndRegister();

ASSEMBLER_RECIPES.recipeBuilder()
Expand All @@ -388,6 +392,7 @@ public static void register() {
.outputs(FLUID_REGULATOR_IV.getStackForm())
.EUt(VA[IV])
.duration(200)
.withRecycling()
.buildAndRegister();

ASSEMBLER_RECIPES.recipeBuilder()
Expand Down
Loading