aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/util/GTRecipeConstants.java
diff options
context:
space:
mode:
authorNotAPenguin <michiel.vandeginste@gmail.com>2024-09-02 23:17:17 +0200
committerGitHub <noreply@github.com>2024-09-02 23:17:17 +0200
commit1b820de08a05070909a267e17f033fcf58ac8710 (patch)
tree02831a025986a06b20f87e5bcc69d1e0c639a342 /src/main/java/gregtech/api/util/GTRecipeConstants.java
parentafd3fd92b6a6ab9ab0d0dc3214e6bc8ff7a86c9b (diff)
downloadGT5-Unofficial-1b820de08a05070909a267e17f033fcf58ac8710.tar.gz
GT5-Unofficial-1b820de08a05070909a267e17f033fcf58ac8710.tar.bz2
GT5-Unofficial-1b820de08a05070909a267e17f033fcf58ac8710.zip
The Great Renaming (#3014)
* move kekztech to a single root dir * move detrav to a single root dir * move gtnh-lanthanides to a single root dir * move tectech and delete some gross reflection in gt++ * remove more reflection inside gt5u * delete more reflection in gt++ * fix imports * move bartworks and bwcrossmod * fix proxies * move galactigreg and ggfab * move gtneioreplugin * try to fix gt++ bee loader * apply the rename rules to BW * apply rename rules to bwcrossmod * apply rename rules to detrav scanner mod * apply rename rules to galacticgreg * apply rename rules to ggfab * apply rename rules to goodgenerator * apply rename rules to gtnh-lanthanides * apply rename rules to gt++ * apply rename rules to kekztech * apply rename rules to kubatech * apply rename rules to tectech * apply rename rules to gt apply the rename rules to gt * fix tt import * fix mui hopefully * fix coremod except intergalactic * rename assline recipe class * fix a class name i stumbled on * rename StructureUtility to GTStructureUtility to prevent conflict with structurelib * temporary rename of GTTooltipDataCache to old name * fix gt client/server proxy names
Diffstat (limited to 'src/main/java/gregtech/api/util/GTRecipeConstants.java')
-rw-r--r--src/main/java/gregtech/api/util/GTRecipeConstants.java691
1 files changed, 691 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/util/GTRecipeConstants.java b/src/main/java/gregtech/api/util/GTRecipeConstants.java
new file mode 100644
index 0000000000..82a477756a
--- /dev/null
+++ b/src/main/java/gregtech/api/util/GTRecipeConstants.java
@@ -0,0 +1,691 @@
+package gregtech.api.util;
+
+import static gregtech.api.recipe.RecipeMaps.scannerFakeRecipes;
+import static gregtech.api.util.GTRecipeMapUtil.convertCellToFluid;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Optional;
+
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+import cpw.mods.fml.common.registry.GameRegistry;
+import gregtech.api.enums.GTValues;
+import gregtech.api.enums.ItemList;
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.OrePrefixes;
+import gregtech.api.enums.TierEU;
+import gregtech.api.interfaces.IRecipeMap;
+import gregtech.api.objects.ItemData;
+import gregtech.api.recipe.RecipeCategories;
+import gregtech.api.recipe.RecipeMaps;
+import gregtech.api.recipe.RecipeMetadataKey;
+import gregtech.api.recipe.metadata.SimpleRecipeMetadataKey;
+import gregtech.common.items.IDMetaItem03;
+import gregtech.common.items.MetaGeneratedItem03;
+import gtnhlanth.common.item.ItemPhotolithographicMask;
+import gtnhlanth.common.item.MaskList;
+import gtnhlanth.common.register.LanthItemList;
+
+// this class is intended to be import-static-ed on every recipe script
+// so take care to not put unrelated stuff here!
+public class GTRecipeConstants {
+
+ /**
+ * Set to true to signal the recipe require low gravity. do nothing if recipe set specialValue explicitly. Can
+ * coexist with CLEANROOM just fine
+ */
+ public static final RecipeMetadataKey<Boolean> LOW_GRAVITY = SimpleRecipeMetadataKey
+ .create(Boolean.class, "low_gravity");
+ /**
+ * Set to true to signal the recipe require cleanroom. do nothing if recipe set specialValue explicitly. Can coexist
+ * with LOW_GRAVITY just fine
+ */
+ public static final RecipeMetadataKey<Boolean> CLEANROOM = SimpleRecipeMetadataKey
+ .create(Boolean.class, "cleanroom");
+ /**
+ * Common additive to use in recipe, e.g. for PBF, this is coal amount.
+ */
+ public static final RecipeMetadataKey<Integer> ADDITIVE_AMOUNT = SimpleRecipeMetadataKey
+ .create(Integer.class, "additives");
+ /**
+ * Used for fusion reactor. Denotes ignition threshold.
+ */
+ public static final RecipeMetadataKey<Integer> FUSION_THRESHOLD = SimpleRecipeMetadataKey
+ .create(Integer.class, "fusion_threshold");
+ /**
+ * Research time in a scanner used in ticks.
+ */
+ public static final RecipeMetadataKey<Integer> RESEARCH_TIME = SimpleRecipeMetadataKey
+ .create(Integer.class, "research_time");
+ /**
+ * Fuel type. TODO should we use enum directly?
+ */
+ public static final RecipeMetadataKey<Integer> FUEL_TYPE = SimpleRecipeMetadataKey
+ .create(Integer.class, "fuel_type");
+ /**
+ * Fuel value.
+ */
+ public static final RecipeMetadataKey<Integer> FUEL_VALUE = SimpleRecipeMetadataKey
+ .create(Integer.class, "fuel_value");
+ /**
+ * Required heat for heating coil (Kelvin).
+ */
+ public static final RecipeMetadataKey<Integer> COIL_HEAT = SimpleRecipeMetadataKey
+ .create(Integer.class, "coil_heat");
+ /**
+ * Research item used by assline recipes.
+ */
+ public static final RecipeMetadataKey<ItemStack> RESEARCH_ITEM = SimpleRecipeMetadataKey
+ .create(ItemStack.class, "research_item");
+ /**
+ * For assembler. It accepts a single item as oredict. It looks like no one uses this anyway...
+ */
+ public static final RecipeMetadataKey<Object> OREDICT_INPUT = SimpleRecipeMetadataKey
+ .create(Object.class, "oredict_input");
+ /**
+ * Replicator output material.
+ */
+ public static final RecipeMetadataKey<Materials> MATERIAL = SimpleRecipeMetadataKey
+ .create(Materials.class, "material");
+ /**
+ * Marker for {@link #UniversalArcFurnace} to tell that the recipe belongs to recycling category.
+ */
+ public static final RecipeMetadataKey<Boolean> RECYCLE = SimpleRecipeMetadataKey.create(Boolean.class, "recycle");
+ /**
+ * For Microwave.
+ */
+ public static final RecipeMetadataKey<Boolean> EXPLODE = SimpleRecipeMetadataKey.create(Boolean.class, "explode");
+ /**
+ * For Microwave.
+ */
+ public static final RecipeMetadataKey<Boolean> ON_FIRE = SimpleRecipeMetadataKey.create(Boolean.class, "on_fire");
+
+ /**
+ * Nano Forge Tier.
+ */
+ public static final RecipeMetadataKey<Integer> NANO_FORGE_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "nano_forge_tier");
+
+ /**
+ * FOG Exotic recipe tier.
+ */
+ public static final RecipeMetadataKey<Integer> FOG_EXOTIC_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "fog_exotic_tier");
+
+ /**
+ * FOG Plasma recipe tier.
+ */
+ public static final RecipeMetadataKey<Integer> FOG_PLASMA_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "fog_plasma_tier");
+
+ /**
+ * DEFC Casing tier.
+ */
+ public static final RecipeMetadataKey<Integer> DEFC_CASING_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "defc_casing_tier");
+
+ /**
+ * Chemplant Casing tier. Beware, codewise index starts at 0, but it is tier 1.
+ */
+ public static final RecipeMetadataKey<Integer> CHEMPLANT_CASING_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "chemplant_casing_tier");
+
+ /**
+ * QFT Focus tier.
+ */
+ public static final RecipeMetadataKey<Integer> QFT_FOCUS_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "qft_focus_tier");
+
+ /**
+ * Tier of advanced compression (HIP/black hole)
+ */
+ public static final RecipeMetadataKey<Integer> COMPRESSION_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "compression");
+
+ /**
+ * Dissolution Tank Ratio.
+ */
+ public static final RecipeMetadataKey<Integer> DISSOLUTION_TANK_RATIO = SimpleRecipeMetadataKey
+ .create(Integer.class, "dissolution_tank_ratio");
+
+ /**
+ * Duration in days for the RTG.
+ */
+ public static final RecipeMetadataKey<Integer> RTG_DURATION_IN_DAYS = SimpleRecipeMetadataKey
+ .create(Integer.class, "rtg_duration_in_days");
+
+ /**
+ * Basic output for the Large Naquadah Generator.
+ */
+ public static final RecipeMetadataKey<Integer> LNG_BASIC_OUTPUT = SimpleRecipeMetadataKey
+ .create(Integer.class, "lng_basic_output");
+
+ /**
+ * Coil tier for the Naquadah Fuel Refinery.
+ */
+ public static final RecipeMetadataKey<Integer> NFR_COIL_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "nfr_coil_tier");
+
+ /**
+ * NKE range for the neutron activator.
+ */
+ public static final RecipeMetadataKey<Integer> NKE_RANGE = SimpleRecipeMetadataKey
+ .create(Integer.class, "nke_range");
+ /**
+ * Precise Assembler casing tier.
+ */
+ public static final RecipeMetadataKey<Integer> PRECISE_ASSEMBLER_CASING_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "precise_assembler_casing_tier");
+ /**
+ * CoAL casing tier.
+ */
+ public static final RecipeMetadataKey<Integer> COAL_CASING_TIER = SimpleRecipeMetadataKey
+ .create(Integer.class, "coal_casing_tier");
+
+ /**
+ * LFTR output power.
+ */
+ public static final RecipeMetadataKey<Integer> LFTR_OUTPUT_POWER = SimpleRecipeMetadataKey
+ .create(Integer.class, "lftr_output_power");
+
+ /**
+ * Research Station data.
+ */
+ public static final RecipeMetadataKey<Integer> RESEARCH_STATION_DATA = SimpleRecipeMetadataKey
+ .create(Integer.class, "research_station_data");
+
+ /**
+ * glass tier required for the biovat recipes.
+ */
+ public static final RecipeMetadataKey<Integer> SIEVERTS = SimpleRecipeMetadataKey.create(Integer.class, "sieverts");
+
+ public static final RecipeMetadataKey<Integer> DECAY_TICKS = SimpleRecipeMetadataKey
+ .create(Integer.class, "decay_ticks");
+
+ public static final RecipeMetadataKey<Boolean> NOBLE_GASES = SimpleRecipeMetadataKey
+ .create(Boolean.class, "noble_gases");
+
+ public static final RecipeMetadataKey<Boolean> ANAEROBE_GASES = SimpleRecipeMetadataKey
+ .create(Boolean.class, "anaerobe_gases");
+
+ public static final RecipeMetadataKey<Boolean> NO_GAS = SimpleRecipeMetadataKey.create(Boolean.class, "no_gas");
+
+ /**
+ * Add a arc furnace recipe. Adds to both normal arc furnace and plasma arc furnace.
+ * Will override the fluid input with oxygen/plasma for the respective recipe maps, so there is no point setting it.
+ */
+ public static final IRecipeMap UniversalArcFurnace = IRecipeMap.newRecipeMap(builder -> {
+ if (!GTUtility.isArrayOfLength(builder.getItemInputsBasic(), 1)
+ || GTUtility.isArrayEmptyOrNull(builder.getItemOutputs())) return Collections.emptyList();
+ int aDuration = builder.getDuration();
+ if (aDuration <= 0) {
+ return Collections.emptyList();
+ }
+ builder.duration(aDuration);
+ boolean recycle = builder.getMetadataOrDefault(RECYCLE, false);
+ Collection<GTRecipe> ret = new ArrayList<>();
+ for (Materials mat : new Materials[] { Materials.Argon, Materials.Nitrogen }) {
+ int tPlasmaAmount = (int) Math.max(1L, aDuration / (mat.getMass() * 16L));
+ GTRecipeBuilder plasmaBuilder = builder.copy()
+ .fluidInputs(mat.getPlasma(tPlasmaAmount))
+ .fluidOutputs(mat.getGas(tPlasmaAmount));
+ if (recycle) {
+ plasmaBuilder.recipeCategory(RecipeCategories.plasmaArcFurnaceRecycling);
+ }
+ ret.addAll(RecipeMaps.plasmaArcFurnaceRecipes.doAdd(plasmaBuilder));
+ }
+ GTRecipeBuilder arcBuilder = builder.copy()
+ .fluidInputs(Materials.Oxygen.getGas(aDuration));
+ if (recycle) {
+ arcBuilder.recipeCategory(RecipeCategories.arcFurnaceRecycling);
+ }
+ ret.addAll(RecipeMaps.arcFurnaceRecipes.doAdd(arcBuilder));
+ return ret;
+ });
+
+ /**
+ * Add a chemical reactor recipe to both LCR and singleblocks.
+ */
+ public static final IRecipeMap UniversalChemical = IRecipeMap.newRecipeMap(builder -> {
+ for (ItemStack input : builder.getItemInputsBasic()) {
+ // config >= 10 -> this is a special chemical recipe that output fluid/canned fluid variant.
+ // it doesn't belong to multiblocks
+ if (GTUtility.isAnyIntegratedCircuit(input) && input.getItemDamage() >= 10) {
+ return builder.addTo(RecipeMaps.chemicalReactorRecipes);
+ }
+ }
+ return GTUtility.concat(
+ builder.copy()
+ .addTo(RecipeMaps.chemicalReactorRecipes),
+ convertCellToFluid(builder, false)
+ // LCR does not need cleanroom.
+ .metadata(CLEANROOM, false)
+ .addTo(RecipeMaps.multiblockChemicalReactorRecipes));
+ });
+
+ /**
+ * Adds an engraver recipe that might use purified water. Still added to the regular recipemap if it ends up not
+ * needing it.
+ */
+ public static final IRecipeMap WaferEngravingRecipes = IRecipeMap.newRecipeMap(builder -> {
+ // spotless:off
+ enum Wafer{
+ Naquadah,
+ Europium,
+ Americium,
+ // Beamline masks
+ MaskT1,
+ MaskT2,
+ MaskT3,
+ }
+ // spotless:on
+ // Find the wafer used
+ Wafer wafer = null;
+ ItemPhotolithographicMask t1Item = (ItemPhotolithographicMask) LanthItemList.maskMap.get(MaskList.BLANK1);
+ ItemPhotolithographicMask t2Item = (ItemPhotolithographicMask) LanthItemList.maskMap.get(MaskList.BLANK2);
+ ItemPhotolithographicMask t3Item = (ItemPhotolithographicMask) LanthItemList.maskMap.get(MaskList.BLANK3);
+ for (ItemStack input : builder.getItemInputsBasic()) {
+ if (input.getItem() instanceof MetaGeneratedItem03) {
+ int meta = input.getItemDamage() - 32000;
+ // Check if this input item is indicating a wafer recipe we want to modify
+ if (meta == IDMetaItem03.Circuit_Silicon_Wafer3.ID) wafer = Wafer.Naquadah;
+ else if (meta == IDMetaItem03.Circuit_Silicon_Wafer4.ID) wafer = Wafer.Europium;
+ else if (meta == IDMetaItem03.Circuit_Silicon_Wafer5.ID) wafer = Wafer.Americium;
+ }
+
+ // Now look for beamline masks
+ if (input.getItem() instanceof ItemPhotolithographicMask mask) {
+ String spectrum = mask.getDescSpectrum();
+ if (spectrum.equals(t1Item.getDescSpectrum())) wafer = Wafer.MaskT1;
+ else if (spectrum.equals(t2Item.getDescSpectrum())) wafer = Wafer.MaskT2;
+ else if (spectrum.equals(t3Item.getDescSpectrum())) wafer = Wafer.MaskT3;
+ }
+
+ // Found a wafer, stop checking inputs
+ if (wafer != null) break;
+ }
+
+ int recipeTime = builder.duration;
+ // Bonus for using purified water of a higher tier than necessary
+ int halfBoostedRecipeTime = (int) (recipeTime * 0.75);
+ int boostedRecipeTime = (int) (recipeTime * 0.5);
+
+ // If this recipe does not use a wafer, exit without modifying it.
+ if (wafer == null) return builder.addTo(RecipeMaps.laserEngraverRecipes);
+ switch (wafer) {
+ case Naquadah -> {
+ ArrayList<ItemStack> items = new ArrayList<>(Arrays.asList(builder.getItemInputsBasic()));
+ ItemStack[] itemInputs = items.toArray(new ItemStack[] {});
+ // Naquadah wafers can use grade 1-2 purified water for a bonus, otherwise use distilled so we don't
+ // have to
+ // deal with circuits
+ return GTUtility.concat(
+ builder.copy()
+ .itemInputs(itemInputs)
+ .fluidInputs(GTModHandler.getDistilledWater(100L))
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .itemInputs(itemInputs)
+ .fluidInputs(Materials.Grade1PurifiedWater.getFluid(100L))
+ .duration(halfBoostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .itemInputs(itemInputs)
+ .fluidInputs(Materials.Grade2PurifiedWater.getFluid(100L))
+ .duration(boostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes));
+ }
+ case Europium -> {
+ // Require purified water for europium wafers, at least grade 3
+ return GTUtility.concat(
+ builder.copy()
+ .fluidInputs(Materials.Grade3PurifiedWater.getFluid(100L))
+ .duration(recipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .fluidInputs(Materials.Grade4PurifiedWater.getFluid(100L))
+ .duration(boostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes));
+ }
+ case Americium -> {
+ // Require purified water for americium wafers, at least grade 5
+ return GTUtility.concat(
+ builder.copy()
+ .fluidInputs(Materials.Grade5PurifiedWater.getFluid(100L))
+ .duration(recipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .fluidInputs(Materials.Grade6PurifiedWater.getFluid(100L))
+ .duration(boostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes));
+ }
+ // Masks require much more purified water because they can make many wafers at once
+ case MaskT1 -> {
+ // T1 masks require grade 1, 2 or 3 purified water
+ return GTUtility.concat(
+ builder.copy()
+ .fluidInputs(Materials.Grade1PurifiedWater.getFluid(32000L))
+ .duration(recipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .fluidInputs(Materials.Grade2PurifiedWater.getFluid(32000L))
+ .duration(halfBoostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .fluidInputs(Materials.Grade3PurifiedWater.getFluid(32000L))
+ .duration(boostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes));
+ }
+ case MaskT2 -> {
+ // T2 masks require grade 4 or 5 purified water
+ return GTUtility.concat(
+ builder.copy()
+ .fluidInputs(Materials.Grade4PurifiedWater.getFluid(32000L))
+ .duration(recipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .fluidInputs(Materials.Grade5PurifiedWater.getFluid(32000L))
+ .duration(boostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes));
+ }
+ case MaskT3 -> {
+ // T3 masks require grade 6, 7 or 8 purified water
+ return GTUtility.concat(
+ builder.copy()
+ .fluidInputs(Materials.Grade6PurifiedWater.getFluid(32000L))
+ .duration(recipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .fluidInputs(Materials.Grade7PurifiedWater.getFluid(32000L))
+ .duration(halfBoostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes),
+ builder.copy()
+ .fluidInputs(Materials.Grade8PurifiedWater.getFluid(32000L))
+ .duration(boostedRecipeTime)
+ .addTo(RecipeMaps.laserEngraverRecipes));
+ }
+ }
+
+ throw new RuntimeException("Unreachable code reached in Laser Engraver Recipe Transformer");
+ });
+
+ /**
+ * The one and only :tm: assline recipe adder.
+ * Uses {@link #RESEARCH_ITEM} metadata as research item, and {@link #RESEARCH_TIME} metadata as research time, unit
+ * in ticks.
+ */
+ public static final IRecipeMap AssemblyLine = IRecipeMap.newRecipeMap(builder -> {
+ Optional<GTRecipe.GTRecipe_WithAlt> rr = builder.forceOreDictInput()
+ .validateInputCount(4, 16)
+ .validateOutputCount(1, 1)
+ .validateOutputFluidCount(-1, 0)
+ .validateInputFluidCount(1, 4)
+ .buildWithAlt();
+ // noinspection SimplifyOptionalCallChains
+ if (!rr.isPresent()) return Collections.emptyList();
+ GTRecipe.GTRecipe_WithAlt r = rr.get();
+ ItemStack[][] mOreDictAlt = r.mOreDictAlt;
+ Object[] inputs = builder.getItemInputsOreDict();
+ ItemStack aResearchItem = builder.getMetadata(RESEARCH_ITEM);
+ if (aResearchItem == null) {
+ return Collections.emptyList();
+ }
+ ItemStack aOutput = r.mOutputs[0];
+ int tPersistentHash = 1;
+ for (int i = 0, mOreDictAltLength = mOreDictAlt.length; i < mOreDictAltLength; i++) {
+ ItemStack[] alts = mOreDictAlt[i];
+ Object input = inputs[i];
+ if (input == null) {
+ GTLog.err.println(
+ "addAssemblingLineRecipe " + aResearchItem.getDisplayName()
+ + " --> "
+ + aOutput.getUnlocalizedName()
+ + " there is some null item in that recipe");
+ }
+ if (input instanceof ItemStack) {
+ tPersistentHash = tPersistentHash * 31 + GTUtility.persistentHash((ItemStack) input, true, false);
+ } else if (input instanceof ItemStack[]) {
+ for (ItemStack alt : ((ItemStack[]) input)) {
+ tPersistentHash = tPersistentHash * 31 + GTUtility.persistentHash(alt, true, false);
+ if (alt == null) {
+ GTLog.err.println(
+ "addAssemblingLineRecipe " + aResearchItem.getDisplayName()
+ + " --> "
+ + aOutput.getUnlocalizedName()
+ + " there is some null alt item in that recipe");
+ }
+ }
+ tPersistentHash *= 31;
+ } else if (input instanceof Object[]objs) {
+ Arrays.sort(
+ alts,
+ Comparator
+ .<ItemStack, String>comparing(s -> GameRegistry.findUniqueIdentifierFor(s.getItem()).modId)
+ .thenComparing(s -> GameRegistry.findUniqueIdentifierFor(s.getItem()).name)
+ .thenComparingInt(Items.feather::getDamage)
+ .thenComparingInt(s -> s.stackSize));
+
+ tPersistentHash = tPersistentHash * 31 + (objs[0] == null ? "" : objs[0].toString()).hashCode();
+ tPersistentHash = tPersistentHash * 31 + ((Number) objs[1]).intValue();
+ }
+ }
+ tPersistentHash = tPersistentHash * 31 + GTUtility.persistentHash(aResearchItem, true, false);
+ tPersistentHash = tPersistentHash * 31 + GTUtility.persistentHash(aOutput, true, false);
+ for (FluidStack fluidInput : r.mFluidInputs) {
+ if (fluidInput == null) continue;
+ tPersistentHash = tPersistentHash * 31 + GTUtility.persistentHash(fluidInput, true, false);
+ }
+ int aResearchTime = builder.getMetadataOrDefault(RESEARCH_TIME, 0);
+ tPersistentHash = tPersistentHash * 31 + aResearchTime;
+ tPersistentHash = tPersistentHash * 31 + r.mDuration;
+ tPersistentHash = tPersistentHash * 31 + r.mEUt;
+
+ GTRecipe.RecipeAssemblyLine tRecipe = new GTRecipe.RecipeAssemblyLine(
+ aResearchItem,
+ aResearchTime,
+ r.mInputs,
+ r.mFluidInputs,
+ aOutput,
+ r.mDuration,
+ r.mEUt,
+ r.mOreDictAlt);
+ tRecipe.setPersistentHash(tPersistentHash);
+ GTRecipe.RecipeAssemblyLine.sAssemblylineRecipes.add(tRecipe);
+ AssemblyLineUtils.addRecipeToCache(tRecipe);
+
+ ItemStack writesDataStick = ItemList.Tool_DataStick.getWithName(1L, "Writes Research result");
+ AssemblyLineUtils.setAssemblyLineRecipeOnDataStick(writesDataStick, tRecipe, false);
+ Collection<GTRecipe> ret = new ArrayList<>(3);
+ ret.addAll(
+ GTValues.RA.stdBuilder()
+ .itemInputs(aResearchItem)
+ .itemOutputs(aOutput)
+ .special(writesDataStick)
+ .duration(aResearchTime)
+ .eut(TierEU.RECIPE_LV)
+ .specialValue(-201) // means it's scanned
+ .noOptimize()
+ .ignoreCollision()
+ .fake()
+ .addTo(scannerFakeRecipes));
+
+ ItemStack readsDataStick = ItemList.Tool_DataStick.getWithName(1L, "Reads Research result");
+ AssemblyLineUtils.setAssemblyLineRecipeOnDataStick(readsDataStick, tRecipe, false);
+ ret.add(
+ RecipeMaps.assemblylineVisualRecipes.addFakeRecipe(
+ false,
+ r.mInputs,
+ new ItemStack[] { aOutput },
+ new ItemStack[] { readsDataStick },
+ r.mFluidInputs,
+ null,
+ r.mDuration,
+ r.mEUt,
+ 0,
+ r.mOreDictAlt,
+ false));
+
+ return ret;
+ });
+
+ /**
+ * Adds an Electric Blast Furnace recipe that might use gas.
+ */
+ public static final IRecipeMap BlastFurnaceWithGas = IRecipeMap.newRecipeMap(builder -> {
+ Collection<GTRecipe> ret = new ArrayList<>();
+ int basicGasAmount = builder.getMetadataOrDefault(ADDITIVE_AMOUNT, 1000);
+ double durationBase = builder.getDuration();
+ ArrayList<ItemStack> items = new ArrayList<>(Arrays.asList(builder.getItemInputsBasic()));
+ int circuitConfig = 1;
+ if (items.size() == 1) {// Set circuit config if it is a dust -> ingot recipe.
+ ItemData data = GTOreDictUnificator.getAssociation(items.get(0));
+ if (data != null) {
+ OrePrefixes prefix = data.mPrefix;
+ if (OrePrefixes.dust.equals(prefix)) {
+ circuitConfig = 1;
+ } else if (OrePrefixes.dustSmall.equals(prefix)) {
+ circuitConfig = 4;
+ } else if (OrePrefixes.dustTiny.equals(prefix)) {
+ circuitConfig = 9;
+ }
+ }
+ } else { // Set circuit config if there is an integrated circuit
+ for (int i = 0; i < items.size(); i++) {
+ if (GTUtility.isAnyIntegratedCircuit(items.get(i))) {
+ circuitConfig = items.get(i)
+ .getItemDamage();
+ items.remove(i--);
+ }
+ }
+ }
+
+ if (builder.getMetadataOrDefault(NO_GAS, false)) {
+ items.add(GTUtility.getIntegratedCircuit(circuitConfig));
+ ret.addAll(
+ builder.copy()
+ .itemInputs(items.toArray(new ItemStack[0]))
+ .fluidInputs()
+ .duration((int) Math.max(durationBase * 1.1, 1))
+ .addTo(RecipeMaps.blastFurnaceRecipes));
+ items.remove(items.size() - 1);
+ circuitConfig += 10;
+ }
+
+ items.add(GTUtility.getIntegratedCircuit(circuitConfig));
+ boolean nobleGases = builder.getMetadataOrDefault(NOBLE_GASES, false);
+ boolean anaerobeGases = builder.getMetadataOrDefault(ANAEROBE_GASES, false);
+ Collection<BlastFurnaceGasStat> gases = new ArrayList<>();
+
+ if (nobleGases && anaerobeGases) {
+ gases = BlastFurnaceGasStat.getNobleAndAnaerobeGases();
+ } else if (nobleGases) {
+ gases = BlastFurnaceGasStat.getNobleGases();
+ } else if (anaerobeGases) {
+ gases = BlastFurnaceGasStat.getAnaerobeGases();
+ }
+ for (BlastFurnaceGasStat gas : gases) {
+ int gasAmount = (int) (gas.recipeConsumedAmountMultiplier * basicGasAmount);
+ int duration = (int) Math.max(gas.recipeTimeMultiplier * durationBase, 1);
+ ret.addAll(
+ builder.copy()
+ .itemInputs(items.toArray(new ItemStack[0]))
+ .fluidInputs(GTUtility.copyAmount(gasAmount, gas.gas))
+ .duration(duration)
+ .addTo(RecipeMaps.blastFurnaceRecipes));
+ }
+ return ret;
+ });
+
+ /**
+ * Just like any normal assembler recipe, however it accepts one input item to be oredicted. Pass in the item to
+ * oredict via {@link #OREDICT_INPUT}. It will be used along all other item inputs as input of this recipe.
+ */
+ public static IRecipeMap AssemblerOD = IRecipeMap.newRecipeMap(builder -> {
+ Collection<GTRecipe> ret = new ArrayList<>();
+ for (ItemStack input : GTOreDictUnificator.getOresImmutable(builder.getMetadata(OREDICT_INPUT))) {
+ ret.addAll(
+ builder.copy()
+ .itemInputs(GTRecipeMapUtil.appendArray(builder.getItemInputsBasic(), input))
+ .addTo(RecipeMaps.assemblerRecipes));
+ }
+ return ret;
+ });
+
+ /**
+ * A universal fuel adder. It's actually just a dispatcher towards all actual fuel recipe maps.
+ * Dispatch based on {@link #FUEL_TYPE}. Uses {@link #FUEL_VALUE} as fuel value.
+ * Can use {@link FuelType#ordinal()} as a human-readable form of what FUEL_TYPE should be.
+ * You can bypass this and add to relevant fuel maps directly if you wish.
+ */
+ public static IRecipeMap Fuel = IRecipeMap.newRecipeMap(builder -> {
+ builder.validateInputCount(1, 1)
+ .validateNoInputFluid()
+ .validateOutputCount(-1, 1)
+ .validateNoOutputFluid();
+ if (!builder.isValid()) return Collections.emptyList();
+ Integer fuelType = builder.getMetadata(FUEL_TYPE);
+ if (fuelType == null) return Collections.emptyList();
+ builder.metadata(FUEL_VALUE, builder.getMetadataOrDefault(FUEL_VALUE, 0));
+ return FuelType.get(fuelType)
+ .getTarget()
+ .doAdd(builder);
+ });
+
+ public enum FuelType {
+
+ // ORDER MATTERS. DO NOT INSERT ELEMENT BETWEEN EXISTING ONES
+ DieselFuel(RecipeMaps.dieselFuels),
+ GasTurbine(RecipeMaps.gasTurbineFuels),
+ // appears unused
+ HotFuel(RecipeMaps.hotFuels),
+ SemiFluid(RecipeMaps.denseLiquidFuels),
+ PlasmaTurbine(RecipeMaps.plasmaFuels),
+ Magic(RecipeMaps.magicFuels),;
+
+ private static final FuelType[] VALUES = values();
+ private final IRecipeMap target;
+
+ FuelType(IRecipeMap target) {
+ this.target = target;
+ }
+
+ public static FuelType get(int fuelType) {
+ if (fuelType < 0 || fuelType >= VALUES.length) return SemiFluid;
+ return VALUES[fuelType];
+ }
+
+ public IRecipeMap getTarget() {
+ return target;
+ }
+ }
+
+ static {
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(COIL_HEAT);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(FUSION_THRESHOLD);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(FUEL_VALUE);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(NANO_FORGE_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(FOG_EXOTIC_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(FOG_PLASMA_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(DEFC_CASING_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(CHEMPLANT_CASING_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(QFT_FOCUS_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(DISSOLUTION_TANK_RATIO);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(RTG_DURATION_IN_DAYS);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(LNG_BASIC_OUTPUT);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(NFR_COIL_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(NKE_RANGE);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(PRECISE_ASSEMBLER_CASING_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(COAL_CASING_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(COMPRESSION_TIER);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(RESEARCH_STATION_DATA);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(SIEVERTS);
+ GTRecipeMapUtil.SPECIAL_VALUE_ALIASES.add(DECAY_TICKS);
+
+ }
+}