diff options
Diffstat (limited to 'src/main/java/gregtech/api')
95 files changed, 7531 insertions, 6955 deletions
diff --git a/src/main/java/gregtech/api/GregTech_API.java b/src/main/java/gregtech/api/GregTech_API.java index 6848c66a38..c5e27aebca 100644 --- a/src/main/java/gregtech/api/GregTech_API.java +++ b/src/main/java/gregtech/api/GregTech_API.java @@ -36,6 +36,7 @@ import net.minecraft.world.World; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.relauncher.Side; @@ -107,6 +108,7 @@ public class GregTech_API { * Fixes the HashMap Mappings for ItemStacks once the Server started */ public static final Collection<Map<? extends GT_ItemStack, ?>> sItemStackMappings = new ArrayList<>(); + public static final Collection<SetMultimap<? extends GT_ItemStack, ?>> itemStackMultiMaps = new ArrayList<>(); /** * The MetaTileEntity-ID-List-Length @@ -121,17 +123,36 @@ public class GregTech_API { /** * A List of all registered MetaTileEntities * <p/> - * 0 - 749 are used by GregTech. 750 - 999 are reserved for Alkalus. 1000 - 2047 are used by GregTech. 2048 - 2559 - * are reserved for OvermindDL. 2560 - 3071 are reserved for Immibis. 3072 - 3583 are reserved for LinusPhoenix. - * 3584 - 4095 are reserved for BloodyAsp. 4096 - 5095 are used for GregTech Frames. 5096 - 6099 are used for - * GregTech Pipes. 6100 - 8191 are used for GregTech Decoration Blocks. 8192 - 8703 are reserved for ZL123. 8704 - - * 9215 are reserved for Mr10Movie. 9216 - 9727 are used for GregTech Automation Machines. 9728 - 10239 are reserved - * for 28Smiles. 10240 - 10751 are reserved for VirMan. 10752 - 11263 are reserved for Briareos81. 11264 - 12000 are - * reserved for Quantum64. 12001 - 12500 are reserved for RedMage17. 12501 - 13000 are reserved for bartimaeusnek. - * 13001 - 13100 are reserved for Techlone 13101 - 13500 are reserved for kekzdealer 13501 - 14000 are reserved for - * glee8e. 14001 - 14100 are reserved for glowredman 14101 - 14200 are reserved for MuXiu1997. 14201 - 14300 are - * reserved for kuba6000. 14301 - 14999 are currently free. 15000 - 16999 are reserved for TecTech. 17000 - 29999 - * are currently free. 30000 - 31999 are reserved for Alkalus. 32001 - 32766 are reserved for Glod. + * 0 - 749 are used by GregTech. + * 750 - 999 are reserved for Alkalus. + * 1000 - 2047 are used by GregTech. + * 2048 - 2559 are reserved for OvermindDL. + * 2560 - 3071 are reserved for Immibis. + * 3072 - 3583 are reserved for LinusPhoenix. + * 3584 - 4095 are reserved for BloodyAsp. + * 4096 - 5095 are used for GregTech Frames. + * 5096 - 6099 are used for GregTech Pipes. + * 6100 - 8191 are used for GregTech Decoration Blocks. + * 8192 - 8703 are reserved for ZL123. + * 8704 - 9215 are reserved for Mr10Movie. + * 9216 - 9727 are used for GregTech Automation Machines. + * 9728 - 10239 are reserved for 28Smiles. + * 10240 - 10751 are reserved for VirMan. + * 10752 - 11263 are reserved for Briareos81. + * 11264 - 12000 are reserved for Quantum64. + * 12001 - 12500 are reserved for RedMage17. + * 12501 - 13000 are reserved for bartimaeusnek. + * 13001 - 13100 are reserved for Techlone. + * 13101 - 13500 are reserved for kekzdealer. + * 13501 - 14000 are reserved for glee8e. + * 14001 - 14100 are reserved for glowredman. + * 14101 - 14200 are reserved for MuXiu1997. + * 14201 - 14300 are reserved for kuba6000. + * 14301 - 14999 are currently free. + * 15000 - 16999 are reserved for TecTech. + * 17000 - 29999 are currently free. + * 30000 - 31999 are reserved for Alkalus. + * 32001 - 32766 are reserved for Glod. * <p/> * Contact me if you need a free ID-Range, which doesn't conflict with other Addons. You could make an ID-Config, * but we all know what "stupid" customers think about conflicting ID's diff --git a/src/main/java/gregtech/api/enums/Element.java b/src/main/java/gregtech/api/enums/Element.java index a0f8e6c0b1..0931663b0b 100644 --- a/src/main/java/gregtech/api/enums/Element.java +++ b/src/main/java/gregtech/api/enums/Element.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nonnull; + /** * This is some kind of Periodic Table, which I use to determine Properties of the Materials. */ @@ -308,6 +310,7 @@ public enum Element { Companion.VALUES.put(name(), this); } + @Nonnull public static Element get(String aMaterialName) { return Companion.VALUES.getOrDefault(aMaterialName, _NULL); } diff --git a/src/main/java/gregtech/api/enums/ItemList.java b/src/main/java/gregtech/api/enums/ItemList.java index ed2cad0ce1..5ecf39a722 100644 --- a/src/main/java/gregtech/api/enums/ItemList.java +++ b/src/main/java/gregtech/api/enums/ItemList.java @@ -807,7 +807,6 @@ public enum ItemList implements IItemContainer { Machine_Bronze_Hammer, Machine_Bronze_Compressor, Machine_Bronze_AlloySmelter, - Machine_Bronze_BlastFurnace, Machine_Bricked_BlastFurnace, Machine_Steel_Boiler_Lava, Machine_Steel_Boiler, diff --git a/src/main/java/gregtech/api/enums/MachineType.java b/src/main/java/gregtech/api/enums/MachineType.java index 7868d80f8f..14e1781350 100644 --- a/src/main/java/gregtech/api/enums/MachineType.java +++ b/src/main/java/gregtech/api/enums/MachineType.java @@ -10,7 +10,7 @@ public enum MachineType { ASSEMBLER(FunnyTexts.ASSEMBLER, "gt.recipe.assembler"), AUTOCLAVE(FunnyTexts.AUTOCLAVE, "gt.recipe.autoclave"), BENDING_MACHINE(FunnyTexts.BENDING_MACHINE, "gt.recipe.metalbender"), - BREWERY(FunnyTexts.BREWERY, "gt.recipe.brewery"), + BREWERY(FunnyTexts.BREWERY, "gt.recipe.brewer"), CANNER(FunnyTexts.CANNER, "gt.recipe.canner"), CENTRIFUGE(FunnyTexts.CENTRIFUGE, "gt.recipe.centrifuge"), CHEMICAL_BATH(FunnyTexts.CHEMICAL_BATH, "gt.recipe.chemicalbath"), @@ -62,7 +62,7 @@ public enum MachineType { static final String ASSEMBLER = "gt.recipe.assembler.description"; static final String AUTOCLAVE = "gt.recipe.autoclave.description"; static final String BENDING_MACHINE = "gt.recipe.metalbender.description"; - static final String BREWERY = "gt.recipe.brewery.description"; + static final String BREWERY = "gt.recipe.brewer.description"; static final String CANNER = "gt.recipe.canner.description"; static final String CENTRIFUGE = "gt.recipe.centrifuge.description"; static final String CHEMICAL_BATH = "gt.recipe.chemicalbath.description"; diff --git a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java index ace5f620d4..3994a02085 100644 --- a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java +++ b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java @@ -108,7 +108,6 @@ public enum MetaTileEntityIDs { SIMPLE_SOLAR_BOILER(105), STEAM_MACERATOR(106), HP_STEAM_MACERATOR(107), - BRONZE_BLAST_FURNACE_CONTROLLER(108), STEAM_EXTRACTOR(109), HP_STEAM_EXTRACTOR(110), AUTO_MAINTENANCE_HATCH(111), diff --git a/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java index 1a47e41e8c..1dd7c9f6d2 100644 --- a/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java +++ b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import com.gtnewhorizons.modularui.api.drawable.AdaptableUITexture; +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; import com.gtnewhorizons.modularui.api.drawable.UITexture; public class GT_UITextures { @@ -23,6 +24,8 @@ public class GT_UITextures { .of(GregTech.ID, "gui/background/text_field", 142, 28, 1); public static final AdaptableUITexture BACKGROUND_TEXT_FIELD_LIGHT_GRAY = AdaptableUITexture .of(GregTech.ID, "gui/background/text_field_light_gray", 61, 12, 1); + public static final AdaptableUITexture BACKGROUND_NEI_SINGLE_RECIPE = AdaptableUITexture + .of(GregTech.ID, "gui/background/nei_single_recipe.png", 64, 64, 2); public static final SteamTexture SLOT_ITEM_STEAM = SteamTexture.fullImage(GregTech.ID, "gui/slot/item_%s"); public static final SteamTexture SLOT_FLUID_STEAM = SteamTexture.fullImage(GregTech.ID, "gui/slot/fluid_%s"); @@ -200,6 +203,10 @@ public class GT_UITextures { public static final UITexture PROGRESSBAR_STORED_EU = UITexture.fullImage(GregTech.ID, "gui/progressbar/stored_eu"); public static final UITexture PROGRESSBAR_WIREMILL = UITexture.fullImage(GregTech.ID, "gui/progressbar/wiremill"); + public static FallbackableUITexture fallbackableProgressbar(String name, UITexture fallback) { + return new FallbackableUITexture(UITexture.fullImage(GregTech.ID, "gui/progressbar/" + name), fallback); + } + public static final UITexture TAB_COVER_NORMAL = UITexture.fullImage(GregTech.ID, "gui/tab/cover_normal"); public static final UITexture TAB_COVER_HIGHLIGHT = UITexture.fullImage(GregTech.ID, "gui/tab/cover_highlight"); public static final UITexture TAB_COVER_DISABLED = UITexture.fullImage(GregTech.ID, "gui/tab/cover_disabled"); diff --git a/src/main/java/gregtech/api/interfaces/IGT_RecipeMap.java b/src/main/java/gregtech/api/interfaces/IRecipeMap.java index 2c5259882a..ce48b29927 100644 --- a/src/main/java/gregtech/api/interfaces/IGT_RecipeMap.java +++ b/src/main/java/gregtech/api/interfaces/IRecipeMap.java @@ -14,7 +14,7 @@ import gregtech.api.util.GT_Utility; /** * Represents the target of a recipe adding action, usually, but not necessarily, is a recipe map itself. */ -public interface IGT_RecipeMap { +public interface IRecipeMap { /** * Add a downstream recipe map that will get to handle the original builder. @@ -27,7 +27,7 @@ public interface IGT_RecipeMap { * * @param downstream the downstream recipe map to add */ - void addDownstream(IGT_RecipeMap downstream); + void addDownstream(IRecipeMap downstream); /** * Actually add the recipe represented by the builder. CAN modify the builder's internal states!!! @@ -41,17 +41,17 @@ public interface IGT_RecipeMap { * <p> * The returned recipe map will not have any downstreams, but can accept new downstreams. */ - default IGT_RecipeMap deepCopyInput() { + default IRecipeMap deepCopyInput() { return newRecipeMap(b -> doAdd(b.copy())); } - static IGT_RecipeMap newRecipeMap(Function<? super GT_RecipeBuilder, Collection<GT_Recipe>> func) { - return new IGT_RecipeMap() { + static IRecipeMap newRecipeMap(Function<? super GT_RecipeBuilder, Collection<GT_Recipe>> func) { + return new IRecipeMap() { - private final Collection<IGT_RecipeMap> downstreams = new ArrayList<>(); + private final Collection<IRecipeMap> downstreams = new ArrayList<>(); @Override - public void addDownstream(IGT_RecipeMap downstream) { + public void addDownstream(IRecipeMap downstream) { downstreams.add(downstream); } @@ -63,7 +63,7 @@ public interface IGT_RecipeMap { ret.add(out); builder.clearInvalid(); if (!out.isEmpty()) { - for (IGT_RecipeMap downstream : downstreams) { + for (IRecipeMap downstream : downstreams) { ret.add(downstream.doAdd(builder)); } } diff --git a/src/main/java/gregtech/api/interfaces/internal/IGT_RecipeAdder.java b/src/main/java/gregtech/api/interfaces/internal/IGT_RecipeAdder.java index 361e391a9b..e7abfea98f 100644 --- a/src/main/java/gregtech/api/interfaces/internal/IGT_RecipeAdder.java +++ b/src/main/java/gregtech/api/interfaces/internal/IGT_RecipeAdder.java @@ -321,17 +321,6 @@ public interface IGT_RecipeAdder { boolean hidden); /** - * Adds a CNC-Machine Recipe - * - * @param aInput1 must be != null - * @param aOutput1 must be != null - * @param aDuration must be > 0 - * @param aEUt should be > 0 - */ - @Deprecated - boolean addCNCRecipe(ItemStack aInput1, ItemStack aOutput1, int aDuration, int aEUt); - - /** * Adds an Assembler Recipe * * @param aInput1 must be != null @@ -1047,21 +1036,6 @@ public interface IGT_RecipeAdder { FluidStack[] aFluidOutputs, int[] aChances, int aDuration, int aEUt, int aSpecialValue); /** - * Add a Board Manufacturer Recipe. The Board Manufacturer's main use is to make the circuit boards needed to make - * circuits. - * - * @param aInputs must not be null - * @param aFluidInputs must not be null - * @param aOutputs must not be null - * @param aDuration recipe duration - * @param aEUt recipe EU/t expenditure - * @param aSpecialValue defines the tier of the board manufacturer required. - */ - @Deprecated - boolean addPCBFactoryRecipe(ItemStack[] aInputs, FluidStack[] aFluidInputs, ItemStack[] aOutputs, int aDuration, - int aEUt, int aSpecialValue); - - /** * Add a breeder cell. * * @param input raw stack. should be undamaged. diff --git a/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java b/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java index ba164352aa..04522b1012 100644 --- a/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java +++ b/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java @@ -38,7 +38,6 @@ import gregtech.api.interfaces.tileentity.IMachineBlockUpdateable; import gregtech.api.objects.GT_ItemStack; import gregtech.api.util.GT_Config; import gregtech.api.util.GT_Util; -import gregtech.common.power.Power; /** * Warning, this Interface has just been made to be able to add multiple kinds of MetaTileEntities (Cables, Pipes, @@ -366,13 +365,6 @@ public interface IMetaTileEntity extends ISidedInventory, IFluidTank, IFluidHand String getSpecialVoltageToolTip(); /** - * @return Power object used for displaying in NEI - */ - default Power getPower() { - return null; - } - - /** * Icon of the Texture. If this returns null then it falls back to getTextureIndex. * * @param side is the Side of the Block diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IOverclockDescriptionProvider.java b/src/main/java/gregtech/api/interfaces/tileentity/IOverclockDescriptionProvider.java new file mode 100644 index 0000000000..495cd9def4 --- /dev/null +++ b/src/main/java/gregtech/api/interfaces/tileentity/IOverclockDescriptionProvider.java @@ -0,0 +1,15 @@ +package gregtech.api.interfaces.tileentity; + +import javax.annotation.Nullable; + +import gregtech.api.objects.overclockdescriber.OverclockDescriber; + +/** + * Classes implementing this interface can provide {@link OverclockDescriber} to provide overclock behavior and NEI + * description. + */ +public interface IOverclockDescriptionProvider { + + @Nullable + OverclockDescriber getOverclockDescriber(); +} diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IRecipeLockable.java b/src/main/java/gregtech/api/interfaces/tileentity/IRecipeLockable.java index f793221a50..54d178af3c 100644 --- a/src/main/java/gregtech/api/interfaces/tileentity/IRecipeLockable.java +++ b/src/main/java/gregtech/api/interfaces/tileentity/IRecipeLockable.java @@ -1,12 +1,11 @@ package gregtech.api.interfaces.tileentity; import gregtech.api.recipe.check.SingleRecipeCheck; -import gregtech.api.util.GT_Recipe; /** * Machines implementing this interface can have logic to lock to a single recipe. */ -public interface IRecipeLockable { +public interface IRecipeLockable extends RecipeMapWorkable { /** * @return if this machine supports single recipe locking. @@ -29,6 +28,4 @@ public interface IRecipeLockable { } default void setSingleRecipeCheck(SingleRecipeCheck recipeCheck) {} - - GT_Recipe.GT_Recipe_Map getRecipeMap(); } diff --git a/src/main/java/gregtech/api/interfaces/tileentity/RecipeMapWorkable.java b/src/main/java/gregtech/api/interfaces/tileentity/RecipeMapWorkable.java new file mode 100644 index 0000000000..7d4db4396c --- /dev/null +++ b/src/main/java/gregtech/api/interfaces/tileentity/RecipeMapWorkable.java @@ -0,0 +1,49 @@ +package gregtech.api.interfaces.tileentity; + +import java.util.Collection; +import java.util.Collections; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; + +import gregtech.api.recipe.RecipeMap; + +/** + * Machines implementing this interface are capable of executing certain recipes provided by {@link RecipeMap}. + * They will also be automatically registered as NEI recipe catalyst for the corresponding recipemaps. + */ +public interface RecipeMapWorkable { + + /** + * @return RecipeMap this machine currently can execute. In general, it's allowed to be null. + */ + RecipeMap<?> getRecipeMap(); + + /** + * @return ItemStack form of this machine. + */ + ItemStack getStackForm(long amount); + + /** + * If the machine supports multiple recipemaps by switching mode, override this method so that it will be displayed + * as NEI recipe catalyst on all the supported recipemaps. + * + * @return List of possible {@link RecipeMap}s this machine can execute. Must not contain null element. + */ + @Nonnull + default Collection<RecipeMap<?>> getAvailableRecipeMaps() { + RecipeMap<?> recipeMap = getRecipeMap(); + if (recipeMap != null) { + return Collections.singletonList(recipeMap); + } + return Collections.emptyList(); + } + + /** + * @return Priority for NEI recipe catalyst. Higher priority comes first. + */ + default int getRecipeCatalystPriority() { + return 0; + } +} diff --git a/src/main/java/gregtech/api/items/GT_MetaGenerated_Item.java b/src/main/java/gregtech/api/items/GT_MetaGenerated_Item.java index 828fab4368..465c4bc9d6 100644 --- a/src/main/java/gregtech/api/items/GT_MetaGenerated_Item.java +++ b/src/main/java/gregtech/api/items/GT_MetaGenerated_Item.java @@ -3,7 +3,7 @@ package gregtech.api.items; import static gregtech.api.enums.GT_Values.D1; import static gregtech.api.enums.Mods.AppleCore; import static gregtech.api.enums.Mods.GregTech; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sCannerRecipes; +import static gregtech.api.recipe.RecipeMaps.cannerRecipes; import static gregtech.api.util.GT_RecipeBuilder.SECONDS; import java.util.ArrayList; @@ -153,7 +153,7 @@ public abstract class GT_MetaGenerated_Item extends GT_MetaBase_Item implements : ItemList.IC2_Food_Can_Filled.get(tFoodValue)) .duration(tFoodValue * 5 * SECONDS) .eut(1) - .addTo(sCannerRecipes); + .addTo(cannerRecipes); } } tUseOreDict = false; diff --git a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java index 05d39cd02c..3c7974db9e 100644 --- a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java @@ -6,6 +6,7 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; import gregtech.api.multitileentity.multiblock.base.Controller; +import gregtech.api.recipe.RecipeMap; import gregtech.api.util.GT_OverclockCalculator; import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_Recipe; @@ -13,7 +14,7 @@ import gregtech.api.util.GT_Recipe; public class ComplexParallelProcessingLogic { protected Controller<?> tileEntity; - protected GT_Recipe.GT_Recipe_Map recipeMap; + protected RecipeMap<?> recipeMap; protected boolean hasPerfectOverclock; protected final int maxComplexParallels; protected final ItemStack[][] outputItems; @@ -30,7 +31,7 @@ public class ComplexParallelProcessingLogic { this(null, maxComplexParallels); } - public ComplexParallelProcessingLogic(GT_Recipe.GT_Recipe_Map recipeMap, int maxComplexParallels) { + public ComplexParallelProcessingLogic(RecipeMap<?> recipeMap, int maxComplexParallels) { this.maxComplexParallels = maxComplexParallels; this.recipeMap = recipeMap; inputItems = new ItemStack[maxComplexParallels][]; @@ -44,7 +45,7 @@ public class ComplexParallelProcessingLogic { isFluidVoidProtected = new boolean[maxComplexParallels]; } - public ComplexParallelProcessingLogic setRecipeMap(GT_Recipe.GT_Recipe_Map recipeMap) { + public ComplexParallelProcessingLogic setRecipeMap(RecipeMap<?> recipeMap) { this.recipeMap = recipeMap; return this; } diff --git a/src/main/java/gregtech/api/logic/ProcessingLogic.java b/src/main/java/gregtech/api/logic/ProcessingLogic.java index 803abafbe3..6b9f2d454f 100644 --- a/src/main/java/gregtech/api/logic/ProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ProcessingLogic.java @@ -2,6 +2,7 @@ package gregtech.api.logic; import java.util.List; import java.util.function.Supplier; +import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -13,15 +14,13 @@ import org.jetbrains.annotations.NotNull; import gregtech.api.interfaces.tileentity.IRecipeLockable; import gregtech.api.interfaces.tileentity.IVoidable; +import gregtech.api.recipe.RecipeMap; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; -import gregtech.api.recipe.check.FindRecipeResult; -import gregtech.api.recipe.check.RecipeValidator; import gregtech.api.recipe.check.SingleRecipeCheck; import gregtech.api.util.GT_OverclockCalculator; import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; /** * Logic class to calculate result of recipe check from inputs, based on recipemap. @@ -31,9 +30,9 @@ public class ProcessingLogic { protected IVoidable machine; protected IRecipeLockable recipeLockableMachine; - protected Supplier<GT_Recipe_Map> recipeMapSupplier; + protected Supplier<RecipeMap<?>> recipeMapSupplier; protected GT_Recipe lastRecipe; - protected GT_Recipe_Map lastRecipeMap; + protected RecipeMap<?> lastRecipeMap; protected ItemStack specialSlotItem; protected ItemStack[] inputItems; protected ItemStack[] outputItems; @@ -146,11 +145,11 @@ public class ProcessingLogic { return this; } - public ProcessingLogic setRecipeMap(GT_Recipe_Map recipeMap) { + public ProcessingLogic setRecipeMap(RecipeMap<?> recipeMap) { return setRecipeMapSupplier(() -> recipeMap); } - public ProcessingLogic setRecipeMapSupplier(Supplier<GT_Recipe_Map> supplier) { + public ProcessingLogic setRecipeMapSupplier(Supplier<RecipeMap<?>> supplier) { this.recipeMapSupplier = supplier; return this; } @@ -263,7 +262,7 @@ public class ProcessingLogic { */ @Nonnull public CheckRecipeResult process() { - GT_Recipe_Map recipeMap; + RecipeMap<?> recipeMap; if (recipeMapSupplier == null) { recipeMap = null; } else { @@ -278,6 +277,13 @@ public class ProcessingLogic { maxParallel = maxParallelSupplier.get(); } + if (inputItems == null) { + inputItems = new ItemStack[0]; + } + if (inputFluids == null) { + inputFluids = new FluidStack[0]; + } + if (isRecipeLocked && recipeLockableMachine != null && recipeLockableMachine.getSingleRecipeCheck() != null) { // Recipe checker is already built, we'll use it SingleRecipeCheck singleRecipeCheck = recipeLockableMachine.getSingleRecipeCheck(); @@ -287,55 +293,39 @@ public class ProcessingLogic { return CheckRecipeResultRegistry.NO_RECIPE; } - return processRecipe( + return validateAndCalculateRecipe( recipeLockableMachine.getSingleRecipeCheck() - .getRecipe()); + .getRecipe()).checkRecipeResult; } - FindRecipeResult findRecipeResult = findRecipe(recipeMap); - // If processRecipe is not overridden, advanced recipe validation logic is used, and we can reuse calculations. - if (findRecipeResult.hasRecipeValidator()) { - RecipeValidator recipeValidator = findRecipeResult.getRecipeValidator(); - - // There are two cases: - // 1 - there are actually no matching recipes - // 2 - there are some matching recipes, but we rejected it due to our advanced validation (e.g. OUTPUT_FULL) - if (findRecipeResult.getState() == FindRecipeResult.State.NOT_FOUND - && recipeValidator.getFirstCheckResult() != null) { - // Here we're handling case 2 - // If there are matching recipes but our validation rejected them, - // we should return a first one to display a proper error in the machine GUI - return recipeValidator.getFirstCheckResult(); + Stream<GT_Recipe> matchedRecipes = findRecipeMatches(recipeMap); + Iterable<GT_Recipe> recipeIterable = matchedRecipes::iterator; + CheckRecipeResult checkRecipeResult = CheckRecipeResultRegistry.NO_RECIPE; + for (GT_Recipe matchedRecipe : recipeIterable) { + CalculationResult foundResult = validateAndCalculateRecipe(matchedRecipe); + if (foundResult.successfullyConsumedInputs) { + // Successfully found and set recipe, so return it + return foundResult.checkRecipeResult; } - - // If everything is ok, reuse our calculations - if (recipeValidator.isExecutedAtLeastOnce() && findRecipeResult.isSuccessful()) { - return applyRecipe( - findRecipeResult.getRecipeNonNull(), - recipeValidator.getLastParallelHelper(), - recipeValidator.getLastOverclockCalculator(), - recipeValidator.getLastCheckResult()); + if (foundResult.checkRecipeResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that and continue searching + checkRecipeResult = foundResult.checkRecipeResult; } } - - if (!findRecipeResult.isSuccessful()) { - return CheckRecipeResultRegistry.NO_RECIPE; - } - - return processRecipe(findRecipeResult.getRecipeNonNull()); + return checkRecipeResult; } /** - * Checks if supplied recipe is valid for process. - * If so, additionally performs input consumption, output calculation with parallel, and overclock calculation. + * Checks if supplied recipe is valid for process. This involves voltage check, output full check. If successful, + * additionally performs input consumption, output calculation with parallel, and overclock calculation. * * @param recipe The recipe which will be checked and processed */ @Nonnull - protected CheckRecipeResult processRecipe(@Nonnull GT_Recipe recipe) { + private CalculationResult validateAndCalculateRecipe(@Nonnull GT_Recipe recipe) { CheckRecipeResult result = validateRecipe(recipe); if (!result.wasSuccessful()) { - return result; + return CalculationResult.ofFailure(result); } GT_ParallelHelper helper = createParallelHelper(recipe); @@ -343,19 +333,20 @@ public class ProcessingLogic { helper.setCalculator(calculator); helper.build(); - return applyRecipe(recipe, helper, calculator, result); + if (!helper.getResult() + .wasSuccessful()) { + return CalculationResult.ofFailure(helper.getResult()); + } + + return CalculationResult.ofSuccess(applyRecipe(recipe, helper, calculator, result)); } /** - * Applies the recipe and calculated parameters + * Check has been succeeded, so it applies the recipe and calculated parameters. + * At this point, inputs have been already consumed. */ private CheckRecipeResult applyRecipe(@NotNull GT_Recipe recipe, GT_ParallelHelper helper, GT_OverclockCalculator calculator, CheckRecipeResult result) { - if (!helper.getResult() - .wasSuccessful()) { - return helper.getResult(); - } - if (recipe.mCanBeBuffered) { lastRecipe = recipe; } else { @@ -398,30 +389,31 @@ public class ProcessingLogic { } /** - * Override if you don't work with regular gt recipe maps + * Finds a list of matched recipes. At this point no additional check to the matched recipe has been done. + * <p> + * Override {@link #validateRecipe} to have custom check. + * <p> + * Override this method if it doesn't work with normal recipemaps. */ @Nonnull - protected FindRecipeResult findRecipe(@Nullable GT_Recipe_Map map) { - if (map == null) return FindRecipeResult.NOT_FOUND; - - RecipeValidator recipeValidator = new RecipeValidator( - this::validateRecipe, - this::createParallelHelper, - this::createOverclockCalculator); - - FindRecipeResult findRecipeResult = map.findRecipeWithResult( - lastRecipe, - recipeValidator, - false, - false, - amperageOC ? availableVoltage * availableAmperage : availableVoltage, - inputFluids, - specialSlotItem, - inputItems); - - findRecipeResult.setRecipeValidator(recipeValidator); + protected Stream<GT_Recipe> findRecipeMatches(@Nullable RecipeMap<?> map) { + if (map == null) { + return Stream.empty(); + } + return map.findRecipeQuery() + .items(inputItems) + .fluids(inputFluids) + .specialSlot(specialSlotItem) + .cachedRecipe(lastRecipe) + .findAll(); + } - return findRecipeResult; + /** + * Override to do additional check for found recipe if needed. + */ + @Nonnull + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return CheckRecipeResultRegistry.SUCCESSFUL; } /** @@ -443,24 +435,6 @@ public class ProcessingLogic { } /** - * Override to do additional check for finding recipe if needed, mainly for special value of the recipe. - */ - @Nonnull - protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { - return CheckRecipeResultRegistry.SUCCESSFUL; - } - - /** - * Use {@link #createOverclockCalculator(GT_Recipe)} - */ - @Nonnull - @Deprecated - protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, - @Nullable GT_ParallelHelper helper) { - return createOverclockCalculator(recipe); - } - - /** * Override to tweak overclock logic if needed. */ @Nonnull @@ -514,4 +488,28 @@ public class ProcessingLogic { } // endregion + + /** + * Represents the status of check recipe calculation. {@link #successfullyConsumedInputs} does not necessarily mean + * {@link #checkRecipeResult} being successful, when duration or power is overflowed. Being failure means + * recipe cannot meet requirements and recipe search should be continued if possible. + */ + protected final static class CalculationResult { + + public final boolean successfullyConsumedInputs; + public final CheckRecipeResult checkRecipeResult; + + public static CalculationResult ofSuccess(CheckRecipeResult checkRecipeResult) { + return new CalculationResult(true, checkRecipeResult); + } + + public static CalculationResult ofFailure(CheckRecipeResult checkRecipeResult) { + return new CalculationResult(false, checkRecipeResult); + } + + private CalculationResult(boolean successfullyConsumedInputs, CheckRecipeResult checkRecipeResult) { + this.successfullyConsumedInputs = successfullyConsumedInputs; + this.checkRecipeResult = checkRecipeResult; + } + } } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Frame.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Frame.java index f17626cdd8..399c536b9f 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Frame.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Frame.java @@ -1,6 +1,6 @@ package gregtech.api.metatileentity.implementations; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sAssemblerRecipes; +import static gregtech.api.recipe.RecipeMaps.assemblerRecipes; import static gregtech.api.util.GT_RecipeBuilder.SECONDS; import static gregtech.api.util.GT_RecipeBuilder.TICKS; import static gregtech.api.util.GT_Utility.calculateRecipeEU; @@ -54,7 +54,7 @@ public class GT_MetaPipeEntity_Frame extends MetaPipeEntity { .itemOutputs(getStackForm(1)) .duration(3 * SECONDS + 4 * TICKS) .eut(calculateRecipeEU(aMaterial, 7)) - .addTo(sAssemblerRecipes); + .addTo(assemblerRecipes); } } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicGenerator.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicGenerator.java index 93bbdd2d18..897f9dad6f 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicGenerator.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicGenerator.java @@ -15,14 +15,17 @@ import gregtech.api.enums.Textures; import gregtech.api.gui.modularui.GT_UIInfos; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.RecipeMapWorkable; import gregtech.api.objects.ItemData; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.maps.FuelBackend; import gregtech.api.util.GT_OreDictUnificator; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; import gregtech.api.util.GT_Utility; import gregtech.common.GT_Pollution; -public abstract class GT_MetaTileEntity_BasicGenerator extends GT_MetaTileEntity_BasicTank { +public abstract class GT_MetaTileEntity_BasicGenerator extends GT_MetaTileEntity_BasicTank + implements RecipeMapWorkable { public GT_MetaTileEntity_BasicGenerator(int aID, String aName, String aNameRegional, int aTier, String aDescription, ITexture... aTextures) { @@ -273,7 +276,8 @@ public abstract class GT_MetaTileEntity_BasicGenerator extends GT_MetaTileEntity public abstract int getPollution(); - public abstract GT_Recipe_Map getRecipes(); + @Override + public abstract RecipeMap<?> getRecipeMap(); public abstract int getEfficiency(); @@ -287,8 +291,8 @@ public abstract class GT_MetaTileEntity_BasicGenerator extends GT_MetaTileEntity } public long getFuelValue(FluidStack aLiquid, boolean aLong) { - GT_Recipe_Map tRecipes = getRecipes(); - if (aLiquid == null || !(tRecipes instanceof GT_Recipe.GT_Recipe_Map_Fuel tFuels)) return 0; + RecipeMap<?> tRecipes = getRecipeMap(); + if (aLiquid == null || !(tRecipes.getBackend() instanceof FuelBackend tFuels)) return 0; GT_Recipe tFuel = tFuels.findFuel(aLiquid); if (tFuel == null) return 0; @@ -301,8 +305,8 @@ public abstract class GT_MetaTileEntity_BasicGenerator extends GT_MetaTileEntity } public long getFuelValue(ItemStack aStack, boolean aLong) { - if (GT_Utility.isStackInvalid(aStack) || getRecipes() == null) return 0; - GT_Recipe tFuel = getRecipes().findRecipe(getBaseMetaTileEntity(), false, Long.MAX_VALUE, null, aStack); + if (GT_Utility.isStackInvalid(aStack) || getRecipeMap() == null) return 0; + GT_Recipe tFuel = getRecipeMap().findRecipe(getBaseMetaTileEntity(), false, Long.MAX_VALUE, null, aStack); if (tFuel == null) return 0; long liters = 10L; // 1000mb/100 @@ -310,8 +314,8 @@ public abstract class GT_MetaTileEntity_BasicGenerator extends GT_MetaTileEntity } public ItemStack getEmptyContainer(ItemStack aStack) { - if (GT_Utility.isStackInvalid(aStack) || getRecipes() == null) return null; - GT_Recipe tFuel = getRecipes().findRecipe(getBaseMetaTileEntity(), false, Long.MAX_VALUE, null, aStack); + if (GT_Utility.isStackInvalid(aStack) || getRecipeMap() == null) return null; + GT_Recipe tFuel = getRecipeMap().findRecipe(getBaseMetaTileEntity(), false, Long.MAX_VALUE, null, aStack); if (tFuel != null) return GT_Utility.copyOrNull(tFuel.getOutput(0)); return GT_Utility.getContainerItem(aStack, true); } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java index 0e86829027..ba8c865301 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java @@ -14,6 +14,8 @@ import static gregtech.api.metatileentity.BaseTileEntity.STALLED_STUTTERING_TOOL import static gregtech.api.metatileentity.BaseTileEntity.STALLED_VENT_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; import static gregtech.api.metatileentity.BaseTileEntity.UNUSED_SLOT_TOOLTIP; +import static gregtech.api.util.GT_RecipeConstants.EXPLODE; +import static gregtech.api.util.GT_RecipeConstants.ON_FIRE; import static gregtech.api.util.GT_Utility.moveMultipleItemStacks; import static net.minecraftforge.common.util.ForgeDirection.DOWN; import static net.minecraftforge.common.util.ForgeDirection.UNKNOWN; @@ -23,6 +25,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; + import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; @@ -39,7 +43,6 @@ import net.minecraftforge.fluids.IFluidHandler; import org.apache.commons.lang3.tuple.Pair; import com.gtnewhorizons.modularui.api.drawable.IDrawable; -import com.gtnewhorizons.modularui.api.drawable.UITexture; import com.gtnewhorizons.modularui.api.math.Pos2d; import com.gtnewhorizons.modularui.api.math.Size; import com.gtnewhorizons.modularui.api.screen.ModularWindow; @@ -65,21 +68,24 @@ import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.modularui.IAddGregtechLogo; import gregtech.api.interfaces.modularui.IAddUIWidgets; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IOverclockDescriptionProvider; +import gregtech.api.interfaces.tileentity.RecipeMapWorkable; import gregtech.api.objects.GT_ItemStack; -import gregtech.api.recipe.check.FindRecipeResult; +import gregtech.api.objects.overclockdescriber.EUOverclockDescriber; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.recipe.BasicUIProperties; +import gregtech.api.recipe.RecipeMap; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ClientPreference; import gregtech.api.util.GT_CoverBehaviorBase; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_OverclockCalculator; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; import gregtech.api.util.GT_TooltipDataCache; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Waila; import gregtech.common.gui.modularui.UIHelper; -import gregtech.common.power.BasicMachineEUPower; -import gregtech.common.power.Power; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; @@ -89,8 +95,8 @@ import mcp.mobius.waila.api.IWailaDataAccessor; * This is the main construct for my Basic Machines such as the Automatic Extractor Extend this class to make a simple * Machine */ -public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_BasicTank - implements IConfigurationCircuitSupport, IAddGregtechLogo, IAddUIWidgets { +public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_BasicTank implements RecipeMapWorkable, + IConfigurationCircuitSupport, IOverclockDescriptionProvider, IAddGregtechLogo, IAddUIWidgets { /** * return values for checkRecipe() @@ -108,9 +114,7 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B public int mProgresstime = 0, mMaxProgresstime = 0, mEUt = 0, mOutputBlocked = 0; public ForgeDirection mMainFacing = ForgeDirection.WEST; public FluidStack mOutputFluid; - @Deprecated - public String mGUIName = "", mNEIName = ""; - protected final Power mPower; + protected final OverclockDescriber overclockDescriber; /** * Contains the Recipe which has been previously used, or null if there was no previous Recipe, which could have @@ -147,29 +151,7 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B mInputSlotCount = Math.max(0, aInputSlotCount); mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; mAmperage = aAmperage; - mPower = buildPower(); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine(int, String, String, int, int, String, int, int, - * ITexture...)} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine(int aID, String aName, String aNameRegional, int aTier, int aAmperage, - String aDescription, int aInputSlotCount, int aOutputSlotCount, String aGUIName, String aNEIName, - ITexture... aOverlays) { - super( - aID, - aName, - aNameRegional, - aTier, - OTHER_SLOT_COUNT + aInputSlotCount + aOutputSlotCount + 1, - aDescription, - aOverlays); - mInputSlotCount = Math.max(0, aInputSlotCount); - mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; - mAmperage = aAmperage; - mPower = buildPower(); + overclockDescriber = createOverclockDescriber(); } /** @@ -188,42 +170,7 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B mInputSlotCount = Math.max(0, aInputSlotCount); mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; mAmperage = aAmperage; - mPower = buildPower(); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine(int, String, String, int, int, String[], int, int, - * ITexture...)} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine(int aID, String aName, String aNameRegional, int aTier, int aAmperage, - String[] aDescription, int aInputSlotCount, int aOutputSlotCount, String aGUIName, String aNEIName, - ITexture... aOverlays) { - super( - aID, - aName, - aNameRegional, - aTier, - OTHER_SLOT_COUNT + aInputSlotCount + aOutputSlotCount + 1, - aDescription, - aOverlays); - mInputSlotCount = Math.max(0, aInputSlotCount); - mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; - mAmperage = aAmperage; - mPower = buildPower(); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine(String, int, int, String[], ITexture[][][], int, int)} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine(String aName, int aTier, int aAmperage, String aDescription, - ITexture[][][] aTextures, int aInputSlotCount, int aOutputSlotCount, String aGUIName, String aNEIName) { - super(aName, aTier, OTHER_SLOT_COUNT + aInputSlotCount + aOutputSlotCount + 1, aDescription, aTextures); - mInputSlotCount = Math.max(0, aInputSlotCount); - mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; - mAmperage = aAmperage; - mPower = buildPower(); + overclockDescriber = createOverclockDescriber(); } /** @@ -235,27 +182,14 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B mInputSlotCount = Math.max(0, aInputSlotCount); mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; mAmperage = aAmperage; - mPower = buildPower(); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine(String, int, int, String[], ITexture[][][], int, int)} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine(String aName, int aTier, int aAmperage, String[] aDescription, - ITexture[][][] aTextures, int aInputSlotCount, int aOutputSlotCount, String aGUIName, String aNEIName) { - super(aName, aTier, OTHER_SLOT_COUNT + aInputSlotCount + aOutputSlotCount + 1, aDescription, aTextures); - mInputSlotCount = Math.max(0, aInputSlotCount); - mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; - mAmperage = aAmperage; - mPower = buildPower(); + overclockDescriber = createOverclockDescriber(); } /** - * To be called by the constructor to initialize this instance's Power + * To be called by the constructor to initialize this instance's overclock behavior */ - protected Power buildPower() { - return new BasicMachineEUPower(mTier, mAmperage); + protected OverclockDescriber createOverclockDescriber() { + return new EUOverclockDescriber(mTier, mAmperage); } protected boolean isValidMainFacing(ForgeDirection side) { @@ -502,7 +436,7 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B @Override public boolean isFluidInputAllowed(FluidStack aFluid) { - return getFillableStack() != null || (getRecipeList() != null && getRecipeList().containsInput(aFluid)); + return getFillableStack() != null || (getRecipeMap() != null && getRecipeMap().containsInput(aFluid)); } @Override @@ -780,20 +714,30 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B return getBaseMetaTileEntity().decreaseStoredEnergyUnits(aEUt, false); } - protected void calculateOverclockedNess(GT_Recipe aRecipe) { - calculateOverclockedNess(aRecipe.mEUt, aRecipe.mDuration); + /** + * Calculates overclock based on {@link #overclockDescriber}. + */ + protected void calculateCustomOverclock(GT_Recipe recipe) { + GT_OverclockCalculator calculator = overclockDescriber.createCalculator( + new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) + .setDuration(recipe.mDuration) + .setOneTickDiscount(true), + recipe); + calculator.calculate(); + mEUt = (int) calculator.getConsumption(); + mMaxProgresstime = calculator.getDuration(); } /** - * Calcualtes overclocked ness using long integers - * - * @param aEUt - recipe EUt - * @param aDuration - recipe Duration + * Helper method for calculating simple overclock. */ - protected void calculateOverclockedNess(int aEUt, int aDuration) { - mPower.computePowerUsageAndDuration(aEUt, aDuration); - mEUt = mPower.getEuPerTick(); - mMaxProgresstime = mPower.getDurationTicks(); + protected void calculateOverclockedNess(int eut, int duration) { + GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(eut) + .setDuration(duration) + .setOneTickDiscount(true) + .calculate(); + mEUt = (int) calculator.getConsumption(); + mMaxProgresstime = calculator.getDuration(); } protected ItemStack getSpecialSlot() { @@ -1063,10 +1007,8 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B return GregTech_API.getConfigurationCircuitList(mTier); } - /** - * @return the Recipe List which is used for this Machine, this is a useful Default Handler - */ - public GT_Recipe_Map getRecipeList() { + @Override + public RecipeMap<?> getRecipeMap() { return null; } @@ -1115,26 +1057,26 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B * FOUND_AND_SUCCESSFULLY_USED_RECIPE = 2; */ public int checkRecipe(boolean skipOC) { - GT_Recipe_Map tMap = getRecipeList(); + RecipeMap<?> tMap = getRecipeMap(); if (tMap == null) return DID_NOT_FIND_RECIPE; - FindRecipeResult result = tMap.findRecipeWithResult( - mLastRecipe, - false, - false, - V[mTier], - new FluidStack[] { getFillableStack() }, - getSpecialSlot(), - getAllInputs()); - if (result.getState() == FindRecipeResult.State.EXPLODE && getBaseMetaTileEntity() != null) { + GT_Recipe tRecipe = tMap.findRecipeQuery() + .items(getAllInputs()) + .fluids(getFillableStack()) + .specialSlot(getSpecialSlot()) + .voltage(V[mTier]) + .cachedRecipe(mLastRecipe) + .find(); + if (tRecipe == null) { + return DID_NOT_FIND_RECIPE; + } + if (tRecipe.getMetadataOrDefault(EXPLODE, false) && getBaseMetaTileEntity() != null) { getBaseMetaTileEntity().doExplosion(V[mTier] * 4); return DID_NOT_FIND_RECIPE; } - if (result.getState() == FindRecipeResult.State.ON_FIRE && getBaseMetaTileEntity() != null) { + if (tRecipe.getMetadataOrDefault(ON_FIRE, false) && getBaseMetaTileEntity() != null) { getBaseMetaTileEntity().setOnFire(); return DID_NOT_FIND_RECIPE; } - if (!result.isSuccessful()) return DID_NOT_FIND_RECIPE; - GT_Recipe tRecipe = result.getRecipeNonNull(); if (GT_Mod.gregtechproxy.mLowGravProcessing && (tRecipe.mSpecialValue == -100 || tRecipe.mSpecialValue == -300) && !isValidForLowGravity(tRecipe, getBaseMetaTileEntity().getWorld().provider.dimensionId)) @@ -1169,7 +1111,7 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B } mOutputFluid = tRecipe.getFluidOutput(0); if (!skipOC) { - calculateOverclockedNess(tRecipe); + calculateCustomOverclock(tRecipe); // In case recipe is too OP for that machine if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; @@ -1317,16 +1259,17 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B } } + @Nonnull @Override - public Power getPower() { - return mPower; + public OverclockDescriber getOverclockDescriber() { + return overclockDescriber; } // GUI stuff @Override public boolean useModularUI() { - return getRecipeList() != null && getRecipeList().useModularUI; + return getRecipeMap() != null; } @Override @@ -1341,8 +1284,9 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B @Override public void addGregTechLogo(ModularWindow.Builder builder) { - if (getRecipeList() != null) { - getRecipeList().addGregTechLogoUI(builder, new Pos2d(0, 0)); + if (getRecipeMap() != null) { + getRecipeMap().getFrontend() + .addGregTechLogo(builder, new Pos2d(0, 0)); } else { builder.widget( new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) @@ -1358,22 +1302,13 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B builder.widget(createItemAutoOutputButton()); } - addIOSlots(builder); + BasicUIProperties uiProperties = getUIProperties(); + addIOSlots(builder, uiProperties); builder.widget(createChargerSlot(79, 62)); - if (getRecipeList() != null) { - builder.widget( - setNEITransferRect( - createProgressBar( - isSteampowered() ? getRecipeList().getProgressBarTextureSteam(getSteamVariant()) - : getRecipeList().getProgressBarTexture(), - getRecipeList().getProgressBarImageSize(), - getRecipeList().progressBarDirection, - getRecipeList().progressBarPos, - getRecipeList().progressBarSize), - getRecipeList().mNEIName)); - addProgressBarSpecialTextures(builder); - } + + addProgressBar(builder, uiProperties); + builder.widget( createErrorStatusArea( builder, @@ -1381,29 +1316,82 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B } /** + * Override to specify UI properties if this machine doesn't work with recipemap. + */ + protected BasicUIProperties getUIProperties() { + if (getRecipeMap() != null) { + BasicUIProperties originalProperties = getRecipeMap().getFrontend() + .getUIProperties(); + return originalProperties.toBuilder() + .maxItemInputs(mInputSlotCount) + .maxItemOutputs(mOutputItems.length) + .maxFluidInputs(Math.min(originalProperties.maxFluidInputs, 1)) + .maxFluidOutputs(Math.min(originalProperties.maxFluidOutputs, 1)) + .build(); + } + return BasicUIProperties.builder() + .maxItemInputs(mInputSlotCount) + .maxItemOutputs(mOutputItems.length) + .maxFluidInputs(getCapacity() != 0 ? 1 : 0) + .maxFluidOutputs(0) + .build(); + } + + /** * Adds item I/O, special item, and fluid I/O slots. */ - protected void addIOSlots(ModularWindow.Builder builder) { - final boolean hasFluidInput = getRecipeList() != null ? (getRecipeList().hasFluidInputs()) - : (getCapacity() != 0); - final boolean hasFluidOutput = getRecipeList() != null && getRecipeList().hasFluidOutputs(); + protected void addIOSlots(ModularWindow.Builder builder, BasicUIProperties uiProperties) { UIHelper.forEachSlots( (i, backgrounds, pos) -> builder.widget(createItemInputSlot(i, backgrounds, pos)), (i, backgrounds, pos) -> builder.widget(createItemOutputSlot(i, backgrounds, pos)), - (i, backgrounds, pos) -> builder.widget(createSpecialSlot(backgrounds, pos)), + (i, backgrounds, pos) -> builder.widget(createSpecialSlot(backgrounds, pos, uiProperties)), (i, backgrounds, pos) -> builder.widget(createFluidInputSlot(backgrounds, pos)), (i, backgrounds, pos) -> builder.widget(createFluidOutputSlot(backgrounds, pos)), getGUITextureSet().getItemSlot(), getGUITextureSet().getFluidSlot(), - getRecipeList(), - mInputSlotCount, - mOutputItems.length, - hasFluidInput ? 1 : 0, - hasFluidOutput ? 1 : 0, + uiProperties, + uiProperties.maxItemInputs, + uiProperties.maxItemOutputs, + uiProperties.maxFluidInputs, + uiProperties.maxFluidOutputs, getSteamVariant(), Pos2d.ZERO); } + protected void addProgressBar(ModularWindow.Builder builder, BasicUIProperties uiProperties) { + boolean isSteamPowered = isSteampowered(); + RecipeMap<?> recipeMap = getRecipeMap(); + if (!isSteamPowered && uiProperties.progressBarTexture == null) { + if (recipeMap != null) { + // Require progress bar texture for machines working with recipemap, otherwise permit + throw new RuntimeException("Missing progressbar texture for " + recipeMap.unlocalizedName); + } else { + return; + } + } + if (isSteamPowered && uiProperties.progressBarTextureSteam == null) { + if (recipeMap != null) { + throw new RuntimeException("Missing steam progressbar texture for " + recipeMap.unlocalizedName); + } else { + return; + } + } + + builder.widget( + setNEITransferRect( + new ProgressBar() + .setProgress(() -> maxProgresstime() != 0 ? (float) getProgresstime() / maxProgresstime() : 0) + .setTexture( + isSteamPowered ? uiProperties.progressBarTextureSteam.get(getSteamVariant()) + : uiProperties.progressBarTexture.get(), + uiProperties.progressBarImageSize) + .setDirection(uiProperties.progressBarDirection) + .setPos(uiProperties.progressBarPos) + .setSize(uiProperties.progressBarSize), + uiProperties.neiTransferRectId)); + addProgressBarSpecialTextures(builder, uiProperties); + } + /** * Override this as needed instead of calling. */ @@ -1425,13 +1413,11 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B /** * Override this as needed instead of calling. */ - protected SlotWidget createSpecialSlot(IDrawable[] backgrounds, Pos2d pos) { + protected SlotWidget createSpecialSlot(IDrawable[] backgrounds, Pos2d pos, BasicUIProperties uiProperties) { return (SlotWidget) new SlotWidget(inventoryHandler, getSpecialSlotIndex()).setAccess(true, true) .disableShiftInsert() .setGTTooltip( - () -> mTooltipCache.getData( - getRecipeList() != null && getRecipeList().usesSpecialSlot() ? SPECIAL_SLOT_TOOLTIP - : UNUSED_SLOT_TOOLTIP)) + () -> mTooltipCache.getData(uiProperties.useSpecialSlot ? SPECIAL_SLOT_TOOLTIP : UNUSED_SLOT_TOOLTIP)) .setTooltipShowUpDelay(TOOLTIP_DELAY) .setBackground(backgrounds) .setPos(pos); @@ -1478,40 +1464,25 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B .setSize(18, 18); } - protected ProgressBar createProgressBar(UITexture texture, int imageSize, ProgressBar.Direction direction, - Pos2d pos, Size size) { - final ProgressBar ret = new ProgressBar(); - ret.setProgress(() -> maxProgresstime() != 0 ? (float) getProgresstime() / maxProgresstime() : 0) - .setTexture(texture, imageSize) - .setDirection(direction) - .setPos(pos) - .setSize(size); - return ret; - } - - public boolean hasNEITransferRect() { - return getRecipeList() != null; - } - protected Widget setNEITransferRect(Widget widget, String transferRectID) { - if (hasNEITransferRect()) { - final Power powerInfo = getPower(); - final String transferRectTooltip; - if (isSteampowered()) { - transferRectTooltip = StatCollector - .translateToLocalFormatted(NEI_TRANSFER_STEAM_TOOLTIP, powerInfo.getTierString()); - } else { - transferRectTooltip = StatCollector - .translateToLocalFormatted(NEI_TRANSFER_VOLTAGE_TOOLTIP, powerInfo.getTierString()); - } - widget.setNEITransferRect(transferRectID, new Object[] { powerInfo }, transferRectTooltip); + if (GT_Utility.isStringInvalid(transferRectID)) { + return widget; + } + final String transferRectTooltip; + if (isSteampowered()) { + transferRectTooltip = StatCollector + .translateToLocalFormatted(NEI_TRANSFER_STEAM_TOOLTIP, overclockDescriber.getTierString()); + } else { + transferRectTooltip = StatCollector + .translateToLocalFormatted(NEI_TRANSFER_VOLTAGE_TOOLTIP, overclockDescriber.getTierString()); } + widget.setNEITransferRect(transferRectID, new Object[] { overclockDescriber }, transferRectTooltip); return widget; } - protected void addProgressBarSpecialTextures(ModularWindow.Builder builder) { + protected void addProgressBarSpecialTextures(ModularWindow.Builder builder, BasicUIProperties uiProperties) { if (isSteampowered()) { - for (Pair<SteamTexture, Pair<Size, Pos2d>> specialTexture : getRecipeList().specialTexturesSteam) { + for (Pair<SteamTexture, Pair<Size, Pos2d>> specialTexture : uiProperties.specialTexturesSteam) { builder.widget( new DrawableWidget().setDrawable( specialTexture.getLeft() @@ -1524,7 +1495,7 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B .getRight())); } } else { - for (Pair<IDrawable, Pair<Size, Pos2d>> specialTexture : getRecipeList().specialTextures) { + for (Pair<IDrawable, Pair<Size, Pos2d>> specialTexture : uiProperties.specialTextures) { builder.widget( new DrawableWidget().setDrawable(specialTexture.getLeft()) .setSize( diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Bronze.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Bronze.java index e1321c144f..5eb648d560 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Bronze.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Bronze.java @@ -35,13 +35,13 @@ import gregtech.api.gui.modularui.GUITextureSet; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.objects.overclockdescriber.SteamOverclockDescriber; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; -import gregtech.common.power.Power; -import gregtech.common.power.SteamPower; /** * NEVER INCLUDE THIS FILE IN YOUR MOD!!! @@ -70,8 +70,8 @@ public abstract class GT_MetaTileEntity_BasicMachine_Bronze extends GT_MetaTileE } @Override - public Power buildPower() { - return new SteamPower(mTier, 1, 2); + public OverclockDescriber createOverclockDescriber() { + return new SteamOverclockDescriber(SteamVariant.BRONZE, 1, 2); } @Override @@ -189,11 +189,11 @@ public abstract class GT_MetaTileEntity_BasicMachine_Bronze extends GT_MetaTileE @Override public int checkRecipe() { - GT_Recipe tRecipe = getRecipeList().findRecipe(getBaseMetaTileEntity(), false, TierEU.LV, null, getAllInputs()); + GT_Recipe tRecipe = getRecipeMap().findRecipe(getBaseMetaTileEntity(), false, TierEU.LV, null, getAllInputs()); if ((tRecipe != null) && (canOutput(tRecipe.mOutputs)) && (tRecipe.isRecipeInputEqual(true, null, getAllInputs()))) { this.mOutputItems[0] = tRecipe.getOutput(0); - calculateOverclockedNess(tRecipe); + calculateCustomOverclock(tRecipe); return FOUND_AND_SUCCESSFULLY_USED_RECIPE; } return DID_NOT_FIND_RECIPE; @@ -380,7 +380,7 @@ public abstract class GT_MetaTileEntity_BasicMachine_Bronze extends GT_MetaTileE String[] description = Arrays.copyOf(mDescriptionArray, mDescriptionArray.length + 1); description[mDescriptionArray.length] = StatCollector.translateToLocal(TT_machineType) + ": " + EnumChatFormatting.YELLOW - + StatCollector.translateToLocal(this.getRecipeList().mUnlocalizedName) + + StatCollector.translateToLocal(this.getRecipeMap().unlocalizedName) + EnumChatFormatting.RESET; return description; } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_GT_Recipe.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_GT_Recipe.java index 3297490b51..8bba0fee25 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_GT_Recipe.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_GT_Recipe.java @@ -5,7 +5,6 @@ import static gregtech.api.enums.GT_Values.VN; import static gregtech.api.enums.GT_Values.W; import static gregtech.api.enums.GT_Values.ticksBetweenSounds; import static gregtech.api.enums.Mods.BartWorks; -import static gregtech.api.enums.Mods.GregTech; import static gregtech.api.objects.XSTR.XSTR_INSTANCE; import static net.minecraftforge.common.util.ForgeDirection.UP; @@ -21,9 +20,6 @@ import net.minecraftforge.oredict.OreDictionary; import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; import com.gtnewhorizons.modularui.api.drawable.UITexture; -import com.gtnewhorizons.modularui.api.math.Pos2d; -import com.gtnewhorizons.modularui.api.math.Size; -import com.gtnewhorizons.modularui.common.widget.ProgressBar; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -39,10 +35,11 @@ import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.recipe.BasicUIProperties; +import gregtech.api.recipe.RecipeMap; import gregtech.api.render.TextureFactory; import gregtech.api.util.ExternalMaterials; import gregtech.api.util.GT_ModHandler; -import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; import ic2.core.Ic2Items; @@ -55,20 +52,19 @@ import ic2.core.Ic2Items; */ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_BasicMachine { - private final GT_Recipe.GT_Recipe_Map mRecipes; + private final RecipeMap<?> mRecipes; private final int mTankCapacity; private final SpecialEffects mSpecialEffect; private final ResourceLocation mSoundResourceLocation; - private final boolean mSharedTank, mRequiresFluidForFiltering; private FallbackableUITexture progressBarTexture; + private int recipeCatalystPriority; /** * Registers machine with single-line description, specific tank capacity, and sound specified by ResourceLocation. */ public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, - ResourceLocation aSound, boolean aSharedTank, boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, - String aOverlays, Object[] aRecipe) { + String aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + ResourceLocation aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { this( aID, aName, @@ -80,8 +76,6 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ aOutputSlots, aTankCapacity, aSound, - aSharedTank, - aRequiresFluidForFiltering, aSpecialEffect, aOverlays, aRecipe); @@ -91,15 +85,14 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ * Registers machine with multi-line descriptions, specific tank capacity, and sound specified by ResourceLocation. */ public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String[] aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, - ResourceLocation aSound, boolean aSharedTank, boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, - String aOverlays, Object[] aRecipe) { + String[] aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + ResourceLocation aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { super( aID, aName, aNameRegional, aTier, - aRecipes.mAmperage, + aRecipes.getAmperage(), aDescription, aInputSlots, aOutputSlots, @@ -176,13 +169,12 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_BOTTOM_GLOW"))) .glow() .build())); - this.mSharedTank = aSharedTank; this.mTankCapacity = aTankCapacity; this.mSpecialEffect = aSpecialEffect; - this.mRequiresFluidForFiltering = aRequiresFluidForFiltering; this.mRecipes = aRecipes; this.mSoundResourceLocation = aSound; - this.progressBarTexture = mRecipes.getProgressBarTextureRaw(); + this.progressBarTexture = mRecipes.getFrontend() + .getUIProperties().progressBarTexture; // TODO: CHECK if (aRecipe != null) { @@ -447,9 +439,8 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ * Registers machine with single-line description, auto-scaled fluid tank, and sound specified by SoundResource. */ public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, - SoundResource aSound, boolean aSharedTank, boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, - String aOverlays, Object[] aRecipe) { + String aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { this( aID, aName, @@ -461,35 +452,6 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ aOutputSlots, usesFluids ? getCapacityForTier(aTier) : 0, aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, - aSpecialEffect, - aOverlays, - aRecipe); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine_GT_Recipe(int, String, String, int, String, - * GT_Recipe.GT_Recipe_Map, int, int, boolean, SoundResource, boolean, boolean, SpecialEffects, String, Object[])} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, - int aGUIParameterA, int aGUIParameterB, String aGUIName, SoundResource aSound, boolean aSharedTank, - boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { - this( - aID, - aName, - aNameRegional, - aTier, - aDescription, - aRecipes, - aInputSlots, - aOutputSlots, - usesFluids ? getCapacityForTier(aTier) : 0, - aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, aSpecialEffect, aOverlays, aRecipe); @@ -499,9 +461,8 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ * Registers machine with multi-line descriptions, auto-scaled fluid tank, and sound specified by SoundResource. */ public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String[] aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, - SoundResource aSound, boolean aSharedTank, boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, - String aOverlays, Object[] aRecipe) { + String[] aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { this( aID, aName, @@ -513,35 +474,6 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ aOutputSlots, usesFluids ? getCapacityForTier(aTier) : 0, aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, - aSpecialEffect, - aOverlays, - aRecipe); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine_GT_Recipe(int, String, String, int, String[], - * GT_Recipe.GT_Recipe_Map, int, int, boolean, SoundResource, boolean, boolean, SpecialEffects, String, Object[])} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String[] aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, - int aGUIParameterA, int aGUIParameterB, String aGUIName, SoundResource aSound, boolean aSharedTank, - boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { - this( - aID, - aName, - aNameRegional, - aTier, - aDescription, - aRecipes, - aInputSlots, - aOutputSlots, - usesFluids ? getCapacityForTier(aTier) : 0, - aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, aSpecialEffect, aOverlays, aRecipe); @@ -551,9 +483,8 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ * Registers machine with single-line description, specific tank capacity, and sound specified by SoundResource. */ public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, - SoundResource aSound, boolean aSharedTank, boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, - String aOverlays, Object[] aRecipe) { + String aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { this( aID, aName, @@ -565,35 +496,6 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ aOutputSlots, aTankCapacity, aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, - aSpecialEffect, - aOverlays, - aRecipe); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine_GT_Recipe(int, String, String, int, String, - * GT_Recipe.GT_Recipe_Map, int, int, int, SoundResource, boolean, boolean, SpecialEffects, String, Object[])} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, - int aGUIParameterA, int aGUIParameterB, String aGUIName, SoundResource aSound, boolean aSharedTank, - boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { - this( - aID, - aName, - aNameRegional, - aTier, - aDescription, - aRecipes, - aInputSlots, - aOutputSlots, - aTankCapacity, - aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, aSpecialEffect, aOverlays, aRecipe); @@ -603,36 +505,8 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ * Registers machine with multi-line descriptions, specific tank capacity, and sound specified by SoundResource. */ public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String[] aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, - SoundResource aSound, boolean aSharedTank, boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, - String aOverlays, Object[] aRecipe) { - this( - aID, - aName, - aNameRegional, - aTier, - aDescription, - aRecipes, - aInputSlots, - aOutputSlots, - aTankCapacity, - aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, - aSpecialEffect, - aOverlays, - aRecipe); - } - - /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine_GT_Recipe(int, String, String, int, String[], - * GT_Recipe.GT_Recipe_Map, int, int, int, SoundResource, boolean, boolean, SpecialEffects, String, Object[])} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String[] aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, - int aGUIParameterA, int aGUIParameterB, String aGUIName, SoundResource aSound, boolean aSharedTank, - boolean aRequiresFluidForFiltering, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { + String[] aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { this( aID, aName, @@ -644,52 +518,20 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ aOutputSlots, aTankCapacity, aSound.resourceLocation, - aSharedTank, - aRequiresFluidForFiltering, aSpecialEffect, aOverlays, aRecipe); } /** - * @deprecated Use {@link #GT_MetaTileEntity_BasicMachine_GT_Recipe(int, String, String, int, String, - * GT_Recipe.GT_Recipe_Map, int, int, int, ResourceLocation, boolean, boolean, SpecialEffects, String, Object[])} - */ - @Deprecated - public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, - String aDescription, GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, - int aGUIParameterA, int aGUIParameterB, String aGUIName, String aSound, boolean aSharedTank, - boolean aRequiresFluidForFiltering, int aSpecialEffect, String aOverlays, Object[] aRecipe) { - this( - aID, - aName, - aNameRegional, - aTier, - aDescription, - aRecipes, - aInputSlots, - aOutputSlots, - aTankCapacity, - new ResourceLocation(aSound), - aSharedTank, - aRequiresFluidForFiltering, - SpecialEffects.fromId(aSpecialEffect), - aOverlays, - aRecipe); - } - - /** * For {@link #newMetaEntity}. */ public GT_MetaTileEntity_BasicMachine_GT_Recipe(String aName, int aTier, String[] aDescription, - GT_Recipe.GT_Recipe_Map aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, int aAmperage, - ITexture[][][] aTextures, ResourceLocation aSound, boolean aSharedTank, boolean aRequiresFluidForFiltering, - SpecialEffects aSpecialEffect) { + RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, int aAmperage, + ITexture[][][] aTextures, ResourceLocation aSound, SpecialEffects aSpecialEffect) { super(aName, aTier, aAmperage, aDescription, aTextures, aInputSlots, aOutputSlots); - this.mSharedTank = aSharedTank; this.mTankCapacity = aTankCapacity; this.mSpecialEffect = aSpecialEffect; - this.mRequiresFluidForFiltering = aRequiresFluidForFiltering; this.mRecipes = aRecipes; this.mSoundResourceLocation = aSound; } @@ -707,9 +549,8 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ this.mAmperage, this.mTextures, this.mSoundResourceLocation, - this.mSharedTank, - this.mRequiresFluidForFiltering, - this.mSpecialEffect).setProgressBarTexture(this.progressBarTexture); + this.mSpecialEffect).setProgressBarTexture(this.progressBarTexture) + .setRecipeCatalystPriority(this.recipeCatalystPriority); } public GT_MetaTileEntity_BasicMachine_GT_Recipe setProgressBarTexture(FallbackableUITexture progressBarTexture) { @@ -718,8 +559,7 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ } public GT_MetaTileEntity_BasicMachine_GT_Recipe setProgressBarTextureName(String name, UITexture fallback) { - return setProgressBarTexture( - new FallbackableUITexture(UITexture.fullImage(GregTech.ID, "gui/progressbar/" + name), fallback)); + return setProgressBarTexture(GT_UITextures.fallbackableProgressbar(name, fallback)); } public GT_MetaTileEntity_BasicMachine_GT_Recipe setProgressBarTextureName(String name) { @@ -735,9 +575,9 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ return false; } case 1 -> { - if (this.getFillableStack() == null) return !this.mRequiresFluidForFiltering && this.getRecipeList() + if (this.getFillableStack() == null) return this.getRecipeMap() .containsInput(aStack); - else return this.getRecipeList() + else return this.getRecipeMap() .findRecipe( this.getBaseMetaTileEntity(), this.mLastRecipe, @@ -750,25 +590,23 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ != null; } case 2 -> { - return (!this.mRequiresFluidForFiltering || this.getFillableStack() != null) - && (((this.getInputAt(0) != null && this.getInputAt(1) != null) - || (this.getInputAt(0) == null && this.getInputAt(1) == null ? this.getRecipeList() + return ((this.getInputAt(0) != null && this.getInputAt(1) != null) + || (this.getInputAt(0) == null && this.getInputAt(1) == null ? this.getRecipeMap() + .containsInput(aStack) + : (this.getRecipeMap() .containsInput(aStack) - : (this.getRecipeList() - .containsInput(aStack) - && this.getRecipeList() - .findRecipe( - this.getBaseMetaTileEntity(), - this.mLastRecipe, - true, - true, - V[this.mTier], - new FluidStack[] { this.getFillableStack() }, - this.getSpecialSlot(), - aIndex == this.getInputSlot() - ? appendSelectedCircuit(aStack, this.getInputAt(1)) - : appendSelectedCircuit(this.getInputAt(0), aStack)) - != null)))); + && this.getRecipeMap() + .findRecipe( + this.getBaseMetaTileEntity(), + this.mLastRecipe, + true, + true, + V[this.mTier], + new FluidStack[] { this.getFillableStack() }, + this.getSpecialSlot(), + aIndex == this.getInputSlot() ? appendSelectedCircuit(aStack, this.getInputAt(1)) + : appendSelectedCircuit(this.getInputAt(0), aStack)) + != null))); } default -> { int tID = this.getBaseMetaTileEntity() @@ -786,7 +624,7 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ .startsWith("circuit")) return true; } } - return this.getRecipeList() + return this.getRecipeMap() .containsInput(aStack); } } @@ -889,11 +727,21 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ } @Override - public GT_Recipe.GT_Recipe_Map getRecipeList() { + public RecipeMap<?> getRecipeMap() { return this.mRecipes; } @Override + public int getRecipeCatalystPriority() { + return recipeCatalystPriority; + } + + public GT_MetaTileEntity_BasicMachine_GT_Recipe setRecipeCatalystPriority(int recipeCatalystPriority) { + this.recipeCatalystPriority = recipeCatalystPriority; + return this; + } + + @Override public int getCapacity() { return this.mTankCapacity; } @@ -922,20 +770,10 @@ public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_ } @Override - public FluidStack getFillableStack() { - return this.mSharedTank ? this.getDrainableStack() : super.getFillableStack(); - } - - @Override - public FluidStack setFillableStack(FluidStack aFluid) { - return this.mSharedTank ? this.setDrainableStack(aFluid) : super.setFillableStack(aFluid); - } - - @Override - protected ProgressBar createProgressBar(UITexture texture, int imageSize, ProgressBar.Direction direction, - Pos2d pos, Size size) { - return super.createProgressBar(texture, imageSize, direction, pos, size) - .setTexture(progressBarTexture.get(), mRecipes.getProgressBarImageSize()); + protected BasicUIProperties getUIProperties() { + return super.getUIProperties().toBuilder() + .progressBarTexture(progressBarTexture) + .build(); } public enum X { diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Steel.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Steel.java index eae713d28a..d6ae385430 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Steel.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Steel.java @@ -12,9 +12,9 @@ import gregtech.api.enums.Dyes; import gregtech.api.enums.SteamVariant; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.modularui.IGetTitleColor; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.objects.overclockdescriber.SteamOverclockDescriber; import gregtech.api.render.TextureFactory; -import gregtech.common.power.Power; -import gregtech.common.power.SteamPower; /** * NEVER INCLUDE THIS FILE IN YOUR MOD!!! @@ -36,8 +36,8 @@ public abstract class GT_MetaTileEntity_BasicMachine_Steel extends GT_MetaTileEn } @Override - public Power buildPower() { - return new SteamPower(mTier, 2, 1); + public OverclockDescriber createOverclockDescriber() { + return new SteamOverclockDescriber(SteamVariant.STEEL, 2, 1); } @Override diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java index 85fb98cafd..6f351fb5ab 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java @@ -20,6 +20,7 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.logic.ProcessingLogic; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.util.GT_ExoticEnergyInputHelper; +import gregtech.api.util.GT_OverclockCalculator; import gregtech.api.util.GT_Utility; /** @@ -54,29 +55,13 @@ public abstract class GT_MetaTileEntity_ExtendedPowerMultiBlockBase<T extends GT @Override protected void calculateOverclockedNessMultiInternal(long aEUt, int aDuration, int mAmperage, long maxInputVoltage, boolean perfectOC) { - // 5% space for cable loss - long zMaxInputVoltage = maxInputVoltage / 100L * 95L; - long zTime = aDuration; - long zEUt = aEUt; - while (zEUt < zMaxInputVoltage) { - zEUt = zEUt << 2; - zTime = zTime >> (perfectOC ? 2 : 1); - if (zTime <= 0) { - break; - } - } - if (zTime <= 0) { - zTime = 1; - } - if (zEUt > zMaxInputVoltage) { - zEUt = zEUt >> 2; - zTime = zTime << (perfectOC ? 2 : 1); - } - if (zTime > Integer.MAX_VALUE - 1) { - zTime = Integer.MAX_VALUE - 1; - } - this.lEUt = zEUt; - this.mMaxProgresstime = (int) zTime; + GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(aEUt) + .setEUt(maxInputVoltage * mAmperage) + .setDuration(aDuration) + .setDurationDecreasePerOC(perfectOC ? 2 : 1) + .calculate(); + lEUt = calculator.getConsumption(); + mMaxProgresstime = calculator.getDuration(); } @Override diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Input.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Input.java index b6eb19b5aa..18aef371b6 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Input.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Input.java @@ -14,13 +14,13 @@ import gregtech.api.gui.modularui.GT_UIInfos; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.recipe.RecipeMap; import gregtech.api.render.TextureFactory; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; import gregtech.api.util.GT_Utility; public class GT_MetaTileEntity_Hatch_Input extends GT_MetaTileEntity_Hatch { - public GT_Recipe_Map mRecipeMap = null; + public RecipeMap<?> mRecipeMap = null; public GT_MetaTileEntity_Hatch_Input(int aID, String aName, String aNameRegional, int aTier) { this( @@ -112,13 +112,15 @@ public class GT_MetaTileEntity_Hatch_Input extends GT_MetaTileEntity_Hatch { @Override public void saveNBTData(NBTTagCompound aNBT) { super.saveNBTData(aNBT); - if (mRecipeMap != null) aNBT.setString("recipeMap", mRecipeMap.mUniqueIdentifier); + if (mRecipeMap != null) { + aNBT.setString("recipeMap", mRecipeMap.unlocalizedName); + } } @Override public void loadNBTData(NBTTagCompound aNBT) { super.loadNBTData(aNBT); - mRecipeMap = GT_Recipe_Map.sIndexedMappings.getOrDefault(aNBT.getString("recipeMap"), null); + mRecipeMap = RecipeMap.getFromOldIdentifier(aNBT.getString("recipeMap")); } @Override diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_InputBus.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_InputBus.java index 5769cd82c2..f4c4eb6a14 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_InputBus.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_InputBus.java @@ -30,23 +30,22 @@ import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.modularui.IAddUIWidgets; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.recipe.RecipeMap; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ClientPreference; import gregtech.api.util.GT_OreDictUnificator; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; import gregtech.api.util.GT_TooltipDataCache; import gregtech.api.util.GT_Utility; import gregtech.api.util.extensions.ArrayExt; -import gregtech.common.tileentities.machines.IRecipeProcessingAwareHatch; public class GT_MetaTileEntity_Hatch_InputBus extends GT_MetaTileEntity_Hatch - implements IConfigurationCircuitSupport, IAddUIWidgets, IRecipeProcessingAwareHatch { + implements IConfigurationCircuitSupport, IAddUIWidgets { private static final String SORTING_MODE_TOOLTIP = "GT5U.machines.sorting_mode.tooltip"; private static final String ONE_STACK_LIMIT_TOOLTIP = "GT5U.machines.one_stack_limit.tooltip"; private static final int BUTTON_SIZE = 18; - public GT_Recipe_Map mRecipeMap = null; + public RecipeMap<?> mRecipeMap = null; public boolean disableSort; public boolean disableFilter = true; public boolean disableLimited = true; @@ -204,7 +203,9 @@ public class GT_MetaTileEntity_Hatch_InputBus extends GT_MetaTileEntity_Hatch aNBT.setBoolean("disableSort", disableSort); aNBT.setBoolean("disableFilter", disableFilter); aNBT.setBoolean("disableLimited", disableLimited); - if (mRecipeMap != null) aNBT.setString("recipeMap", mRecipeMap.mUniqueIdentifier); + if (mRecipeMap != null) { + aNBT.setString("recipeMap", mRecipeMap.unlocalizedName); + } } @Override @@ -212,8 +213,10 @@ public class GT_MetaTileEntity_Hatch_InputBus extends GT_MetaTileEntity_Hatch super.loadNBTData(aNBT); disableSort = aNBT.getBoolean("disableSort"); disableFilter = aNBT.getBoolean("disableFilter"); - if (aNBT.hasKey("disableLimited")) disableLimited = aNBT.getBoolean("disableLimited"); - mRecipeMap = GT_Recipe_Map.sIndexedMappings.getOrDefault(aNBT.getString("recipeMap"), null); + if (aNBT.hasKey("disableLimited")) { + disableLimited = aNBT.getBoolean("disableLimited"); + } + mRecipeMap = RecipeMap.getFromOldIdentifier(aNBT.getString("recipeMap")); } @Override diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java index 767695658c..d2d3c347a0 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java @@ -72,15 +72,16 @@ import gregtech.api.items.GT_MetaGenerated_Tool; import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.RecipeMap; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.recipe.check.SingleRecipeCheck; import gregtech.api.util.GT_ClientPreference; import gregtech.api.util.GT_ExoticEnergyInputHelper; import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_OverclockCalculator; import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Waila; import gregtech.api.util.OutputHatchWrapper; @@ -785,9 +786,13 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity IDualInputInventory slot = it.next(); processingLogic.setInputItems(slot.getItemInputs()); processingLogic.setInputFluids(slot.getFluidInputs()); - result = processingLogic.process(); - if (result.wasSuccessful()) { - return result; + CheckRecipeResult foundResult = processingLogic.process(); + if (foundResult.wasSuccessful()) { + return foundResult; + } + if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that and continue searching + result = foundResult; } } } @@ -808,9 +813,13 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity inputItems.add(getControllerSlot()); } processingLogic.setInputItems(inputItems.toArray(new ItemStack[0])); - result = processingLogic.process(); - if (result.wasSuccessful()) { - return result; + CheckRecipeResult foundResult = processingLogic.process(); + if (foundResult.wasSuccessful()) { + return foundResult; + } + if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that and continue searching + result = foundResult; } } } else { @@ -819,7 +828,14 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity inputItems.add(getControllerSlot()); } processingLogic.setInputItems(inputItems); - result = processingLogic.process(); + CheckRecipeResult foundResult = processingLogic.process(); + if (foundResult.wasSuccessful()) { + return foundResult; + } + if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that + result = foundResult; + } } return result; } @@ -1119,50 +1135,13 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity */ protected void calculateOverclockedNessMultiInternal(long aEUt, int aDuration, int mAmperage, long maxInputVoltage, boolean perfectOC) { - byte mTier = (byte) Math.max(0, GT_Utility.getTier(maxInputVoltage)); - if (mTier == 0) { - // Long time calculation - long xMaxProgresstime = ((long) aDuration) << 1; - if (xMaxProgresstime > Integer.MAX_VALUE - 1) { - // make impossible if too long - mEUt = Integer.MAX_VALUE - 1; - mMaxProgresstime = Integer.MAX_VALUE - 1; - } else { - mEUt = GT_Utility.safeInt(aEUt >> 2); - mMaxProgresstime = (int) xMaxProgresstime; - } - } else { - // Long EUt calculation - long xEUt = aEUt; - // Isnt too low EUt check? - long tempEUt = Math.max(xEUt, V[1]); - - mMaxProgresstime = aDuration; - - final int ocTimeShift = perfectOC ? 2 : 1; - - while (tempEUt <= V[mTier - 1] * mAmperage) { - tempEUt <<= 2; // this actually controls overclocking - // xEUt *= 4;//this is effect of everclocking - int oldTime = mMaxProgresstime; - mMaxProgresstime >>= ocTimeShift; // this is effect of overclocking - if (mMaxProgresstime < 1) { - if (oldTime == 1) break; - xEUt *= (long) oldTime * (perfectOC ? 1 : 2); - break; - } else { - xEUt <<= 2; - } - } - if (xEUt > Integer.MAX_VALUE - 1) { - mEUt = Integer.MAX_VALUE - 1; - mMaxProgresstime = Integer.MAX_VALUE - 1; - } else { - mEUt = (int) xEUt; - if (mEUt == 0) mEUt = 1; - if (mMaxProgresstime == 0) mMaxProgresstime = 1; // set time to 1 tick - } - } + GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(aEUt) + .setEUt(maxInputVoltage * mAmperage) + .setDuration(aDuration) + .setDurationDecreasePerOC(perfectOC ? 2 : 1) + .calculate(); + mEUt = (int) calculator.getConsumption(); + mMaxProgresstime = calculator.getDuration(); } @Deprecated @@ -1234,7 +1213,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity public boolean depleteInput(FluidStack aLiquid, boolean simulate) { if (aLiquid == null) return false; for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { - tHatch.mRecipeMap = getRecipeMap(); + setHatchRecipeMap(tHatch); FluidStack tLiquid = tHatch.drain(ForgeDirection.UNKNOWN, aLiquid, false); if (tLiquid != null && tLiquid.amount >= aLiquid.amount) { if (simulate) { @@ -1274,7 +1253,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity FluidStack aLiquid = GT_Utility.getFluidForFilledItem(aStack, true); if (aLiquid != null) return depleteInput(aLiquid); for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { - tHatch.mRecipeMap = getRecipeMap(); + setHatchRecipeMap(tHatch); if (GT_Utility.areStacksEqual( aStack, tHatch.getBaseMetaTileEntity() @@ -1336,7 +1315,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity ArrayList<FluidStack> rList = new ArrayList<>(); for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { - tHatch.mRecipeMap = getRecipeMap(); + setHatchRecipeMap(tHatch); if (tHatch instanceof GT_MetaTileEntity_Hatch_MultiInput) { for (FluidStack tFluid : ((GT_MetaTileEntity_Hatch_MultiInput) tHatch).getStoredFluid()) { if (tFluid != null) { @@ -1393,7 +1372,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity } @Override - public GT_Recipe_Map getRecipeMap() { + public RecipeMap<?> getRecipeMap() { return null; } @@ -1414,7 +1393,9 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity protected void startRecipeProcessing() { for (GT_MetaTileEntity_Hatch_InputBus hatch : filterValidMTEs(mInputBusses)) { - hatch.startRecipeProcessing(); + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + aware.startRecipeProcessing(); + } } for (GT_MetaTileEntity_Hatch_Input hatch : filterValidMTEs(mInputHatches)) { if (hatch instanceof IRecipeProcessingAwareHatch aware) { @@ -1431,7 +1412,9 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity }; for (GT_MetaTileEntity_Hatch_InputBus hatch : filterValidMTEs(mInputBusses)) { - setResultIfFailure.accept(hatch.endRecipeProcessing(this)); + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + setResultIfFailure.accept(aware.endRecipeProcessing(this)); + } } for (GT_MetaTileEntity_Hatch_Input hatch : filterValidMTEs(mInputHatches)) { if (hatch instanceof IRecipeProcessingAwareHatch aware) { @@ -1453,7 +1436,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return mDualInputHatches.add(hatch); } if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) { - ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = getRecipeMap(); + setHatchRecipeMap((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity); return mInputHatches.add((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity); } if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_InputBus) { @@ -1587,7 +1570,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input hatch) { hatch.updateTexture(aBaseCasingIndex); hatch.updateCraftingIcon(this.getMachineCraftingIcon()); - hatch.mRecipeMap = getRecipeMap(); + setHatchRecipeMap(hatch); return mInputHatches.add(hatch); } return false; @@ -1605,6 +1588,10 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return false; } + protected void setHatchRecipeMap(GT_MetaTileEntity_Hatch_Input hatch) { + hatch.mRecipeMap = getRecipeMap(); + } + @Override public String[] getInfoData() { int mPollutionReduction = 0; diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java index 24c057251e..00201171a8 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java @@ -209,10 +209,10 @@ import gregtech.api.multitileentity.machine.MultiTileBasicMachine; import gregtech.api.multitileentity.multiblock.casing.FunctionalCasing; import gregtech.api.multitileentity.multiblock.casing.UpgradeCasing; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.RecipeMap; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; -import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Waila; import gregtech.common.tileentities.casings.upgrade.Inventory; @@ -2184,7 +2184,7 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public GT_Recipe.GT_Recipe_Map getRecipeMap() { + public RecipeMap<?> getRecipeMap() { return null; } diff --git a/src/main/java/gregtech/api/objects/overclockdescriber/EUNoOverclockDescriber.java b/src/main/java/gregtech/api/objects/overclockdescriber/EUNoOverclockDescriber.java new file mode 100644 index 0000000000..1e29e2d812 --- /dev/null +++ b/src/main/java/gregtech/api/objects/overclockdescriber/EUNoOverclockDescriber.java @@ -0,0 +1,110 @@ +package gregtech.api.objects.overclockdescriber; + +import static gregtech.api.util.GT_Utility.trans; + +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class EUNoOverclockDescriber extends OverclockDescriber { + + /** + * Amperage of the recipemap. + */ + protected final int amperage; + + public EUNoOverclockDescriber(byte tier, int amperage) { + super(tier); + if (amperage < 1) { + throw new IllegalArgumentException("Amperage cannot be lower than 1"); + } + this.amperage = amperage; + } + + @Override + public GT_OverclockCalculator createCalculator(GT_OverclockCalculator template, GT_Recipe recipe) { + return GT_OverclockCalculator.ofNoOverclock(recipe); + } + + @Override + public String getTierString() { + return GT_Utility.getColoredTierNameFromTier(tier); + } + + @Override + public final void drawEnergyInfo(RecipeDisplayInfo recipeInfo) { + if (recipeInfo.calculator.getDuration() > 0 && recipeInfo.calculator.getConsumption() > 0) { + recipeInfo.drawText(trans("152", "Total: ") + getTotalPowerString(recipeInfo.calculator)); + } + drawEnergyInfoImpl(recipeInfo); + } + + /** + * Override this to draw custom info about the energy this object can handle on NEI recipe GUI, minus total + * power usage. + */ + protected void drawEnergyInfoImpl(RecipeDisplayInfo recipeInfo) { + if (recipeInfo.calculator.getConsumption() <= 0) { + return; + } + recipeInfo.drawText(trans("153", "Usage: ") + getEUtDisplay(recipeInfo.calculator)); + if (shouldShowAmperage(recipeInfo.calculator)) { + recipeInfo.drawText(trans("154", "Voltage: ") + getVoltageString(recipeInfo.calculator)); + recipeInfo.drawText(trans("155", "Amperage: ") + getAmperageString(recipeInfo.calculator)); + } + } + + protected String getTotalPowerString(GT_OverclockCalculator calculator) { + return GT_Utility.formatNumbers(calculator.getConsumption() * calculator.getDuration()) + " EU"; + } + + /** + * @return If amperage should be shown on NEI. + */ + protected boolean shouldShowAmperage(GT_OverclockCalculator calculator) { + return amperage != 1; + } + + /** + * @return Whole EU/t usage, without tier display. + */ + protected String getEUtWithoutTier(GT_OverclockCalculator calculator) { + return GT_Utility.formatNumbers(calculator.getConsumption()) + " EU/t"; + } + + /** + * @return Whole EU/t usage, with tier display. + */ + protected String getEUtWithTier(GT_OverclockCalculator calculator) { + return getEUtWithoutTier(calculator) + GT_Utility.getTierNameWithParentheses(calculator.getConsumption()); + } + + /** + * @return Whole EU/t usage. Also displays voltage tier if it should be shown. + */ + protected String getEUtDisplay(GT_OverclockCalculator calculator) { + return shouldShowAmperage(calculator) ? getEUtWithoutTier(calculator) : getEUtWithTier(calculator); + } + + /** + * @return EU/t usage, divided by amperage. With tier display. + */ + protected String getVoltageString(GT_OverclockCalculator calculator) { + long voltage = computeVoltageForEURate(calculator.getConsumption()); + return GT_Utility.formatNumbers(voltage) + " EU/t" + GT_Utility.getTierNameWithParentheses(voltage); + } + + protected String getAmperageString(GT_OverclockCalculator calculator) { + return GT_Utility.formatNumbers(amperage); + } + + protected long computeVoltageForEURate(long euPerTick) { + return euPerTick / amperage; + } +} diff --git a/src/main/java/gregtech/api/objects/overclockdescriber/EUOverclockDescriber.java b/src/main/java/gregtech/api/objects/overclockdescriber/EUOverclockDescriber.java new file mode 100644 index 0000000000..9d53711515 --- /dev/null +++ b/src/main/java/gregtech/api/objects/overclockdescriber/EUOverclockDescriber.java @@ -0,0 +1,80 @@ +package gregtech.api.objects.overclockdescriber; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.util.GT_Utility.trans; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.google.common.primitives.Ints; + +import gregtech.GT_Mod; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class EUOverclockDescriber extends EUNoOverclockDescriber { + + public EUOverclockDescriber(byte tier, int amperage) { + super(tier, amperage); + } + + @Override + public GT_OverclockCalculator createCalculator(GT_OverclockCalculator template, GT_Recipe recipe) { + return template.setEUt(Ints.saturatedCast(V[tier] * amperage)); + } + + @Override + protected void drawEnergyInfoImpl(RecipeDisplayInfo recipeInfo) { + if (!wasOverclocked(recipeInfo.calculator)) { + super.drawEnergyInfoImpl(recipeInfo); + return; + } + + recipeInfo.drawText(trans("153", "Usage: ") + getEUtDisplay(recipeInfo.calculator)); + if (shouldShowAmperage(recipeInfo.calculator)) { + recipeInfo.drawText(trans("154", "Voltage: ") + getVoltageString(recipeInfo.calculator)); + } + if (GT_Mod.gregtechproxy.mNEIOriginalVoltage) { + EUNoOverclockDescriber originalPower = new EUNoOverclockDescriber(tier, amperage); + GT_OverclockCalculator originalPowerCalculator = GT_OverclockCalculator.ofNoOverclock(recipeInfo.recipe) + .calculate(); + recipeInfo + .drawText(trans("275", "Original usage: ") + originalPower.getEUtDisplay(originalPowerCalculator)); + } + if (shouldShowAmperage(recipeInfo.calculator)) { + recipeInfo.drawText(trans("155", "Amperage: ") + getAmperageString(recipeInfo.calculator)); + } + } + + @Override + protected String getEUtWithoutTier(GT_OverclockCalculator calculator) { + return decorateWithOverclockLabel(super.getEUtWithoutTier(calculator), calculator); + } + + @Override + protected String getEUtWithTier(GT_OverclockCalculator calculator) { + return this.getEUtWithoutTier(calculator) + GT_Utility.getTierNameWithParentheses(calculator.getConsumption()); + } + + @Override + protected String getVoltageString(GT_OverclockCalculator calculator) { + long voltage = computeVoltageForEURate(calculator.getConsumption()); + return decorateWithOverclockLabel(GT_Utility.formatNumbers(voltage) + " EU/t", calculator) + + GT_Utility.getTierNameWithParentheses(voltage); + } + + protected String decorateWithOverclockLabel(String s, GT_OverclockCalculator calculator) { + if (wasOverclocked(calculator)) { + s += " (OC)"; + } + return s; + } + + protected boolean wasOverclocked(GT_OverclockCalculator calculator) { + return calculator.getPerformedOverclocks() > 0; + } +} diff --git a/src/main/java/gregtech/api/objects/overclockdescriber/FusionOverclockDescriber.java b/src/main/java/gregtech/api/objects/overclockdescriber/FusionOverclockDescriber.java new file mode 100644 index 0000000000..43ce1c8760 --- /dev/null +++ b/src/main/java/gregtech/api/objects/overclockdescriber/FusionOverclockDescriber.java @@ -0,0 +1,69 @@ +package gregtech.api.objects.overclockdescriber; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.util.EnumChatFormatting; + +import gregtech.api.enums.GT_Values; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class FusionOverclockDescriber extends EUOverclockDescriber { + + protected final long capableStartup; + + public FusionOverclockDescriber(byte energyTier, long capableStartup) { + super(energyTier, 1); + this.capableStartup = capableStartup; + } + + @Override + public GT_OverclockCalculator createCalculator(GT_OverclockCalculator template, GT_Recipe recipe) { + return super.createCalculator(template, recipe).limitOverclockCount(overclock(recipe.mSpecialValue)) + .setEUtIncreasePerOC(getEUtIncreasePerOC()) + .setDurationDecreasePerOC(getDurationDecreasePerOC()); + } + + protected int getEUtIncreasePerOC() { + return 1; + } + + protected int getDurationDecreasePerOC() { + return 1; + } + + @Override + public String getTierString() { + return GT_Values.TIER_COLORS[tier] + "MK " + getFusionTier() + EnumChatFormatting.RESET; + } + + @Override + public boolean canHandle(GT_Recipe recipe) { + byte tier = GT_Utility.getTier(recipe.mEUt); + if (this.tier < tier) { + return false; + } + return this.capableStartup >= recipe.mSpecialValue; + } + + protected int overclock(int startEnergy) { + return switch (getFusionTier()) { + case 1 -> 0; + case 2 -> (startEnergy <= 160000000) ? 1 : 0; + case 3 -> (startEnergy <= 160000000) ? 2 : ((startEnergy <= 320000000) ? 1 : 0); + case 4 -> (startEnergy <= 160000000) ? 3 + : (startEnergy <= 320000000) ? 2 : (startEnergy <= 640000000) ? 1 : 0; + case 5 -> (startEnergy <= 160000000) ? 4 + : (startEnergy <= 320000000) ? 3 : (startEnergy <= 640000000) ? 2 : (startEnergy <= 1280000000) ? 1 : 0; + default -> throw new IllegalStateException("Unexpected fusion tier: " + getFusionTier()); + }; + } + + protected int getFusionTier() { + return this.tier - 5; // Mk1 <-> LuV + } +} diff --git a/src/main/java/gregtech/api/objects/overclockdescriber/OverclockDescriber.java b/src/main/java/gregtech/api/objects/overclockdescriber/OverclockDescriber.java new file mode 100644 index 0000000000..0b253c95fa --- /dev/null +++ b/src/main/java/gregtech/api/objects/overclockdescriber/OverclockDescriber.java @@ -0,0 +1,106 @@ +package gregtech.api.objects.overclockdescriber; + +import static gregtech.api.util.GT_Utility.trans; + +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.GT_Mod; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +/** + * Provides an overclock behavior that will run on machines with the ability to draw information about it on NEI. + * <p> + * Implement {@link gregtech.api.interfaces.tileentity.IOverclockDescriptionProvider} for corresponding machine to use + * derivative of this class when looking up NEI recipe catalyst. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public abstract class OverclockDescriber { + + /** + * Tier of the (maybe virtual) machine this object belongs to. + */ + protected final byte tier; + + public OverclockDescriber(byte tier) { + this.tier = tier; + } + + /** + * @return Tier of this object. Used to limit recipes shown on NEI, based on recipe EU/t. + */ + public final byte getTier() { + return tier; + } + + /** + * @return Tier display of this object, shown on NEI header in a form of {@code Machine Name (tier)} + */ + public abstract String getTierString(); + + /** + * Creates overclock calculator from given template. This template should be used instead of building from the + * ground to avoid issues coming from different caller using different templates, but it's not applicable when using + * {@link GT_OverclockCalculator#ofNoOverclock(GT_Recipe)}. + * + * @param template Calculator that can be used as template. Recipe EU/t and duration are already set. + * @param recipe Recipe to calculate. + */ + public abstract GT_OverclockCalculator createCalculator(GT_OverclockCalculator template, GT_Recipe recipe); + + /** + * Draws info about the energy this object can handle on NEI recipe GUI. + */ + public abstract void drawEnergyInfo(RecipeDisplayInfo recipeInfo); + + public void drawDurationInfo(RecipeDisplayInfo recipeInfo) { + if (getDurationTicks(recipeInfo.calculator) <= 0) return; + + String textToDraw = trans("158", "Time: "); + if (GT_Mod.gregtechproxy.mNEIRecipeSecondMode) { + textToDraw += getDurationStringSeconds(recipeInfo.calculator); + if (getDurationSeconds(recipeInfo.calculator) <= 1.0d) { + textToDraw += String.format(" (%s)", getDurationStringTicks(recipeInfo.calculator)); + } + } else { + textToDraw += getDurationStringTicks(recipeInfo.calculator); + } + recipeInfo.drawText(textToDraw); + } + + /** + * Used to limit the shown recipes when searching recipes with NEI recipe catalyst. Unless overridden, this method + * doesn't do anything special (except for a bit worse performance). + * <p> + * In order to make use of this method, {@link gregtech.api.recipe.RecipeMapBuilder#useCustomFilterForNEI} + * should be enabled for the recipemap. + * + * @return If this object can handle the supplied recipe + */ + public boolean canHandle(GT_Recipe recipe) { + byte tier = GT_Utility.getTier(recipe.mEUt); + return this.tier >= tier; + } + + private int getDurationTicks(GT_OverclockCalculator calculator) { + return calculator.getDuration(); + } + + private double getDurationSeconds(GT_OverclockCalculator calculator) { + return 0.05d * getDurationTicks(calculator); + } + + private String getDurationStringSeconds(GT_OverclockCalculator calculator) { + return GT_Utility.formatNumbers(getDurationSeconds(calculator)) + GT_Utility.trans("161", " secs"); + } + + private String getDurationStringTicks(GT_OverclockCalculator calculator) { + String ticksString = getDurationTicks(calculator) == 1 ? GT_Utility.trans("209.1", " tick") + : GT_Utility.trans("209", " ticks"); + return GT_Utility.formatNumbers(getDurationTicks(calculator)) + ticksString; + } +} diff --git a/src/main/java/gregtech/api/objects/overclockdescriber/SteamOverclockDescriber.java b/src/main/java/gregtech/api/objects/overclockdescriber/SteamOverclockDescriber.java new file mode 100644 index 0000000000..5da64d4028 --- /dev/null +++ b/src/main/java/gregtech/api/objects/overclockdescriber/SteamOverclockDescriber.java @@ -0,0 +1,64 @@ +package gregtech.api.objects.overclockdescriber; + +import static gregtech.api.util.GT_Utility.trans; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.util.StatCollector; + +import gregtech.api.enums.SteamVariant; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class SteamOverclockDescriber extends OverclockDescriber { + + private final SteamVariant steamVariant; + private final int euPerTickMultiplier; + private final int durationMultiplier; + + public SteamOverclockDescriber(SteamVariant steamVariant, int euPerTickMultiplier, int durationMultiplier) { + super((byte) 1); // recipe tier is always LV + this.steamVariant = steamVariant; + this.euPerTickMultiplier = euPerTickMultiplier; + this.durationMultiplier = durationMultiplier; + } + + @Override + public String getTierString() { + return StatCollector.translateToLocal("GT5U.steam_variant." + steamVariant.toString()); + } + + @Override + public GT_OverclockCalculator createCalculator(GT_OverclockCalculator template, GT_Recipe recipe) { + return GT_OverclockCalculator.ofNoOverclock(recipe) + .setEUtDiscount(euPerTickMultiplier) + .setSpeedBoost(durationMultiplier); + } + + @Override + public void drawEnergyInfo(RecipeDisplayInfo recipeInfo) { + if (recipeInfo.calculator.getConsumption() <= 0) return; + + recipeInfo.drawText(trans("152", "Total: ") + getTotalPowerString(recipeInfo.calculator)); + recipeInfo.drawText(trans("153", "Usage: ") + getSteamUsageString(recipeInfo.calculator)); + } + + private String getTotalPowerString(GT_OverclockCalculator calculator) { + return GT_Utility.formatNumbers(convertEUToSteam(calculator.getConsumption() * calculator.getDuration())) + + " Steam"; + } + + private String getSteamUsageString(GT_OverclockCalculator calculator) { + return GT_Utility.formatNumbers(20 * convertEUToSteam(calculator.getConsumption())) + " L/s Steam"; + } + + private static long convertEUToSteam(long eu) { + // 2L normal steam == 1EU + return 2 * eu; + } +} diff --git a/src/main/java/gregtech/api/recipe/BasicUIProperties.java b/src/main/java/gregtech/api/recipe/BasicUIProperties.java new file mode 100644 index 0000000000..fde86785b2 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/BasicUIProperties.java @@ -0,0 +1,251 @@ +package gregtech.api.recipe; + +import java.awt.Rectangle; +import java.util.List; +import java.util.function.IntFunction; +import java.util.function.Supplier; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.apache.commons.lang3.tuple.Pair; + +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import gregtech.api.gui.modularui.FallbackableSteamTexture; +import gregtech.api.gui.modularui.SteamTexture; +import gregtech.api.util.FieldsAreNonnullByDefault; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Data object to store properties, used to draw both basic machine GUI and NEI recipe GUI, mainly GUI widgets. + * Not all the info used to draw NEI are listed here, see also {@link NEIRecipeProperties}. + * <p> + * Use {@link #builder()} for creation. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +public final class BasicUIProperties { + + /** + * Starts constructing BasicUIProperties. + */ + public static BasicUIPropertiesBuilder builder() { + return new BasicUIPropertiesBuilder(); + } + + /** + * Creates new builder from this instance. + */ + public BasicUIPropertiesBuilder toBuilder() { + return new BasicUIPropertiesBuilder().maxItemInputs(maxItemInputs) + .maxItemOutputs(maxItemOutputs) + .maxFluidInputs(maxFluidInputs) + .maxFluidOutputs(maxFluidOutputs) + .slotOverlays(slotOverlays) + .slotOverlaysSteam(slotOverlaysSteam) + .progressBarTexture(progressBarTexture) + .progressBarTextureSteam(progressBarTextureSteam) + .progressBarDirection(progressBarDirection) + .progressBarSize(progressBarSize) + .progressBarPos(progressBarPos) + .useProgressBar(useProgressBar) + .useSpecialSlot(useSpecialSlot) + .neiTransferRect(neiTransferRect) + .neiTransferRectId(neiTransferRectId) + .specialTextures(specialTextures) + .specialTexturesSteam(specialTexturesSteam) + .logo(logo) + .logoSize(logoSize) + .logoPos(logoPos) + .itemInputPositionsGetter(itemInputPositionsGetter) + .itemOutputPositionsGetter(itemOutputPositionsGetter) + .specialItemPositionGetter(specialItemPositionGetter) + .fluidInputPositionsGetter(fluidInputPositionsGetter) + .fluidOutputPositionsGetter(fluidOutputPositionsGetter) + .amperage(amperage); + } + + /** + * How many item inputs does this recipemap usually has at most. + * It does not actually restrict number of items used in the recipe. + */ + public final int maxItemInputs; + /** + * How many item outputs does this recipemap usually has at most. + * It does not actually restrict number of items used in the recipe. + */ + public final int maxItemOutputs; + /** + * How many fluid inputs does this recipemap usually has at most. + * It does not actually restrict number of items used in the recipe. + */ + public final int maxFluidInputs; + /** + * How many fluid outputs does this recipemap usually has at most. + * It does not actually restrict number of items used in the recipe. + */ + public final int maxFluidOutputs; + + private final SlotOverlayGetter<IDrawable> slotOverlays; + private final SlotOverlayGetter<SteamTexture> slotOverlaysSteam; + + /** + * Progressbar used for BasicMachine GUI and NEI. + */ + @Nullable + public final FallbackableUITexture progressBarTexture; + /** + * Progressbar used for steam machine GUI. + */ + @Nullable + public final FallbackableSteamTexture progressBarTextureSteam; + /** + * Direction of progressbar animation. + */ + public final ProgressBar.Direction progressBarDirection; + /** + * Size of the progressbar. (20, 36) by default. + */ + public final Size progressBarSize; + /** + * Position of the progressbar. (78, 24) by default. + */ + public final Pos2d progressBarPos; + /** + * Image size in the direction of progressbar. Used for non-smooth rendering. + */ + public final int progressBarImageSize; + + /** + * If progressbar should be added. + */ + public final boolean useProgressBar; + + /** + * If special slot has its usage for this GUI. + */ + public final boolean useSpecialSlot; + + /** + * GUI area where clicking shows up all the recipes available. + */ + public final List<Rectangle> neiTransferRect; + /** + * ID used to open NEI recipe GUI when progressbar is clicked. + */ + @Nullable + public final String neiTransferRectId; + + /** + * Additional textures shown on GUI. + */ + public final List<Pair<IDrawable, Pair<Size, Pos2d>>> specialTextures; + /** + * Additional textures shown on steam machine GUI. + */ + public final List<Pair<SteamTexture, Pair<Size, Pos2d>>> specialTexturesSteam; + + /** + * Logo shown on GUI. GregTech logo by default. + */ + public final IDrawable logo; + /** + * Size of logo. (17, 17) by default. + */ + public final Size logoSize; + /** + * Position of logo. (152, 63) by default. + */ + public final Pos2d logoPos; + + public final IntFunction<List<Pos2d>> itemInputPositionsGetter; + public final IntFunction<List<Pos2d>> itemOutputPositionsGetter; + public final Supplier<Pos2d> specialItemPositionGetter; + public final IntFunction<List<Pos2d>> fluidInputPositionsGetter; + public final IntFunction<List<Pos2d>> fluidOutputPositionsGetter; + + /** + * Amperage for the recipemap. Even though this is placed at frontend because backend logic doesn't need it, + * some machine logic also use this variable. + */ + public final int amperage; + + BasicUIProperties(int maxItemInputs, int maxItemOutputs, int maxFluidInputs, int maxFluidOutputs, + SlotOverlayGetter<IDrawable> slotOverlays, SlotOverlayGetter<SteamTexture> slotOverlaysSteam, + @Nullable FallbackableUITexture progressBarTexture, @Nullable FallbackableSteamTexture progressBarTextureSteam, + ProgressBar.Direction progressBarDirection, Size progressBarSize, Pos2d progressBarPos, boolean useProgressBar, + boolean useSpecialSlot, List<Rectangle> neiTransferRect, @Nullable String neiTransferRectId, + List<Pair<IDrawable, Pair<Size, Pos2d>>> specialTextures, + List<Pair<SteamTexture, Pair<Size, Pos2d>>> specialTexturesSteam, IDrawable logo, Size logoSize, Pos2d logoPos, + IntFunction<List<Pos2d>> itemInputPositionsGetter, IntFunction<List<Pos2d>> itemOutputPositionsGetter, + Supplier<Pos2d> specialItemPositionGetter, IntFunction<List<Pos2d>> fluidInputPositionsGetter, + IntFunction<List<Pos2d>> fluidOutputPositionsGetter, int amperage) { + if (maxItemInputs < 0 || maxItemOutputs < 0 || maxFluidInputs < 0 || maxFluidOutputs < 0) { + throw new IllegalArgumentException( + "maxItemInputs, maxItemOutputs, maxFluidInputs and maxFluidOutputs cannot be negative"); + } + if (amperage < 1) { + throw new IllegalArgumentException("Amperage cannot be lower than 1"); + } + this.maxItemInputs = maxItemInputs; + this.maxItemOutputs = maxItemOutputs; + this.maxFluidInputs = maxFluidInputs; + this.maxFluidOutputs = maxFluidOutputs; + this.slotOverlays = slotOverlays; + this.slotOverlaysSteam = slotOverlaysSteam; + this.progressBarTexture = progressBarTexture; + this.progressBarTextureSteam = progressBarTextureSteam; + this.progressBarDirection = progressBarDirection; + this.progressBarSize = progressBarSize; + this.progressBarPos = progressBarPos; + this.useProgressBar = useProgressBar; + this.useSpecialSlot = useSpecialSlot; + this.neiTransferRect = neiTransferRect; + this.neiTransferRectId = neiTransferRectId; + this.specialTextures = specialTextures; + this.specialTexturesSteam = specialTexturesSteam; + this.logo = logo; + this.logoSize = logoSize; + this.logoPos = logoPos; + this.itemInputPositionsGetter = itemInputPositionsGetter; + this.itemOutputPositionsGetter = itemOutputPositionsGetter; + this.specialItemPositionGetter = specialItemPositionGetter; + this.fluidInputPositionsGetter = fluidInputPositionsGetter; + this.fluidOutputPositionsGetter = fluidOutputPositionsGetter; + this.amperage = amperage; + + this.progressBarImageSize = switch (progressBarDirection) { + case UP, DOWN -> progressBarSize.height; + case CIRCULAR_CW -> Math.max(progressBarSize.width, progressBarSize.height); + default -> progressBarSize.width; + }; + } + + /** + * Retrieves overlay for slot, with given matching conditions. + */ + @Nullable + public IDrawable getOverlayForSlot(int index, boolean isFluid, boolean isOutput, boolean isSpecial) { + return slotOverlays.apply(index, isFluid, isOutput, isSpecial); + } + + /** + * Retrieves overlay for slot of steam machines, with given matching conditions. + */ + @Nullable + public SteamTexture getOverlayForSlotSteam(int index, boolean isFluid, boolean isOutput, boolean isSpecial) { + return slotOverlaysSteam.apply(index, isFluid, isOutput, isSpecial); + } + + public interface SlotOverlayGetter<T> { + + @Nullable + T apply(int index, boolean isFluid, boolean isOutput, boolean isSpecial); + } +} diff --git a/src/main/java/gregtech/api/recipe/BasicUIPropertiesBuilder.java b/src/main/java/gregtech/api/recipe/BasicUIPropertiesBuilder.java new file mode 100644 index 0000000000..7be2c94b23 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/BasicUIPropertiesBuilder.java @@ -0,0 +1,264 @@ +package gregtech.api.recipe; + +import java.awt.Rectangle; +import java.util.Collections; +import java.util.List; +import java.util.function.IntFunction; +import java.util.function.Supplier; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import gregtech.api.gui.modularui.FallbackableSteamTexture; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.modularui.SteamTexture; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; + +/** + * Builder class for {@link BasicUIProperties}. + */ +@SuppressWarnings("UnusedReturnValue") +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public final class BasicUIPropertiesBuilder { + + private int maxItemInputs, maxItemOutputs, maxFluidInputs, maxFluidOutputs; + + private BasicUIProperties.SlotOverlayGetter<IDrawable> slotOverlays = (index, isFluid, isOutput, isSpecial) -> null; + private BasicUIProperties.SlotOverlayGetter<SteamTexture> slotOverlaysSteam = (index, isFluid, isOutput, + isSpecial) -> null; + + @Nullable + private FallbackableUITexture progressBarTexture; + @Nullable + private FallbackableSteamTexture progressBarTextureSteam; + private ProgressBar.Direction progressBarDirection = ProgressBar.Direction.RIGHT; + private Size progressBarSize = new Size(20, 18); + private Pos2d progressBarPos = new Pos2d(78, 24); + + private boolean useProgressBar = true; + + private boolean useSpecialSlot; + + private final ImmutableList.Builder<Rectangle> neiTransferRect = ImmutableList.builder(); + @Nullable + private String neiTransferRectId; + + private final ImmutableList.Builder<Pair<IDrawable, Pair<Size, Pos2d>>> specialTextures = ImmutableList.builder(); + private final ImmutableList.Builder<Pair<SteamTexture, Pair<Size, Pos2d>>> specialTexturesSteam = ImmutableList + .builder(); + + private IDrawable logo = GT_UITextures.PICTURE_GT_LOGO_17x17_TRANSPARENT; + private Size logoSize = new Size(17, 17); + private Pos2d logoPos = new Pos2d(152, 63); + + private IntFunction<List<Pos2d>> itemInputPositionsGetter = UIHelper::getItemInputPositions; + private IntFunction<List<Pos2d>> itemOutputPositionsGetter = UIHelper::getItemOutputPositions; + private Supplier<Pos2d> specialItemPositionGetter = UIHelper::getSpecialItemPosition; + private IntFunction<List<Pos2d>> fluidInputPositionsGetter = UIHelper::getFluidInputPositions; + private IntFunction<List<Pos2d>> fluidOutputPositionsGetter = UIHelper::getFluidOutputPositions; + + private int amperage = 1; + + BasicUIPropertiesBuilder() {} + + public BasicUIProperties build() { + if (maxItemInputs == 0 && maxItemOutputs == 0 && maxFluidInputs == 0 && maxFluidOutputs == 0) { + throw new IllegalArgumentException("Set either of max I/O count"); + } + List<Rectangle> builtNEITransferRect = neiTransferRect.build(); + if (builtNEITransferRect.isEmpty()) { + builtNEITransferRect = Collections.singletonList( + new Rectangle( + progressBarPos.x - (16 / 2), + progressBarPos.y, + progressBarSize.width + 16, + progressBarSize.height)); + } + return new BasicUIProperties( + maxItemInputs, + maxItemOutputs, + maxFluidInputs, + maxFluidOutputs, + slotOverlays, + slotOverlaysSteam, + progressBarTexture, + progressBarTextureSteam, + progressBarDirection, + progressBarSize, + progressBarPos, + useProgressBar, + useSpecialSlot, + builtNEITransferRect, + neiTransferRectId, + specialTextures.build(), + specialTexturesSteam.build(), + logo, + logoSize, + logoPos, + itemInputPositionsGetter, + itemOutputPositionsGetter, + specialItemPositionGetter, + fluidInputPositionsGetter, + fluidOutputPositionsGetter, + amperage); + } + + public BasicUIPropertiesBuilder maxItemInputs(int maxItemInputs) { + this.maxItemInputs = maxItemInputs; + return this; + } + + public BasicUIPropertiesBuilder maxItemOutputs(int maxItemOutputs) { + this.maxItemOutputs = maxItemOutputs; + return this; + } + + public BasicUIPropertiesBuilder maxFluidInputs(int maxFluidInputs) { + this.maxFluidInputs = maxFluidInputs; + return this; + } + + public BasicUIPropertiesBuilder maxFluidOutputs(int maxFluidOutputs) { + this.maxFluidOutputs = maxFluidOutputs; + return this; + } + + public BasicUIPropertiesBuilder slotOverlays(BasicUIProperties.SlotOverlayGetter<IDrawable> slotOverlays) { + this.slotOverlays = slotOverlays; + return this; + } + + public BasicUIPropertiesBuilder slotOverlaysSteam( + BasicUIProperties.SlotOverlayGetter<SteamTexture> slotOverlaysSteam) { + this.slotOverlaysSteam = slotOverlaysSteam; + return this; + } + + public BasicUIPropertiesBuilder progressBarTexture(@Nullable FallbackableUITexture progressBarTexture) { + this.progressBarTexture = progressBarTexture; + return this; + } + + public BasicUIPropertiesBuilder progressBarTextureSteam( + @Nullable FallbackableSteamTexture progressBarTextureSteam) { + this.progressBarTextureSteam = progressBarTextureSteam; + return this; + } + + public BasicUIPropertiesBuilder progressBarDirection(ProgressBar.Direction progressBarDirection) { + this.progressBarDirection = progressBarDirection; + return this; + } + + public BasicUIPropertiesBuilder progressBarSize(Size progressBarSize) { + this.progressBarSize = progressBarSize; + return this; + } + + public BasicUIPropertiesBuilder progressBarPos(Pos2d progressBarPos) { + this.progressBarPos = progressBarPos; + return this; + } + + public BasicUIPropertiesBuilder useProgressBar(boolean useProgressBar) { + this.useProgressBar = useProgressBar; + return this; + } + + public BasicUIPropertiesBuilder useSpecialSlot(boolean useSpecialSlot) { + this.useSpecialSlot = useSpecialSlot; + return this; + } + + public BasicUIPropertiesBuilder addNEITransferRect(Rectangle neiTransferRect) { + this.neiTransferRect.add(neiTransferRect); + return this; + } + + BasicUIPropertiesBuilder neiTransferRect(List<Rectangle> neiTransferRect) { + this.neiTransferRect.addAll(neiTransferRect); + return this; + } + + public BasicUIPropertiesBuilder neiTransferRectId(@Nullable String neiTransferRectId) { + this.neiTransferRectId = neiTransferRectId; + return this; + } + + public BasicUIPropertiesBuilder addSpecialTexture(Size size, Pos2d pos, IDrawable texture) { + this.specialTextures.add(new ImmutablePair<>(texture, new ImmutablePair<>(size, pos))); + return this; + } + + BasicUIPropertiesBuilder specialTextures(List<Pair<IDrawable, Pair<Size, Pos2d>>> specialTextures) { + this.specialTextures.addAll(specialTextures); + return this; + } + + public BasicUIPropertiesBuilder addSpecialTextureSteam(Size size, Pos2d pos, SteamTexture texture) { + this.specialTexturesSteam.add(new ImmutablePair<>(texture, new ImmutablePair<>(size, pos))); + return this; + } + + BasicUIPropertiesBuilder specialTexturesSteam(List<Pair<SteamTexture, Pair<Size, Pos2d>>> specialTextures) { + this.specialTexturesSteam.addAll(specialTextures); + return this; + } + + public BasicUIPropertiesBuilder logo(IDrawable logo) { + this.logo = logo; + return this; + } + + public BasicUIPropertiesBuilder logoSize(Size logoSize) { + this.logoSize = logoSize; + return this; + } + + public BasicUIPropertiesBuilder logoPos(Pos2d logoPos) { + this.logoPos = logoPos; + return this; + } + + public BasicUIPropertiesBuilder itemInputPositionsGetter(IntFunction<List<Pos2d>> itemInputPositionsGetter) { + this.itemInputPositionsGetter = itemInputPositionsGetter; + return this; + } + + public BasicUIPropertiesBuilder itemOutputPositionsGetter(IntFunction<List<Pos2d>> itemOutputPositionsGetter) { + this.itemOutputPositionsGetter = itemOutputPositionsGetter; + return this; + } + + public BasicUIPropertiesBuilder specialItemPositionGetter(Supplier<Pos2d> specialItemPositionGetter) { + this.specialItemPositionGetter = specialItemPositionGetter; + return this; + } + + public BasicUIPropertiesBuilder fluidInputPositionsGetter(IntFunction<List<Pos2d>> fluidInputPositionsGetter) { + this.fluidInputPositionsGetter = fluidInputPositionsGetter; + return this; + } + + public BasicUIPropertiesBuilder fluidOutputPositionsGetter(IntFunction<List<Pos2d>> fluidOutputPositionsGetter) { + this.fluidOutputPositionsGetter = fluidOutputPositionsGetter; + return this; + } + + public BasicUIPropertiesBuilder amperage(int amperage) { + this.amperage = amperage; + return this; + } +} diff --git a/src/main/java/gregtech/api/recipe/FindRecipeQuery.java b/src/main/java/gregtech/api/recipe/FindRecipeQuery.java new file mode 100644 index 0000000000..77c0648688 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/FindRecipeQuery.java @@ -0,0 +1,178 @@ +package gregtech.api.recipe; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +// spotless:off spotless likes formatting @code to @code +/** + * Helper class for searching recipe. Retrieve instance with {@link RecipeMap#findRecipeQuery}. + * <p> + * It features fluent API, so you can find recipes like this: + * + * <pre> + * {@code + * GT_Recipe recipe = recipeMap.findRecipeQuery() + * .items(inputItems) + * .fluids(inputFluids) + * .find(); + * } + * </pre> + */ +// spotless:on +@SuppressWarnings("unused") +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public final class FindRecipeQuery { + + private static final Predicate<GT_Recipe> ALWAYS = r -> true; + + private final RecipeMap<?> recipeMap; + + @Nullable + private ItemStack[] items; + @Nullable + private FluidStack[] fluids; + @Nullable + private ItemStack specialSlot; + private Predicate<GT_Recipe> filter = ALWAYS; + private long voltage = Integer.MAX_VALUE; + @Nullable + private GT_Recipe cachedRecipe; + private boolean notUnificated; + private boolean dontCheckStackSizes; + private boolean forCollisionCheck; + + FindRecipeQuery(RecipeMap<?> recipeMap) { + this.recipeMap = recipeMap; + } + + // region executors + + /** + * @return The first matched recipe, or null if not found. + */ + @Nullable + public GT_Recipe find() { + return findAll().findFirst() + .orElse(null); + } + + /** + * @return All the matched recipes in the form of Stream. + */ + public Stream<GT_Recipe> findAll() { + if (items == null) { + items = new ItemStack[0]; + } + if (fluids == null) { + fluids = new FluidStack[0]; + } + + return recipeMap.getBackend() + .matchRecipeStream( + items, + fluids, + specialSlot, + cachedRecipe, + notUnificated, + dontCheckStackSizes, + forCollisionCheck) + .filter(recipe -> voltage * recipeMap.getAmperage() >= recipe.mEUt && filter.test(recipe)); + } + + /** + * Checks if given inputs conflict with already registered recipes. + * + * @return True if collision is found. + */ + public boolean checkCollision() { + dontCheckStackSizes = true; + forCollisionCheck = true; + return findAll().findAny() + .isPresent(); + } + + // endregion + + // region setters + + /** + * @param items Item inputs. + */ + public FindRecipeQuery items(@Nullable ItemStack... items) { + this.items = items; + return this; + } + + /** + * @param fluids Fluid inputs. + */ + public FindRecipeQuery fluids(@Nullable FluidStack... fluids) { + this.fluids = fluids; + return this; + } + + /** + * @param specialSlot Content of the special slot. Normal recipemaps don't need this, but some do. + * Set {@link RecipeMapBuilder#specialSlotSensitive} to make it actually functional. + * Alternatively overriding {@link RecipeMapBackend#filterFindRecipe} will also work. + */ + public FindRecipeQuery specialSlot(@Nullable ItemStack specialSlot) { + this.specialSlot = specialSlot; + return this; + } + + /** + * @param filter Matched recipe will be tested by this function. If it returns false, the query will attempt to + * find next recipe. + */ + public FindRecipeQuery filter(Predicate<GT_Recipe> filter) { + this.filter = filter; + return this; + } + + /** + * @param voltage Recipes that exceed this voltage won't match. It will be automatically multiplied by amperage + * of the recipemap. + */ + public FindRecipeQuery voltage(long voltage) { + this.voltage = voltage; + return this; + } + + /** + * @param cachedRecipe If this is not null, the query tests it before all other recipes. + */ + public FindRecipeQuery cachedRecipe(@Nullable GT_Recipe cachedRecipe) { + this.cachedRecipe = cachedRecipe; + return this; + } + + /** + * @param notUnificated If this is set to true, item inputs will be unificated. + */ + public FindRecipeQuery notUnificated(boolean notUnificated) { + this.notUnificated = notUnificated; + return this; + } + + /** + * @param dontCheckStackSizes If this is set to true, the query won't check item count and fluid amount + * for the matched recipe. + */ + public FindRecipeQuery dontCheckStackSizes(boolean dontCheckStackSizes) { + this.dontCheckStackSizes = dontCheckStackSizes; + return this; + } + + // endregion +} diff --git a/src/main/java/gregtech/api/recipe/NEIRecipeProperties.java b/src/main/java/gregtech/api/recipe/NEIRecipeProperties.java new file mode 100644 index 0000000000..2ba49f5da1 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/NEIRecipeProperties.java @@ -0,0 +1,89 @@ +package gregtech.api.recipe; + +import java.util.Comparator; +import java.util.function.UnaryOperator; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; + +import codechicken.nei.recipe.HandlerInfo; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.util.FieldsAreNonnullByDefault; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.formatter.INEISpecialInfoFormatter; + +/** + * Data object storing info exclusively used to draw NEI recipe GUI. Not all the properties used to draw NEI + * are present here. See {@link BasicUIProperties} for the rest. + * <p> + * Use {@link #builder} for creation. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +public final class NEIRecipeProperties { + + static NEIRecipePropertiesBuilder builder() { + return new NEIRecipePropertiesBuilder(); + } + + /** + * Whether to register dedicated NEI recipe page for the recipemap. + */ + public final boolean registerNEI; + @Nullable + public final UnaryOperator<HandlerInfo.Builder> handlerInfoCreator; + + /** + * Size of background shown. + */ + // todo make it final + public Size recipeBackgroundSize; + /** + * Offset of background shown. + */ + public final Pos2d recipeBackgroundOffset; + + /** + * Formats special description for the recipe, mainly {@link gregtech.api.util.GT_Recipe#mSpecialValue}. + */ + public final INEISpecialInfoFormatter neiSpecialInfoFormatter; + + /** + * Whether to show oredict equivalent item outputs. + */ + public final boolean unificateOutput; + /** + * If a custom filter method {@link OverclockDescriber#canHandle} should be used to limit the shown recipes when + * searching recipes with recipe catalyst. Else, the voltage of the recipe is the only factor to filter recipes. + */ + public final boolean useCustomFilter; + /** + * Whether to render the actual stack size of items or not. + */ + public final boolean renderRealStackSizes; + + /** + * Comparator for NEI recipe sort. {@link GT_Recipe#compareTo(GT_Recipe)} by default. + */ + public final Comparator<GT_Recipe> comparator; + + NEIRecipeProperties(boolean registerNEI, @Nullable UnaryOperator<HandlerInfo.Builder> handlerInfoCreator, + Size recipeBackgroundSize, Pos2d recipeBackgroundOffset, INEISpecialInfoFormatter neiSpecialInfoFormatter, + boolean unificateOutput, boolean useCustomFilter, boolean renderRealStackSizes, + Comparator<GT_Recipe> comparator) { + this.registerNEI = registerNEI; + this.handlerInfoCreator = handlerInfoCreator; + this.recipeBackgroundOffset = recipeBackgroundOffset; + this.recipeBackgroundSize = recipeBackgroundSize; + this.neiSpecialInfoFormatter = neiSpecialInfoFormatter; + this.unificateOutput = unificateOutput; + this.useCustomFilter = useCustomFilter; + this.renderRealStackSizes = renderRealStackSizes; + this.comparator = comparator; + } +} diff --git a/src/main/java/gregtech/api/recipe/NEIRecipePropertiesBuilder.java b/src/main/java/gregtech/api/recipe/NEIRecipePropertiesBuilder.java new file mode 100644 index 0000000000..050a1c4920 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/NEIRecipePropertiesBuilder.java @@ -0,0 +1,100 @@ +package gregtech.api.recipe; + +import java.util.Comparator; +import java.util.function.UnaryOperator; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; + +import codechicken.nei.recipe.HandlerInfo; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.formatter.DefaultSpecialValueFormatter; +import gregtech.nei.formatter.INEISpecialInfoFormatter; + +/** + * Builder class for {@link NEIRecipeProperties}. + */ +@SuppressWarnings("UnusedReturnValue") +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public final class NEIRecipePropertiesBuilder { + + private boolean registerNEI = true; + @Nullable + private UnaryOperator<HandlerInfo.Builder> handlerInfoCreator; + + private Size recipeBackgroundSize = new Size(170, 82); + private Pos2d recipeBackgroundOffset = new Pos2d(3, 3); + + private INEISpecialInfoFormatter neiSpecialInfoFormatter = DefaultSpecialValueFormatter.INSTANCE; + + private boolean unificateOutput = true; + private boolean useCustomFilter; + private boolean renderRealStackSizes = true; + + private Comparator<GT_Recipe> comparator = GT_Recipe::compareTo; + + NEIRecipePropertiesBuilder() {} + + public NEIRecipeProperties build() { + return new NEIRecipeProperties( + registerNEI, + handlerInfoCreator, + recipeBackgroundSize, + recipeBackgroundOffset, + neiSpecialInfoFormatter, + unificateOutput, + useCustomFilter, + renderRealStackSizes, + comparator); + } + + public NEIRecipePropertiesBuilder disableRegisterNEI() { + this.registerNEI = false; + return this; + } + + public NEIRecipePropertiesBuilder handlerInfoCreator(UnaryOperator<HandlerInfo.Builder> builderCreator) { + this.handlerInfoCreator = builderCreator; + return this; + } + + public NEIRecipePropertiesBuilder recipeBackgroundSize(Size recipeBackgroundSize) { + this.recipeBackgroundSize = recipeBackgroundSize; + return this; + } + + public NEIRecipePropertiesBuilder recipeBackgroundOffset(Pos2d recipeBackgroundOffset) { + this.recipeBackgroundOffset = recipeBackgroundOffset; + return this; + } + + public NEIRecipePropertiesBuilder neiSpecialInfoFormatter(INEISpecialInfoFormatter neiSpecialInfoFormatter) { + this.neiSpecialInfoFormatter = neiSpecialInfoFormatter; + return this; + } + + public NEIRecipePropertiesBuilder unificateOutput(boolean unificateOutput) { + this.unificateOutput = unificateOutput; + return this; + } + + public NEIRecipePropertiesBuilder useCustomFilter() { + this.useCustomFilter = true; + return this; + } + + public NEIRecipePropertiesBuilder disableRenderRealStackSizes() { + this.renderRealStackSizes = false; + return this; + } + + public NEIRecipePropertiesBuilder recipeComparator(Comparator<GT_Recipe> comparator) { + this.comparator = comparator; + return this; + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeCategories.java b/src/main/java/gregtech/api/recipe/RecipeCategories.java new file mode 100644 index 0000000000..c2de890793 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeCategories.java @@ -0,0 +1,56 @@ +package gregtech.api.recipe; + +import static gregtech.api.enums.Mods.GregTech; +import static gregtech.api.recipe.RecipeCategory.createIcon; + +public final class RecipeCategories { + + @RecipeCategoryHolder + public static final RecipeCategory arcFurnaceRecycling = new RecipeCategory( + "gt.recipe.category.arc_furnace_recycling", + RecipeMaps.arcFurnaceRecipes, + builder -> builder.setDisplayImage( + createIcon(GregTech.getResourcePath("textures", "gui", "picture", "arc_furnace_recycling.png")))); + + @RecipeCategoryHolder + public static final RecipeCategory plasmaArcFurnaceRecycling = new RecipeCategory( + "gt.recipe.category.plasma_arc_furnace_recycling", + RecipeMaps.plasmaArcFurnaceRecipes, + builder -> builder.setDisplayImage( + createIcon(GregTech.getResourcePath("textures", "gui", "picture", "plasma_arc_furnace_recycling.png")))); + + @RecipeCategoryHolder + public static final RecipeCategory maceratorRecycling = new RecipeCategory( + "gt.recipe.category.macerator_recycling", + RecipeMaps.maceratorRecipes, + builder -> builder.setDisplayImage( + createIcon(GregTech.getResourcePath("textures", "gui", "picture", "macerator_recycling.png")))); + + @RecipeCategoryHolder + public static final RecipeCategory fluidExtractorRecycling = new RecipeCategory( + "gt.recipe.category.fluid_extractor_recycling", + RecipeMaps.fluidExtractionRecipes, + builder -> builder.setDisplayImage( + createIcon(GregTech.getResourcePath("textures", "gui", "picture", "fluid_extractor_recycling.png")))); + + @RecipeCategoryHolder + public static final RecipeCategory alloySmelterRecycling = new RecipeCategory( + "gt.recipe.category.alloy_smelter_recycling", + RecipeMaps.alloySmelterRecipes, + builder -> builder.setDisplayImage( + createIcon(GregTech.getResourcePath("textures", "gui", "picture", "alloy_smelter_recycling.png")))); + + @RecipeCategoryHolder + public static final RecipeCategory alloySmelterMolding = new RecipeCategory( + "gt.recipe.category.alloy_smelter_molding", + RecipeMaps.alloySmelterRecipes, + builder -> builder.setDisplayImage( + createIcon(GregTech.getResourcePath("textures", "gui", "picture", "alloy_smelter_molding.png")))); + + @RecipeCategoryHolder + public static final RecipeCategory forgeHammerRecycling = new RecipeCategory( + "gt.recipe.category.forge_hammer_recycling", + RecipeMaps.hammerRecipes, + builder -> builder.setDisplayImage( + createIcon(GregTech.getResourcePath("textures", "gui", "picture", "forge_hammer_recycling.png")))); +} diff --git a/src/main/java/gregtech/api/recipe/RecipeCategory.java b/src/main/java/gregtech/api/recipe/RecipeCategory.java new file mode 100644 index 0000000000..d7729ac493 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeCategory.java @@ -0,0 +1,81 @@ +package gregtech.api.recipe; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.UnaryOperator; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import codechicken.nei.drawable.DrawableBuilder; +import codechicken.nei.drawable.DrawableResource; +import codechicken.nei.recipe.HandlerInfo; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import gregtech.api.util.FieldsAreNonnullByDefault; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Used to display recipes on NEI on different tabs. + * <p> + * Also apply {@link RecipeCategoryHolder} annotation to each instance to be picked up by GT config. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +public final class RecipeCategory { + + public static final Map<String, RecipeCategory> ALL_RECIPE_CATEGORIES = new HashMap<>(); + + public final String unlocalizedName; + public final RecipeMap<?> recipeMap; + public final ModContainer ownerMod; + @Nullable + public final UnaryOperator<HandlerInfo.Builder> handlerInfoCreator; + + /** + * @param unlocalizedName Unlocalized name of this category. Must be unique. + * @param recipeMap RecipeMap this category belongs to. + * @param handlerInfoCreator Supplier of handler info for the NEI handler this category belongs to. + */ + public RecipeCategory(String unlocalizedName, RecipeMap<?> recipeMap, + @Nullable UnaryOperator<HandlerInfo.Builder> handlerInfoCreator) { + this.unlocalizedName = unlocalizedName; + this.recipeMap = recipeMap; + this.ownerMod = Loader.instance() + .activeModContainer(); + this.handlerInfoCreator = handlerInfoCreator; + if (ALL_RECIPE_CATEGORIES.containsKey(unlocalizedName)) { + throw new IllegalArgumentException( + "Cannot register recipe category with duplicated unlocalized name: " + unlocalizedName); + } + ALL_RECIPE_CATEGORIES.put(unlocalizedName, this); + } + + RecipeCategory(RecipeMap<?> recipeMap) { + this(recipeMap.unlocalizedName, recipeMap, recipeMap.getFrontend().neiProperties.handlerInfoCreator); + } + + @Override + public String toString() { + return "RecipeCategory{" + "unlocalizedName='" + + unlocalizedName + + '\'' + + ", recipeMap=" + + recipeMap.unlocalizedName + + ", ownerMod=" + + ownerMod.getModId() + + '}'; + } + + /** + * Creates icon for recipe category. Size is 16px. + */ + public static DrawableResource createIcon(String resourceLocation) { + return new DrawableBuilder(resourceLocation, 0, 0, 16, 16) + // GuiRecipeTab#drawForeground draws icon with 1px offset to make fuel icon (14px) prettier + .addPadding(-1, 0, -1, 0) + .setTextureSize(16, 16) + .build(); + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeCategoryHolder.java b/src/main/java/gregtech/api/recipe/RecipeCategoryHolder.java new file mode 100644 index 0000000000..0ad87e3f6f --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeCategoryHolder.java @@ -0,0 +1,13 @@ +package gregtech.api.recipe; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Apply this annotation to each recipe category so that GT config will pick it up. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface RecipeCategoryHolder {} diff --git a/src/main/java/gregtech/api/recipe/RecipeCategorySetting.java b/src/main/java/gregtech/api/recipe/RecipeCategorySetting.java new file mode 100644 index 0000000000..4920d64212 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeCategorySetting.java @@ -0,0 +1,52 @@ +package gregtech.api.recipe; + +import java.util.Locale; +import java.util.stream.Stream; + +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Specifies behaviors for {@link RecipeCategory}. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public enum RecipeCategorySetting { + + /** + * Show the category in separated NEI tab. + */ + ENABLE, + /** + * The category is merged to default one for the recipemap. + */ + MERGE, + /** + * Recipes belonging to the category are hidden from NEI. + */ + HIDE; + + public static final RecipeCategorySetting[] VALUES = values(); + public static final String[] NAMES = Stream.of(VALUES) + .map(RecipeCategorySetting::toName) + .toArray(String[]::new); + + public static RecipeCategorySetting getDefault() { + return ENABLE; + } + + public String toName() { + return toString().toLowerCase(Locale.ENGLISH); + } + + public static RecipeCategorySetting find(String name) { + for (RecipeCategorySetting setting : VALUES) { + if (setting.toName() + .equals(name)) { + return setting; + } + } + return getDefault(); + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMap.java b/src/main/java/gregtech/api/recipe/RecipeMap.java new file mode 100644 index 0000000000..2ee2d3cb94 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMap.java @@ -0,0 +1,395 @@ +package gregtech.api.recipe; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.Unmodifiable; + +import gregtech.api.interfaces.IRecipeMap; +import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; +import gregtech.api.util.FieldsAreNonnullByDefault; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Manages list of recipes. Its functionalities are split + * between {@link RecipeMapBackend} and {@link RecipeMapFrontend}. + * + * @param <B> Type of {@link RecipeMapBackend} + */ +@SuppressWarnings({ "unused", "UnusedReturnValue" }) +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +public final class RecipeMap<B extends RecipeMapBackend> implements IRecipeMap { + + /** + * All the recipemap instances. key=unlocalized name, value=instance. + */ + public static final Map<String, RecipeMap<?>> ALL_RECIPE_MAPS = new HashMap<>(); + + private final B backend; + private final RecipeMapFrontend frontend; + + /** + * Unique unlocalized name of this recipemap. Used for identifier, localization key for NEI tab name, etc. + */ + public final String unlocalizedName; + + private final RecipeCategory defaultRecipeCategory; + + /** + * Use {@link RecipeMapBuilder} to instantiate. + */ + RecipeMap(String unlocalizedName, B backend, RecipeMapFrontend frontend) { + this.unlocalizedName = unlocalizedName; + this.backend = backend; + this.frontend = frontend; + this.defaultRecipeCategory = new RecipeCategory(this); + backend.setRecipeMap(this); + if (ALL_RECIPE_MAPS.containsKey(unlocalizedName)) { + throw new IllegalArgumentException( + "Cannot register recipemap with duplicated unlocalized name: " + unlocalizedName); + } + ALL_RECIPE_MAPS.put(unlocalizedName, this); + } + + public B getBackend() { + return backend; + } + + public RecipeMapFrontend getFrontend() { + return frontend; + } + + /** + * @return All the recipes belonging to this recipemap. + */ + @Unmodifiable + public Collection<GT_Recipe> getAllRecipes() { + return backend.getAllRecipes(); + } + + /** + * @return List of registered recipe categories associated with this recipemap. + */ + public List<RecipeCategory> getAssociatedCategories() { + return RecipeCategory.ALL_RECIPE_CATEGORIES.values() + .stream() + .filter(category -> category.recipeMap == this) + .collect(Collectors.toList()); + } + + public RecipeCategory getDefaultRecipeCategory() { + return defaultRecipeCategory; + } + + /** + * @return Amperage of this recipemap. Note that recipes store EU/t with amperage included, + * e.g. Arc Furnace recipe with 90 EU/t means 30 EU/t (LV) with 3 amperage. + */ + public int getAmperage() { + return frontend.getUIProperties().amperage; + } + + @Override + public void addDownstream(IRecipeMap downstream) { + backend.addDownstream(downstream); + } + + // region add recipe + + @Nullable + public GT_Recipe addRecipe(boolean aOptimize, @Nullable ItemStack[] aInputs, @Nullable ItemStack[] aOutputs, + @Nullable Object aSpecial, @Nullable int[] aOutputChances, @Nullable FluidStack[] aFluidInputs, + @Nullable FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue) { + return addRecipe( + new GT_Recipe( + aOptimize, + aInputs, + aOutputs, + aSpecial, + aOutputChances, + aFluidInputs, + aFluidOutputs, + aDuration, + aEUt, + aSpecialValue)); + } + + @Nullable + public GT_Recipe addRecipe(@Nullable int[] aOutputChances, @Nullable FluidStack[] aFluidInputs, + @Nullable FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue) { + return addRecipe( + new GT_Recipe( + false, + null, + null, + null, + aOutputChances, + aFluidInputs, + aFluidOutputs, + aDuration, + aEUt, + aSpecialValue), + false, + false, + false); + } + + @Nullable + public GT_Recipe addRecipe(boolean aOptimize, @Nullable ItemStack[] aInputs, @Nullable ItemStack[] aOutputs, + @Nullable Object aSpecial, @Nullable FluidStack[] aFluidInputs, @Nullable FluidStack[] aFluidOutputs, + int aDuration, int aEUt, int aSpecialValue) { + return addRecipe( + new GT_Recipe( + aOptimize, + aInputs, + aOutputs, + aSpecial, + null, + aFluidInputs, + aFluidOutputs, + aDuration, + aEUt, + aSpecialValue)); + } + + @Nullable + public GT_Recipe addRecipe(GT_Recipe aRecipe) { + return addRecipe(aRecipe, true, false, false); + } + + @Nullable + public GT_Recipe addRecipe(GT_Recipe aRecipe, boolean aCheckForCollisions, boolean aFakeRecipe, boolean aHidden) { + aRecipe.mHidden = aHidden; + aRecipe.mFakeRecipe = aFakeRecipe; + if (aRecipe.mFluidInputs.length < backend.properties.minFluidInputs + && aRecipe.mInputs.length < backend.properties.minItemInputs) return null; + if (aCheckForCollisions && backend.checkCollision(aRecipe)) return null; + return backend.compileRecipe(aRecipe); + } + + /** + * Only used for fake Recipe Handlers to show something in NEI, do not use this for adding actual Recipes! + * findRecipe won't find fake Recipes, containsInput WILL find fake Recipes + */ + @Nullable + public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, @Nullable ItemStack[] aInputs, + @Nullable ItemStack[] aOutputs, @Nullable Object aSpecial, @Nullable int[] aOutputChances, + @Nullable FluidStack[] aFluidInputs, @Nullable FluidStack[] aFluidOutputs, int aDuration, int aEUt, + int aSpecialValue) { + return addFakeRecipe( + aCheckForCollisions, + new GT_Recipe( + false, + aInputs, + aOutputs, + aSpecial, + aOutputChances, + aFluidInputs, + aFluidOutputs, + aDuration, + aEUt, + aSpecialValue)); + } + + /** + * Only used for fake Recipe Handlers to show something in NEI, do not use this for adding actual Recipes! + * findRecipe won't find fake Recipes, containsInput WILL find fake Recipes + */ + @Nullable + public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, @Nullable ItemStack[] aInputs, + @Nullable ItemStack[] aOutputs, @Nullable Object aSpecial, @Nullable FluidStack[] aFluidInputs, + @Nullable FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue) { + return addFakeRecipe( + aCheckForCollisions, + new GT_Recipe( + false, + aInputs, + aOutputs, + aSpecial, + null, + aFluidInputs, + aFluidOutputs, + aDuration, + aEUt, + aSpecialValue)); + } + + @Nullable + public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, @Nullable ItemStack[] aInputs, + @Nullable ItemStack[] aOutputs, @Nullable Object aSpecial, @Nullable FluidStack[] aFluidInputs, + @Nullable FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue, boolean hidden) { + return addFakeRecipe( + aCheckForCollisions, + new GT_Recipe( + false, + aInputs, + aOutputs, + aSpecial, + null, + aFluidInputs, + aFluidOutputs, + aDuration, + aEUt, + aSpecialValue), + hidden); + } + + @Nullable + public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, @Nullable ItemStack[] aInputs, + @Nullable ItemStack[] aOutputs, @Nullable Object aSpecial, @Nullable FluidStack[] aFluidInputs, + @Nullable FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue, ItemStack[][] aAlt, + boolean hidden) { + return addFakeRecipe( + aCheckForCollisions, + new GT_Recipe.GT_Recipe_WithAlt( + false, + aInputs, + aOutputs, + aSpecial, + null, + aFluidInputs, + aFluidOutputs, + aDuration, + aEUt, + aSpecialValue, + aAlt), + hidden); + } + + /** + * Only used for fake Recipe Handlers to show something in NEI, do not use this for adding actual Recipes! + * findRecipe won't find fake Recipes, containsInput WILL find fake Recipes + */ + @Nullable + public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, GT_Recipe aRecipe) { + return addRecipe(aRecipe, aCheckForCollisions, true, false); + } + + @Nullable + public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, GT_Recipe aRecipe, boolean hidden) { + return addRecipe(aRecipe, aCheckForCollisions, true, hidden); + } + + @Nonnull + @Override + public Collection<GT_Recipe> doAdd(GT_RecipeBuilder builder) { + return backend.doAdd(builder); + } + + public GT_Recipe add(GT_Recipe aRecipe) { + return backend.compileRecipe(aRecipe); + } + + // endregion + + /** + * @return if this Item is a valid Input for any for the Recipes + */ + public boolean containsInput(@Nullable ItemStack aStack) { + return aStack != null && backend.containsInput(aStack); + } + + /** + * @return if this Fluid is a valid Input for any for the Recipes + */ + public boolean containsInput(@Nullable FluidStack aFluid) { + return aFluid != null && containsInput(aFluid.getFluid()); + } + + /** + * @return if this Fluid is a valid Input for any for the Recipes + */ + public boolean containsInput(@Nullable Fluid aFluid) { + return aFluid != null && backend.containsInput(aFluid); + } + + // region find recipe + + /** + * @return Entrypoint for fluent API for finding recipe. + */ + public FindRecipeQuery findRecipeQuery() { + return new FindRecipeQuery(this); + } + + @Nullable + public GT_Recipe findRecipe(@Nullable IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, long aVoltage, + @Nullable FluidStack[] aFluids, @Nullable ItemStack... aInputs) { + return findRecipe(aTileEntity, null, aNotUnificated, aVoltage, aFluids, null, aInputs); + } + + @Nullable + public GT_Recipe findRecipe(@Nullable IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, @Nullable FluidStack[] aFluids, @Nullable ItemStack... aInputs) { + return findRecipe(aTileEntity, null, aNotUnificated, aDontCheckStackSizes, aVoltage, aFluids, null, aInputs); + } + + @Nullable + public GT_Recipe findRecipe(@Nullable IHasWorldObjectAndCoords aTileEntity, @Nullable GT_Recipe aRecipe, + boolean aNotUnificated, long aVoltage, @Nullable FluidStack[] aFluids, @Nullable ItemStack aSpecialSlot, + @Nullable ItemStack... aInputs) { + return findRecipe(aTileEntity, aRecipe, aNotUnificated, false, aVoltage, aFluids, aSpecialSlot, aInputs); + } + + @Nullable + public GT_Recipe findRecipe(@Nullable IHasWorldObjectAndCoords aTileEntity, @Nullable GT_Recipe aRecipe, + boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, @Nullable FluidStack[] aFluids, + @Nullable ItemStack aSpecialSlot, @Nullable ItemStack... aInputs) { + return findRecipeQuery().items(aInputs != null ? aInputs : new ItemStack[0]) + .fluids(aFluids != null ? aFluids : new FluidStack[0]) + .specialSlot(aSpecialSlot) + .voltage(aVoltage) + .cachedRecipe(aRecipe) + .notUnificated(aNotUnificated) + .dontCheckStackSizes(aDontCheckStackSizes) + .find(); + } + + // endregion + + @Override + public String toString() { + return "RecipeMap{" + "unlocalizedName='" + + unlocalizedName + + '\'' + + ", ownerMod=" + + defaultRecipeCategory.ownerMod.getModId() + + '}'; + } + + private static final Pattern LEGACY_IDENTIFIER_PATTERN = Pattern.compile("(.+)_[0-9]+_[0-9]+_[0-9]+_[0-9]+_[0-9]+"); + + /** + * Gets recipemap instance from old mUniqueIdentifier format. This is only for backward compat, where tiles + * saved recipemap with mUniqueIdentifier. + * + * @param legacyIdentifier mUniqueIdentifier, in %s_%d_%d_%d_%d_%d format + * @return Found recipemap, can be null + */ + @Nullable + public static RecipeMap<?> getFromOldIdentifier(String legacyIdentifier) { + Matcher matcher = LEGACY_IDENTIFIER_PATTERN.matcher(legacyIdentifier); + if (!matcher.find()) { + // It can be new format + return ALL_RECIPE_MAPS.get(legacyIdentifier); + } + return ALL_RECIPE_MAPS.get(matcher.group(1)); + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMapBackend.java b/src/main/java/gregtech/api/recipe/RecipeMapBackend.java new file mode 100644 index 0000000000..a20a99d3c3 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMapBackend.java @@ -0,0 +1,461 @@ +package gregtech.api.recipe; + +import static gregtech.api.util.GT_RecipeBuilder.handleInvalidRecipe; +import static gregtech.api.util.GT_RecipeBuilder.handleRecipeCollision; +import static gregtech.api.util.GT_Utility.areStacksEqualOrNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.Unmodifiable; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.SetMultimap; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.IRecipeMap; +import gregtech.api.objects.GT_ItemStack; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.GT_StreamUtil; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Responsible for recipe addition / search for recipemap. + * <p> + * In order to bind custom backend to recipemap, use {@link RecipeMapBuilder#of(String, BackendCreator)}. + */ +@SuppressWarnings("unused") +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class RecipeMapBackend { + + private RecipeMap<?> recipeMap; + + /** + * Recipe index based on items. + */ + private final SetMultimap<GT_ItemStack, GT_Recipe> itemIndex = HashMultimap.create(); + /** + * Recipe index based on fluids. + */ + private final SetMultimap<String, GT_Recipe> fluidIndex = HashMultimap.create(); + + /** + * All the recipes belonging to this backend, indexed by recipe category. + */ + private final Map<RecipeCategory, Collection<GT_Recipe>> recipesByCategory = new HashMap<>(); + + /** + * List of recipemaps that also receive recipe addition from this backend. + */ + private final List<IRecipeMap> downstreams = new ArrayList<>(0); + + /** + * All the properties specific to this backend. + */ + protected final RecipeMapBackendProperties properties; + + public RecipeMapBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + this.properties = propertiesBuilder.build(); + GregTech_API.itemStackMultiMaps.add(itemIndex); + } + + void setRecipeMap(RecipeMap<?> recipeMap) { + this.recipeMap = recipeMap; + } + + /** + * @return Properties specific to this backend. + */ + public RecipeMapBackendProperties getProperties() { + return properties; + } + + /** + * @return All the recipes belonging to this backend. Returned collection is immutable, + * use {@link #compileRecipe} to add / {@link #removeRecipes} to remove. + */ + @Unmodifiable + public Collection<GT_Recipe> getAllRecipes() { + return Collections.unmodifiableCollection(allRecipes()); + } + + /** + * @return Raw recipe list + */ + private Collection<GT_Recipe> allRecipes() { + return recipesByCategory.values() + .stream() + .flatMap(Collection::stream) + .collect(Collectors.toCollection(ArrayList::new)); + } + + /** + * @return All the recipes belonging to this backend, indexed by recipe category. + */ + @Unmodifiable + public Collection<GT_Recipe> getRecipesByCategory(RecipeCategory recipeCategory) { + return Collections + .unmodifiableCollection(recipesByCategory.getOrDefault(recipeCategory, Collections.emptyList())); + } + + @Unmodifiable + public Map<RecipeCategory, Collection<GT_Recipe>> getRecipeCategoryMap() { + return Collections.unmodifiableMap(recipesByCategory); + } + + // region add recipe + + /** + * Adds the supplied recipe to the recipe list and index, without any check. + * + * @return Supplied recipe. + */ + public GT_Recipe compileRecipe(GT_Recipe recipe) { + if (recipe.getRecipeCategory() == null) { + recipe.setRecipeCategory(recipeMap.getDefaultRecipeCategory()); + } + recipesByCategory.computeIfAbsent(recipe.getRecipeCategory(), v -> new ArrayList<>()) + .add(recipe); + for (FluidStack fluid : recipe.mFluidInputs) { + if (fluid == null) continue; + fluidIndex.put( + fluid.getFluid() + .getName(), + recipe); + } + return addToItemMap(recipe); + } + + /** + * Adds the supplied recipe to the item cache. + */ + protected GT_Recipe addToItemMap(GT_Recipe recipe) { + for (ItemStack item : recipe.mInputs) { + if (item == null) continue; + itemIndex.put(new GT_ItemStack(item), recipe); + } + return recipe; + } + + /** + * Builds recipe from supplied recipe builder and adds it. + */ + protected Collection<GT_Recipe> doAdd(GT_RecipeBuilder builder) { + Iterable<? extends GT_Recipe> recipes = properties.recipeEmitter.apply(builder); + Collection<GT_Recipe> ret = new ArrayList<>(); + for (GT_Recipe recipe : recipes) { + if (properties.recipeConfigCategory != null) { + assert properties.recipeConfigKeyConvertor != null; + String configKey = properties.recipeConfigKeyConvertor.apply(recipe); + if (configKey != null && (recipe.mDuration = GregTech_API.sRecipeFile + .get(properties.recipeConfigCategory, configKey, recipe.mDuration)) <= 0) { + continue; + } + } + if (recipe.mFluidInputs.length < properties.minFluidInputs + || recipe.mInputs.length < properties.minItemInputs) { + return Collections.emptyList(); + } + if (properties.recipeTransformer != null) { + recipe = properties.recipeTransformer.apply(recipe); + } + if (recipe == null) continue; + if (builder.isCheckForCollision() && checkCollision(recipe)) { + handleCollision(recipe); + continue; + } + if (recipe.getRecipeCategory() != null && recipe.getRecipeCategory().recipeMap != this.recipeMap) { + handleInvalidRecipe(); + continue; + } + ret.add(compileRecipe(recipe)); + } + if (!ret.isEmpty()) { + builder.clearInvalid(); + for (IRecipeMap downstream : downstreams) { + downstream.doAdd(builder); + } + } + return ret; + } + + private void handleCollision(GT_Recipe recipe) { + StringBuilder errorInfo = new StringBuilder(); + boolean hasAnEntry = false; + for (FluidStack fluid : recipe.mFluidInputs) { + if (fluid == null) { + continue; + } + String s = fluid.getLocalizedName(); + if (s == null) { + continue; + } + if (hasAnEntry) { + errorInfo.append("+") + .append(s); + } else { + errorInfo.append(s); + } + hasAnEntry = true; + } + for (ItemStack item : recipe.mInputs) { + if (item == null) { + continue; + } + String itemName = item.getDisplayName(); + if (hasAnEntry) { + errorInfo.append("+") + .append(itemName); + } else { + errorInfo.append(itemName); + } + hasAnEntry = true; + } + handleRecipeCollision(errorInfo.toString()); + } + + void addDownstream(IRecipeMap downstream) { + downstreams.add(downstream); + } + + /** + * Removes supplied recipes from recipe list. Do not use unless absolute necessity! + */ + public void removeRecipes(Collection<? extends GT_Recipe> recipesToRemove) { + for (Collection<GT_Recipe> recipes : recipesByCategory.values()) { + recipes.removeAll(recipesToRemove); + } + for (GT_ItemStack key : new HashMap<>(itemIndex.asMap()).keySet()) { + itemIndex.get(key) + .removeAll(recipesToRemove); + } + for (String key : new HashMap<>(fluidIndex.asMap()).keySet()) { + fluidIndex.get(key) + .removeAll(recipesToRemove); + } + } + + /** + * Removes supplied recipe from recipe list. Do not use unless absolute necessity! + */ + public void removeRecipe(GT_Recipe recipe) { + removeRecipes(Collections.singleton(recipe)); + } + + /** + * If you want to shoot your foot... + */ + public void clearRecipes() { + recipesByCategory.clear(); + } + + // endregion + + /** + * Re-unificates all the items present in recipes. Also reflects recipe removals. + */ + public void reInit() { + itemIndex.clear(); + for (GT_Recipe recipe : allRecipes()) { + GT_OreDictUnificator.setStackArray(true, recipe.mInputs); + GT_OreDictUnificator.setStackArray(true, recipe.mOutputs); + addToItemMap(recipe); + } + } + + /** + * @return If supplied item is a valid input for any of the recipes + */ + public boolean containsInput(ItemStack item) { + return itemIndex.containsKey(new GT_ItemStack(item)) || itemIndex.containsKey(new GT_ItemStack(item, true)); + } + + /** + * @return If supplied fluid is a valid input for any of the recipes + */ + public boolean containsInput(Fluid fluid) { + return fluidIndex.containsKey(fluid.getName()); + } + + // region find recipe + + /** + * Checks if given recipe conflicts with already registered recipes. + * + * @return True if collision is found. + */ + boolean checkCollision(GT_Recipe recipe) { + return matchRecipeStream(recipe.mInputs, recipe.mFluidInputs, null, null, false, true, true).findAny() + .isPresent(); + } + + /** + * Overwrites {@link #matchRecipeStream} method. Also override {@link #doesOverwriteFindRecipe} to make it work. + */ + @Nullable + protected GT_Recipe overwriteFindRecipe(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot, + @Nullable GT_Recipe cachedRecipe) { + return null; + } + + /** + * @return Whether to use {@link #overwriteFindRecipe} for finding recipe. + */ + protected boolean doesOverwriteFindRecipe() { + return false; + } + + /** + * Modifies successfully found recipe. Make sure not to mutate the found recipe but use copy! + */ + @Nullable + protected GT_Recipe modifyFoundRecipe(GT_Recipe recipe, ItemStack[] items, FluidStack[] fluids, + @Nullable ItemStack specialSlot) { + return recipe; + } + + /** + * Called when {@link #matchRecipeStream} cannot find recipe. + */ + @Nullable + protected GT_Recipe findFallback(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot) { + return null; + } + + /** + * Returns all the matched recipes in the form of Stream, without any additional check for matches. + * + * @param rawItems Item inputs. + * @param fluids Fluid inputs. + * @param specialSlot Content of the special slot. Normal recipemaps don't need this, but some do. + * Set {@link RecipeMapBuilder#specialSlotSensitive} to make it actually functional. + * Alternatively overriding {@link #filterFindRecipe} will also work. + * @param cachedRecipe If this is not null, this method tests it before all other recipes. + * @param notUnificated If this is set to true, item inputs will be unificated. + * @param dontCheckStackSizes If this is set to true, this method won't check item count and fluid amount + * for the matched recipe. + * @param forCollisionCheck If this method is called to check collision with already registered recipes. + * @return Stream of matches recipes. + */ + Stream<GT_Recipe> matchRecipeStream(ItemStack[] rawItems, FluidStack[] fluids, @Nullable ItemStack specialSlot, + @Nullable GT_Recipe cachedRecipe, boolean notUnificated, boolean dontCheckStackSizes, + boolean forCollisionCheck) { + if (doesOverwriteFindRecipe()) { + return GT_StreamUtil.ofNullable(overwriteFindRecipe(rawItems, fluids, specialSlot, cachedRecipe)); + } + + if (recipesByCategory.isEmpty()) { + return Stream.empty(); + } + + // Some recipe classes require a certain amount of inputs of certain kinds. Like "at least 1 fluid + 1 item" + // or "at least 2 items" before they start searching for recipes. + // This improves performance massively, especially when people leave things like programmed circuits, + // molds or shapes in their machines. + // For checking collision, we assume min inputs check already has been passed as of building the recipe. + if (!forCollisionCheck) { + if (properties.minFluidInputs > 0) { + int count = 0; + for (FluidStack fluid : fluids) if (fluid != null) count++; + if (count < properties.minFluidInputs) { + return Stream.empty(); + } + } + if (properties.minItemInputs > 0) { + int count = 0; + for (ItemStack item : rawItems) if (item != null) count++; + if (count < properties.minItemInputs) { + return Stream.empty(); + } + } + } + + ItemStack[] items; + // Unification happens here in case the item input isn't already unificated. + if (notUnificated) { + items = GT_OreDictUnificator.getStackArray(true, (Object[]) rawItems); + } else { + items = rawItems; + } + + return Stream.<Stream<GT_Recipe>>of( + // Check the recipe which has been used last time in order to not have to search for it again, if possible. + GT_StreamUtil.ofNullable(cachedRecipe) + .filter(recipe -> recipe.mCanBeBuffered) + .filter(recipe -> filterFindRecipe(recipe, items, fluids, specialSlot, dontCheckStackSizes)) + .map(recipe -> modifyFoundRecipe(recipe, items, fluids, specialSlot)) + .filter(Objects::nonNull), + // Now look for the recipes inside the item index, but only when the recipes actually can have items inputs. + GT_StreamUtil.ofConditional(!itemIndex.isEmpty(), items) + .filter(Objects::nonNull) + .flatMap(item -> Stream.of(new GT_ItemStack(item), new GT_ItemStack(item, true))) + .map(itemIndex::get) + .flatMap(Collection::stream) + .filter(recipe -> filterFindRecipe(recipe, items, fluids, specialSlot, dontCheckStackSizes)) + .map(recipe -> modifyFoundRecipe(recipe, items, fluids, specialSlot)) + .filter(Objects::nonNull), + // If the minimum amount of items required for the recipes is 0, then it could match to fluid-only recipes, + // so check fluid index too. + GT_StreamUtil.ofConditional(properties.minItemInputs == 0, fluids) + .filter(Objects::nonNull) + .map( + fluidStack -> fluidIndex.get( + fluidStack.getFluid() + .getName())) + .flatMap(Collection::stream) + .filter(recipe -> filterFindRecipe(recipe, items, fluids, specialSlot, dontCheckStackSizes)) + .map(recipe -> modifyFoundRecipe(recipe, items, fluids, specialSlot)) + .filter(Objects::nonNull), + // Lastly, find fallback. + forCollisionCheck ? Stream.empty() + : GT_StreamUtil.ofSupplier(() -> findFallback(items, fluids, specialSlot)) + .filter(Objects::nonNull)) + .flatMap(Function.identity()); + } + + /** + * The minimum filter required for recipe match logic. You can override this to have custom validation. + * <p> + * Other checks like machine voltage will be done in another places. + * <p> + * Note that this won't be called if {@link #doesOverwriteFindRecipe} is true. + */ + protected boolean filterFindRecipe(GT_Recipe recipe, ItemStack[] items, FluidStack[] fluids, + @Nullable ItemStack specialSlot, boolean dontCheckStackSizes) { + if (recipe.mEnabled && !recipe.mFakeRecipe + && recipe.isRecipeInputEqual(false, dontCheckStackSizes, fluids, items)) { + return !properties.specialSlotSensitive + || areStacksEqualOrNull((ItemStack) recipe.mSpecialItems, specialSlot); + } + return false; + } + + // endregion + + @FunctionalInterface + public interface BackendCreator<B extends RecipeMapBackend> { + + /** + * @see RecipeMapBackend#RecipeMapBackend + */ + B create(RecipeMapBackendPropertiesBuilder propertiesBuilder); + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMapBackendProperties.java b/src/main/java/gregtech/api/recipe/RecipeMapBackendProperties.java new file mode 100644 index 0000000000..7262b794ab --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMapBackendProperties.java @@ -0,0 +1,77 @@ +package gregtech.api.recipe; + +import java.util.function.Function; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.api.util.FieldsAreNonnullByDefault; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Data object to store properties used for {@link RecipeMapBackend}. Use {@link #builder()} for creation. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +public final class RecipeMapBackendProperties { + + static RecipeMapBackendPropertiesBuilder builder() { + return new RecipeMapBackendPropertiesBuilder(); + } + + /** + * Minimum amount of item inputs required for the recipes. + */ + public final int minItemInputs; + /** + * Minimum amount of fluid inputs required for the recipes. + */ + public final int minFluidInputs; + + /** + * Whether this backend should check for equality of special slot when searching recipe. + */ + public final boolean specialSlotSensitive; + + /** + * If recipe builder should stop optimizing inputs. + */ + public final boolean disableOptimize; + + /** + * Changes how recipes are emitted by a particular recipe builder. + */ + public final Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> recipeEmitter; + + /** + * Runs a custom hook on all recipes added <b>via builder</b>. + */ + @Nullable + public final Function<? super GT_Recipe, ? extends GT_Recipe> recipeTransformer; + + @Nullable + public final String recipeConfigCategory; + @Nullable + public final Function<? super GT_Recipe, String> recipeConfigKeyConvertor; + + RecipeMapBackendProperties(int minItemInputs, int minFluidInputs, boolean specialSlotSensitive, + boolean disableOptimize, + Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> recipeEmitter, + @Nullable Function<? super GT_Recipe, ? extends GT_Recipe> recipeTransformer, + @Nullable String recipeConfigCategory, @Nullable Function<? super GT_Recipe, String> recipeConfigKeyConvertor) { + if (minItemInputs < 0 || minFluidInputs < 0) { + throw new IllegalArgumentException("minItemInputs and minFluidInputs cannot be negative"); + } + this.minItemInputs = minItemInputs; + this.minFluidInputs = minFluidInputs; + this.specialSlotSensitive = specialSlotSensitive; + this.disableOptimize = disableOptimize; + this.recipeEmitter = recipeEmitter; + this.recipeTransformer = recipeTransformer; + this.recipeConfigCategory = recipeConfigCategory; + this.recipeConfigKeyConvertor = recipeConfigKeyConvertor; + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMapBackendPropertiesBuilder.java b/src/main/java/gregtech/api/recipe/RecipeMapBackendPropertiesBuilder.java new file mode 100644 index 0000000000..933ea1b06b --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMapBackendPropertiesBuilder.java @@ -0,0 +1,119 @@ +package gregtech.api.recipe; + +import static gregtech.api.util.GT_RecipeMapUtil.buildOrEmpty; + +import java.util.function.Function; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.google.common.collect.Iterables; + +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Builder class for {@link RecipeMapBackendProperties}. + */ +@SuppressWarnings({ "unused", "UnusedReturnValue" }) +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public final class RecipeMapBackendPropertiesBuilder { + + private int minItemInputs; + private int minFluidInputs; + + private boolean specialSlotSensitive; + + private boolean disableOptimize; + + private Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> recipeEmitter = this::defaultBuildRecipe; + + @Nullable + private Function<? super GT_Recipe, ? extends GT_Recipe> recipeTransformer; + + @Nullable + private String recipeConfigCategory; + @Nullable + private Function<? super GT_Recipe, String> recipeConfigKeyConvertor; + + RecipeMapBackendPropertiesBuilder() {} + + RecipeMapBackendProperties build() { + return new RecipeMapBackendProperties( + minItemInputs, + minFluidInputs, + specialSlotSensitive, + disableOptimize, + recipeEmitter, + recipeTransformer, + recipeConfigCategory, + recipeConfigKeyConvertor); + } + + public RecipeMapBackendPropertiesBuilder minItemInputs(int minItemInputs) { + this.minItemInputs = minItemInputs; + return this; + } + + public RecipeMapBackendPropertiesBuilder minFluidInputs(int minFluidInputs) { + this.minFluidInputs = minFluidInputs; + return this; + } + + public RecipeMapBackendPropertiesBuilder specialSlotSensitive() { + this.specialSlotSensitive = true; + return this; + } + + public RecipeMapBackendPropertiesBuilder disableOptimize() { + this.disableOptimize = true; + return this; + } + + public RecipeMapBackendPropertiesBuilder recipeEmitter( + Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> recipeEmitter) { + this.recipeEmitter = recipeEmitter; + return this; + } + + public RecipeMapBackendPropertiesBuilder combineRecipeEmitter( + Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> func) { + // move recipeEmitter to local variable, so lambda capture the function itself instead of this + Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> cur = this.recipeEmitter; + return recipeEmitter(b -> Iterables.concat(cur.apply(b), func.apply(b))); + } + + public RecipeMapBackendPropertiesBuilder recipeTransformer( + Function<? super GT_Recipe, ? extends GT_Recipe> recipeTransformer) { + this.recipeTransformer = recipeTransformer; + return this; + } + + public RecipeMapBackendPropertiesBuilder chainRecipeTransformer( + Function<? super GT_Recipe, ? extends GT_Recipe> func) { + this.recipeTransformer = this.recipeTransformer == null ? func : this.recipeTransformer.andThen(func); + return this; + } + + public RecipeMapBackendPropertiesBuilder recipeConfigFile(String category, + Function<? super GT_Recipe, String> keyConvertor) { + this.recipeConfigCategory = category; + this.recipeConfigKeyConvertor = keyConvertor; + return this; + } + + private Iterable<? extends GT_Recipe> defaultBuildRecipe(GT_RecipeBuilder builder) { + // TODO sensible validation + GT_RecipeBuilder b = builder; + if (disableOptimize && builder.isOptimize()) { + b = copy(builder, b).noOptimize(); + } + return buildOrEmpty(b); + } + + private static GT_RecipeBuilder copy(GT_RecipeBuilder original, GT_RecipeBuilder b) { + return b == original ? b.copy() : b; + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMapBuilder.java b/src/main/java/gregtech/api/recipe/RecipeMapBuilder.java new file mode 100644 index 0000000000..8659018934 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMapBuilder.java @@ -0,0 +1,522 @@ +package gregtech.api.recipe; + +import static gregtech.api.enums.Mods.GregTech; + +import java.awt.Rectangle; +import java.util.Collections; +import java.util.Comparator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.UnaryOperator; + +import javax.annotation.ParametersAreNonnullByDefault; + +import org.apache.commons.lang3.StringUtils; + +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import codechicken.nei.recipe.HandlerInfo; +import gregtech.api.gui.modularui.FallbackableSteamTexture; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.modularui.SteamTexture; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.formatter.INEISpecialInfoFormatter; + +// spotless:off spotless likes formatting @code to @code +/** + * Builder class for constructing {@link RecipeMap}. Instantiate this class and call {@link #build} + * to retrieve RecipeMap. Smallest example: + * + * <pre> + * {@code + * RecipeMap<RecipeMapBackend> exampleRecipes = RecipeMapBuilder.of("example") + * .maxIO(9, 4, 1, 1) + * .build(); + * } + * </pre> + * + * Note that {@link #maxIO} is required to build. + */ +// spotless:on +@SuppressWarnings("unused") +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public final class RecipeMapBuilder<B extends RecipeMapBackend> { + + private final String unlocalizedName; + private final RecipeMapBackendPropertiesBuilder backendPropertiesBuilder = RecipeMapBackendProperties.builder(); + private final RecipeMapBackend.BackendCreator<B> backendCreator; + private final BasicUIPropertiesBuilder uiPropertiesBuilder; + private final NEIRecipePropertiesBuilder neiPropertiesBuilder = NEIRecipeProperties.builder(); + private RecipeMapFrontend.FrontendCreator frontendCreator = RecipeMapFrontend::new; + + /** + * Constructs builder object for {@link RecipeMap} with given backend logic. For custom frontend, + * call {@link #frontend} for the created builder object. + * + * @param unlocalizedName Unique identifier for the recipemap. This is also used as translation key + * for NEI recipe GUI header, so add localization for it if needed. + * @return New builder object. + */ + public static <B extends RecipeMapBackend> RecipeMapBuilder<B> of(String unlocalizedName, + RecipeMapBackend.BackendCreator<B> backendCreator) { + return new RecipeMapBuilder<>(unlocalizedName, backendCreator); + } + + /** + * Constructs builder object for {@link RecipeMap}. + * + * @param unlocalizedName Unique identifier for the recipemap. This is also used as translation key + * for NEI recipe GUI header, so add localization for it if needed. + * @return New builder object. + */ + public static RecipeMapBuilder<RecipeMapBackend> of(String unlocalizedName) { + return new RecipeMapBuilder<>(unlocalizedName, RecipeMapBackend::new); + } + + private RecipeMapBuilder(String unlocalizedName, RecipeMapBackend.BackendCreator<B> backendCreator) { + this.unlocalizedName = unlocalizedName; + this.backendCreator = backendCreator; + this.uiPropertiesBuilder = BasicUIProperties.builder() + .progressBarTexture(GT_UITextures.fallbackableProgressbar(unlocalizedName, GT_UITextures.PROGRESSBAR_ARROW)) + .neiTransferRectId(unlocalizedName); + } + + // region backend + + /** + * Sets minimum amount of inputs required for the recipes. + */ + public RecipeMapBuilder<B> minInputs(int minItemInputs, int minFluidInputs) { + backendPropertiesBuilder.minItemInputs(minItemInputs) + .minFluidInputs(minFluidInputs); + return this; + } + + /** + * Whether this recipemap should check for equality of special slot when searching recipe. + */ + public RecipeMapBuilder<B> specialSlotSensitive() { + backendPropertiesBuilder.specialSlotSensitive(); + return this; + } + + /** + * If recipe builder should stop optimizing inputs. + */ + public RecipeMapBuilder<B> disableOptimize() { + backendPropertiesBuilder.disableOptimize(); + return this; + } + + /** + * Changes how recipes are emitted by a particular recipe builder. Can emit multiple recipe per builder. + */ + public RecipeMapBuilder<B> recipeEmitter( + Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> recipeEmitter) { + backendPropertiesBuilder.recipeEmitter(recipeEmitter); + return this; + } + + /** + * Changes how recipes are emitted by a particular recipe builder. Should not return null. + * <p> + * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. + */ + public RecipeMapBuilder<B> recipeEmitterSingle( + Function<? super GT_RecipeBuilder, ? extends GT_Recipe> recipeEmitter) { + return recipeEmitter(recipeEmitter.andThen(Collections::singletonList)); + } + + /** + * Changes how recipes are emitted by a particular recipe builder. Can emit multiple recipe per builder. + * <p> + * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. + * <p> + * Unlike {@link #recipeEmitter(Function)}, this one does not clear the existing recipe being emitted, if any + */ + public RecipeMapBuilder<B> combineRecipeEmitter( + Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> recipeEmitter) { + backendPropertiesBuilder.combineRecipeEmitter(recipeEmitter); + return this; + } + + /** + * Changes how recipes are emitted by a particular recipe builder. Effectively add a new recipe per recipe added. + * func must not return null. + * <p> + * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. + * <p> + * Unlike {@link #recipeEmitter(Function)}, this one does not clear the existing recipe being emitted, if any + */ + public RecipeMapBuilder<B> combineRecipeEmitterSingle( + Function<? super GT_RecipeBuilder, ? extends GT_Recipe> recipeEmitter) { + return combineRecipeEmitter(recipeEmitter.andThen(Collections::singletonList)); + } + + /** + * Runs a custom hook on all recipes added <b>via builder</b>. For more complicated behavior, + * use {@link #recipeEmitter}. + * <p> + * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. + */ + public RecipeMapBuilder<B> recipeTransformer(Function<? super GT_Recipe, ? extends GT_Recipe> recipeTransformer) { + backendPropertiesBuilder.recipeTransformer(recipeTransformer); + return this; + } + + /** + * Runs a custom hook on all recipes added <b>via builder</b>. For more complicated behavior, + * use {@link #recipeEmitter}. + * <p> + * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. + */ + public RecipeMapBuilder<B> recipeTransformer(Consumer<GT_Recipe> recipeTransformer) { + return recipeTransformer(withIdentityReturn(recipeTransformer)); + } + + /** + * Runs a custom hook on all recipes added <b>via builder</b>. For more complicated behavior, + * use {@link #recipeEmitter}. + * <p> + * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. + * <p> + * Unlike {@link #recipeTransformer(Function)}, this one will not replace the existing special handler. + * The supplied function will be given the output of existing handler when a recipe is added. + */ + public RecipeMapBuilder<B> chainRecipeTransformer( + Function<? super GT_Recipe, ? extends GT_Recipe> recipeTransformer) { + backendPropertiesBuilder.chainRecipeTransformer(recipeTransformer); + return this; + } + + /** + * Runs a custom hook on all recipes added <b>via builder</b>. For more complicated behavior, + * use {@link #recipeEmitter}. + * <p> + * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. + * <p> + * Unlike {@link #recipeTransformer(Function)}, this one will not replace the existing special handler. + * The supplied function will be given the output of existing handler when a recipe is added. + */ + public RecipeMapBuilder<B> chainRecipeTransformer(Consumer<GT_Recipe> recipeTransformer) { + return chainRecipeTransformer(withIdentityReturn(recipeTransformer)); + } + + public RecipeMapBuilder<B> recipeConfigFile(String category, Function<? super GT_Recipe, String> keyConvertor) { + if (StringUtils.isBlank(category)) throw new IllegalArgumentException(); + backendPropertiesBuilder.recipeConfigFile(category, keyConvertor); + return this; + } + + // endregion + + // region frontend UI properties + + /** + * Sets how many item/fluid inputs/outputs does this recipemap usually has at most. + * It does not actually restrict the number of items that can be used in recipes. + */ + public RecipeMapBuilder<B> maxIO(int maxItemInputs, int maxItemOutputs, int maxFluidInputs, int maxFluidOutputs) { + uiPropertiesBuilder.maxItemInputs(maxItemInputs) + .maxItemOutputs(maxItemOutputs) + .maxFluidInputs(maxFluidInputs) + .maxFluidOutputs(maxFluidOutputs); + return this; + } + + /** + * Sets function to get overlay for slots. + */ + public RecipeMapBuilder<B> slotOverlays(BasicUIProperties.SlotOverlayGetter<IDrawable> slotOverlays) { + uiPropertiesBuilder.slotOverlays(slotOverlays); + return this; + } + + /** + * Sets function to get overlay for slots of steam machines. + */ + public RecipeMapBuilder<B> slotOverlaysSteam(BasicUIProperties.SlotOverlayGetter<SteamTexture> slotOverlaysSteam) { + uiPropertiesBuilder.slotOverlaysSteam(slotOverlaysSteam); + return this; + } + + /** + * Sets texture and animation direction of the progressbar. + * <p> + * Unless specified, size should be (20, 36), consisting of two parts; + * First is (20, 18) size of "empty" image at the top, Second is (20, 18) size of "filled" image at the bottom. + * <p> + * By default, it's set to {@code GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT}. + */ + public RecipeMapBuilder<B> progressBar(UITexture texture, ProgressBar.Direction direction) { + return progressBarWithFallback(GT_UITextures.fallbackableProgressbar(unlocalizedName, texture), direction); + } + + /** + * Sets progressbar texture with right direction. + * <p> + * Unless specified, size should be (20, 36), consisting of two parts; + * First is (20, 18) size of "empty" image at the top, Second is (20, 18) size of "filled" image at the bottom. + */ + public RecipeMapBuilder<B> progressBar(UITexture texture) { + return progressBar(texture, ProgressBar.Direction.RIGHT); + } + + /** + * Some resource packs want to use custom progress bar textures even for plain arrow. This method allows them to + * add unique textures, yet other packs don't need to make textures for every recipemap. + */ + private RecipeMapBuilder<B> progressBarWithFallback(FallbackableUITexture texture, + ProgressBar.Direction direction) { + uiPropertiesBuilder.progressBarTexture(texture) + .progressBarDirection(direction); + return this; + } + + /** + * Sets progressbar texture for steam machines. + * <p> + * Unless specified, size should be (20, 36), consisting of two parts; + * First is (20, 18) size of "empty" image at the top, Second is (20, 18) size of "filled" image at the bottom. + */ + public RecipeMapBuilder<B> progressBarSteam(SteamTexture texture) { + return progressBarSteamWithFallback( + new FallbackableSteamTexture( + SteamTexture.fullImage(GregTech.ID, "gui/progressbar/" + unlocalizedName + "_%s"), + texture)); + } + + private RecipeMapBuilder<B> progressBarSteamWithFallback(FallbackableSteamTexture texture) { + uiPropertiesBuilder.progressBarTextureSteam(texture); + return this; + } + + /** + * Sets size of the progressbar. (20, 36) by default. + */ + public RecipeMapBuilder<B> progressBarSize(int x, int y) { + uiPropertiesBuilder.progressBarSize(new Size(x, y)); + return this; + } + + /** + * Sets position of the progressbar. (78, 24) by default. + */ + public RecipeMapBuilder<B> progressBarPos(int x, int y) { + uiPropertiesBuilder.progressBarPos(new Pos2d(x, y)); + return this; + } + + /** + * Stops adding progressbar to the UI. + */ + public RecipeMapBuilder<B> dontUseProgressBar() { + uiPropertiesBuilder.useProgressBar(false); + return this; + } + + /** + * Configures this recipemap to use special slot. This means special slot shows up on NEI and tooltip for + * special slot on basic machine GUI indicates it has actual usage. + */ + public RecipeMapBuilder<B> useSpecialSlot() { + uiPropertiesBuilder.useSpecialSlot(true); + return this; + } + + /** + * Adds GUI area where clicking shows up all the recipes available. + * + * @see codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect + */ + public RecipeMapBuilder<B> neiTransferRect(int x, int y, int width, int height) { + uiPropertiesBuilder.addNEITransferRect(new Rectangle(x, y, width, height)); + return this; + } + + /** + * Sets ID used to open NEI recipe GUI when progressbar is clicked. + */ + public RecipeMapBuilder<B> neiTransferRectId(String neiTransferRectId) { + uiPropertiesBuilder.neiTransferRectId(neiTransferRectId); + return this; + } + + /** + * Adds additional textures shown on GUI. + */ + public RecipeMapBuilder<B> addSpecialTexture(int x, int y, int width, int height, IDrawable texture) { + uiPropertiesBuilder.addSpecialTexture(new Size(width, height), new Pos2d(x, y), texture); + return this; + } + + /** + * Adds additional textures shown on steam machine GUI. + */ + public RecipeMapBuilder<B> addSpecialTextureSteam(int x, int y, int width, int height, SteamTexture texture) { + uiPropertiesBuilder.addSpecialTextureSteam(new Size(width, height), new Pos2d(x, y), texture); + return this; + } + + /** + * Sets logo shown on GUI. GregTech logo by default. + */ + public RecipeMapBuilder<B> logo(IDrawable logo) { + uiPropertiesBuilder.logo(logo); + return this; + } + + /** + * Sets size of logo. (17, 17) by default. + */ + public RecipeMapBuilder<B> logoSize(int width, int height) { + uiPropertiesBuilder.logoSize(new Size(width, height)); + return this; + } + + /** + * Sets position of logo. (152, 63) by default. + */ + public RecipeMapBuilder<B> logoPos(int x, int y) { + uiPropertiesBuilder.logoPos(new Pos2d(x, y)); + return this; + } + + /** + * Sets amperage for the recipemap. + */ + public RecipeMapBuilder<B> amperage(int amperage) { + uiPropertiesBuilder.amperage(amperage); + return this; + } + + // endregion + + // region frontend NEI properties + + /** + * Stops adding dedicated NEI recipe page for this recipemap. This does not prevent adding transferrect + * for the machine GUI. + */ + public RecipeMapBuilder<B> disableRegisterNEI() { + neiPropertiesBuilder.disableRegisterNEI(); + return this; + } + + /** + * Sets properties of NEI handler info this recipemap belongs to. You can specify icon shown on recipe tab, + * handler height, number of recipes per page, etc. Either use supplied template or return newly constructed one. + * <p> + * Invocation of the builder creator is delayed until the actual registration (FMLLoadCompleteEvent), + * so you can safely use itemstack that doesn't exist as of recipemap initialization. + * <p> + * If this method is not used, handler icon will be inferred from recipe catalysts associated with this recipemap. + * <p> + * Precisely, what's registered to NEI is {@link RecipeCategory}, not RecipeMap. However, handler info supplied + * by this method will be used for default category where most of the recipes belong to. + */ + public RecipeMapBuilder<B> neiHandlerInfo(UnaryOperator<HandlerInfo.Builder> handlerInfoCreator) { + neiPropertiesBuilder.handlerInfoCreator(handlerInfoCreator); + return this; + } + + /** + * Sets offset of background shown on NEI. + */ + public RecipeMapBuilder<B> neiRecipeBackgroundSize(int width, int height) { + neiPropertiesBuilder.recipeBackgroundSize(new Size(width, height)); + return this; + } + + /** + * Sets size of background shown on NEI. + */ + public RecipeMapBuilder<B> neiRecipeBackgroundOffset(int x, int y) { + neiPropertiesBuilder.recipeBackgroundOffset(new Pos2d(x, y)); + return this; + } + + /** + * Sets formatter for special description for the recipe, mainly {@link gregtech.api.util.GT_Recipe#mSpecialValue}. + */ + public RecipeMapBuilder<B> neiSpecialInfoFormatter(INEISpecialInfoFormatter neiSpecialInfoFormatter) { + neiPropertiesBuilder.neiSpecialInfoFormatter(neiSpecialInfoFormatter); + return this; + } + + /** + * Sets whether to show oredict equivalent item outputs on NEI. + */ + public RecipeMapBuilder<B> unificateOutputNEI(boolean unificateOutputNEI) { + neiPropertiesBuilder.unificateOutput(unificateOutputNEI); + return this; + } + + /** + * Sets NEI recipe handler to use a custom filter method {@link OverclockDescriber#canHandle} to limit the shown + * recipes when searching recipes with recipe catalyst. Without calling this method, the voltage of the recipe is + * the only factor to filter recipes by default. + * <p> + * This method on its own doesn't do anything. You need to bind custom {@link OverclockDescriber} object to machines + * that will be shown as recipe catalysts for this recipemap by implementing + * {@link gregtech.api.interfaces.tileentity.IOverclockDescriptionProvider}. + */ + public RecipeMapBuilder<B> useCustomFilterForNEI() { + neiPropertiesBuilder.useCustomFilter(); + return this; + } + + /** + * Stops rendering the actual stack size of items on NEI. + */ + public RecipeMapBuilder<B> disableRenderRealStackSizes() { + neiPropertiesBuilder.disableRenderRealStackSizes(); + return this; + } + + /** + * Sets custom comparator for NEI recipe sort. + */ + public RecipeMapBuilder<B> neiRecipeComparator(Comparator<GT_Recipe> comparator) { + neiPropertiesBuilder.recipeComparator(comparator); + return this; + } + + // endregion + + /** + * Sets custom frontend logic. For custom backend, pass it to {@link #of(String, RecipeMapBackend.BackendCreator)}. + */ + public RecipeMapBuilder<B> frontend(RecipeMapFrontend.FrontendCreator frontendCreator) { + this.frontendCreator = frontendCreator; + return this; + } + + /** + * Builds new recipemap. + * + * @return Recipemap object with backend type parameter, which is {@code RecipeMapFrontend} unless specified. + */ + public RecipeMap<B> build() { + return new RecipeMap<>( + unlocalizedName, + backendCreator.create(backendPropertiesBuilder), + frontendCreator.create(uiPropertiesBuilder, neiPropertiesBuilder)); + } + + private static <T> Function<? super T, ? extends T> withIdentityReturn(Consumer<T> func) { + return r -> { + func.accept(r); + return r; + }; + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMapFrontend.java b/src/main/java/gregtech/api/recipe/RecipeMapFrontend.java new file mode 100644 index 0000000000..63daa00dc7 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMapFrontend.java @@ -0,0 +1,395 @@ +package gregtech.api.recipe; + +import static gregtech.api.util.GT_Utility.trans; +import static net.minecraft.util.EnumChatFormatting.GRAY; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.IntStream; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; + +import org.apache.commons.lang3.tuple.Pair; + +import com.gtnewhorizons.modularui.api.GlStateManager; +import com.gtnewhorizons.modularui.api.ModularUITextures; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; + +import codechicken.nei.PositionedStack; +import gregtech.GT_Mod; +import gregtech.api.enums.SteamVariant; +import gregtech.api.gui.GT_GUIColorOverride; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.recipe.metadata.IRecipeMetadataStorage; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; +import gregtech.nei.GT_NEI_DefaultHandler; +import gregtech.nei.RecipeDisplayInfo; + +/** + * Responsible for managing GUI tied to recipemap. It has two property objects, {@link NEIRecipeProperties} and + * {@link BasicUIProperties}. The former is only for NEI display, while the latter is for both NEI and basic machine. + * <p> + * In order to bind custom frontend to recipemap, use {@link RecipeMapBuilder#frontend}. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class RecipeMapFrontend { + + /** + * Properties specific to this frontend, mainly for GUI widgets. + */ + protected final BasicUIProperties uiProperties; + /** + * Properties specific to this frontend, only for NEI specific settings. + */ + protected final NEIRecipeProperties neiProperties; + + protected final GT_GUIColorOverride colorOverride = GT_GUIColorOverride + .get(GT_UITextures.BACKGROUND_NEI_SINGLE_RECIPE.location); + + public RecipeMapFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + this.uiProperties = uiPropertiesBuilder.itemInputPositionsGetter(this::getItemInputPositions) + .itemOutputPositionsGetter(this::getItemOutputPositions) + .specialItemPositionGetter(this::getSpecialItemPosition) + .fluidInputPositionsGetter(this::getFluidInputPositions) + .fluidOutputPositionsGetter(this::getFluidOutputPositions) + .build(); + this.neiProperties = neiPropertiesBuilder.build(); + } + + /** + * @return Properties specific to this frontend, mainly for GUI widgets. + */ + public BasicUIProperties getUIProperties() { + return uiProperties; + } + + /** + * @return Properties specific to this frontend, only for NEI specific settings. + */ + public NEIRecipeProperties getNEIProperties() { + return neiProperties; + } + + /** + * Creates NEI recipe layout, except for actual items / fluids. + */ + public ModularWindow.Builder createNEITemplate(IItemHandlerModifiable itemInputsInventory, + IItemHandlerModifiable itemOutputsInventory, IItemHandlerModifiable specialSlotInventory, + IItemHandlerModifiable fluidInputsInventory, IItemHandlerModifiable fluidOutputsInventory, + Supplier<Float> progressSupplier, Pos2d windowOffset) { + ModularWindow.Builder builder = ModularWindow.builder(neiProperties.recipeBackgroundSize) + .setBackground(GT_UITextures.BACKGROUND_NEI_SINGLE_RECIPE); + + UIHelper.forEachSlots( + (i, backgrounds, pos) -> builder.widget( + SlotWidget.phantom(itemInputsInventory, i) + .setBackground(backgrounds) + .setPos(pos) + .setSize(18, 18)), + (i, backgrounds, pos) -> builder.widget( + SlotWidget.phantom(itemOutputsInventory, i) + .setBackground(backgrounds) + .setPos(pos) + .setSize(18, 18)), + (i, backgrounds, pos) -> { + if (uiProperties.useSpecialSlot) builder.widget( + SlotWidget.phantom(specialSlotInventory, 0) + .setBackground(backgrounds) + .setPos(pos) + .setSize(18, 18)); + }, + (i, backgrounds, pos) -> builder.widget( + SlotWidget.phantom(fluidInputsInventory, i) + .setBackground(backgrounds) + .setPos(pos) + .setSize(18, 18)), + (i, backgrounds, pos) -> builder.widget( + SlotWidget.phantom(fluidOutputsInventory, i) + .setBackground(backgrounds) + .setPos(pos) + .setSize(18, 18)), + ModularUITextures.ITEM_SLOT, + ModularUITextures.FLUID_SLOT, + uiProperties, + uiProperties.maxItemInputs, + uiProperties.maxItemOutputs, + uiProperties.maxFluidInputs, + uiProperties.maxFluidOutputs, + SteamVariant.NONE, + windowOffset); + + if (uiProperties.useProgressBar) { + addProgressBar(builder, progressSupplier, windowOffset); + } + addGregTechLogo(builder, windowOffset); + + for (Pair<IDrawable, Pair<Size, Pos2d>> specialTexture : uiProperties.specialTextures) { + builder.widget( + new DrawableWidget().setDrawable(specialTexture.getLeft()) + .setSize( + specialTexture.getRight() + .getLeft()) + .setPos( + specialTexture.getRight() + .getRight() + .add(windowOffset))); + } + + return builder; + } + + public void addProgressBar(ModularWindow.Builder builder, Supplier<Float> progressSupplier, Pos2d windowOffset) { + assert uiProperties.progressBarTexture != null; + builder.widget( + new ProgressBar().setTexture(uiProperties.progressBarTexture.get(), 20) + .setDirection(uiProperties.progressBarDirection) + .setProgress(progressSupplier) + .setSynced(false, false) + .setPos(uiProperties.progressBarPos.add(windowOffset)) + .setSize(uiProperties.progressBarSize)); + } + + public void addGregTechLogo(ModularWindow.Builder builder, Pos2d windowOffset) { + builder.widget( + new DrawableWidget().setDrawable(uiProperties.logo) + .setSize(uiProperties.logoSize) + .setPos(uiProperties.logoPos.add(windowOffset))); + } + + /** + * Overriding this method allows custom NEI stack placement + */ + public List<Pos2d> getItemInputPositions(int itemInputCount) { + return UIHelper.getItemInputPositions(itemInputCount); + } + + /** + * Overriding this method allows custom NEI stack placement + */ + public List<Pos2d> getItemOutputPositions(int itemOutputCount) { + return UIHelper.getItemOutputPositions(itemOutputCount); + } + + /** + * Overriding this method allows custom NEI stack placement + */ + public Pos2d getSpecialItemPosition() { + return UIHelper.getSpecialItemPosition(); + } + + /** + * Overriding this method allows custom NEI stack placement + */ + public List<Pos2d> getFluidInputPositions(int fluidInputCount) { + return UIHelper.getFluidInputPositions(fluidInputCount); + } + + /** + * Overriding this method allows custom NEI stack placement + */ + public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { + return UIHelper.getFluidOutputPositions(fluidOutputCount); + } + + public void drawDescription(RecipeDisplayInfo recipeInfo) { + drawEnergyInfo(recipeInfo); + drawDurationInfo(recipeInfo); + drawSpecialInfo(recipeInfo); + drawMetadataInfo(recipeInfo); + drawRecipeOwnerInfo(recipeInfo); + } + + protected void drawEnergyInfo(RecipeDisplayInfo recipeInfo) { + recipeInfo.overclockDescriber.drawEnergyInfo(recipeInfo); + } + + protected void drawDurationInfo(RecipeDisplayInfo recipeInfo) { + recipeInfo.overclockDescriber.drawDurationInfo(recipeInfo); + } + + protected void drawSpecialInfo(RecipeDisplayInfo recipeInfo) { + String[] recipeDesc = recipeInfo.recipe.getNeiDesc(); + if (recipeDesc != null) { + for (String s : recipeDesc) { + recipeInfo.drawText(s); + } + } else { + recipeInfo.drawTextMultipleLines(neiProperties.neiSpecialInfoFormatter.format(recipeInfo)); + } + } + + protected void drawMetadataInfo(RecipeDisplayInfo recipeInfo) { + IRecipeMetadataStorage metadataStorage = recipeInfo.recipe.getMetadataStorage(); + for (Map.Entry<RecipeMetadataKey<?>, Object> entry : metadataStorage.getEntries()) { + entry.getKey() + .drawInfo(recipeInfo, entry.getValue()); + } + } + + protected void drawRecipeOwnerInfo(RecipeDisplayInfo recipeInfo) { + GT_Recipe recipe = recipeInfo.recipe; + if (GT_Mod.gregtechproxy.mNEIRecipeOwner) { + if (recipe.owners.size() > 1) { + recipeInfo.drawText( + EnumChatFormatting.ITALIC + trans("273", "Original Recipe by: ") + + recipe.owners.get(0) + .getName()); + for (int i = 1; i < recipe.owners.size(); i++) { + recipeInfo.drawText( + EnumChatFormatting.ITALIC + trans("274", "Modified by: ") + + recipe.owners.get(i) + .getName()); + } + } else if (!recipe.owners.isEmpty()) { + recipeInfo.drawText( + EnumChatFormatting.ITALIC + trans("272", "Recipe by: ") + + recipe.owners.get(0) + .getName()); + } + } + if (GT_Mod.gregtechproxy.mNEIRecipeOwnerStackTrace && recipe.stackTraces != null + && !recipe.stackTraces.isEmpty()) { + recipeInfo.drawText("stackTrace:"); + // todo: good way to show all stacktraces + for (String stackTrace : recipe.stackTraces.get(0)) { + recipeInfo.drawText(stackTrace); + } + } + } + + public List<String> handleNEIItemTooltip(ItemStack stack, List<String> currentTip, + GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) { + for (PositionedStack pStack : neiCachedRecipe.mInputs) { + if (stack == pStack.item) { + if (pStack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { + currentTip = handleNEIItemInputTooltip( + currentTip, + (GT_NEI_DefaultHandler.FixedPositionedStack) pStack); + } + break; + } + } + for (PositionedStack pStack : neiCachedRecipe.mOutputs) { + if (stack == pStack.item) { + if (pStack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { + currentTip = handleNEIItemOutputTooltip( + currentTip, + (GT_NEI_DefaultHandler.FixedPositionedStack) pStack); + } + break; + } + } + return currentTip; + } + + protected List<String> handleNEIItemInputTooltip(List<String> currentTip, + GT_NEI_DefaultHandler.FixedPositionedStack pStack) { + if (pStack.isNotConsumed()) { + currentTip.add(GRAY + trans("151", "Does not get consumed in the process")); + } + return currentTip; + } + + protected List<String> handleNEIItemOutputTooltip(List<String> currentTip, + GT_NEI_DefaultHandler.FixedPositionedStack pStack) { + if (pStack.isChanceBased()) { + currentTip.add(GRAY + trans("150", "Chance: ") + pStack.getChanceText()); + } + return currentTip; + } + + public void drawNEIOverlays(GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) { + for (PositionedStack stack : neiCachedRecipe.mInputs) { + if (stack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { + drawNEIOverlayForInput((GT_NEI_DefaultHandler.FixedPositionedStack) stack); + } + } + for (PositionedStack stack : neiCachedRecipe.mOutputs) { + if (stack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { + drawNEIOverlayForOutput((GT_NEI_DefaultHandler.FixedPositionedStack) stack); + } + } + } + + protected void drawNEIOverlayForInput(GT_NEI_DefaultHandler.FixedPositionedStack stack) { + if (stack.isNotConsumed()) { + drawNEIOverlayText("NC", stack); + } + } + + protected void drawNEIOverlayForOutput(GT_NEI_DefaultHandler.FixedPositionedStack stack) { + if (stack.isChanceBased()) { + drawNEIOverlayText(stack.getChanceText(), stack); + } + } + + @SuppressWarnings("SameParameterValue") + protected void drawNEIOverlayText(String text, PositionedStack stack, int color, float scale, boolean shadow, + Alignment alignment) { + FontRenderer fontRenderer = net.minecraft.client.Minecraft.getMinecraft().fontRenderer; + int width = fontRenderer.getStringWidth(text); + int x = (int) ((stack.relx + 8 + 8 * alignment.x) / scale) - (width / 2 * (alignment.x + 1)); + int y = (int) ((stack.rely + 8 + 8 * alignment.y) / scale) - (fontRenderer.FONT_HEIGHT / 2 * (alignment.y + 1)) + - (alignment.y - 1) / 2; + + GlStateManager.pushMatrix(); + GlStateManager.scale(scale, scale, 1); + fontRenderer.drawString(text, x, y, color, shadow); + GlStateManager.popMatrix(); + } + + protected void drawNEIOverlayText(String text, PositionedStack stack) { + drawNEIOverlayText( + text, + stack, + colorOverride.getTextColorOrDefault("nei_overlay_yellow", 0xFDD835), + 0.5f, + false, + Alignment.TopLeft); + } + + public static List<Supplier<Float>> splitProgress(Supplier<Float> progress, int... progressbarLengthArray) { + float lengthSum = IntStream.of(progressbarLengthArray) + .sum(); + List<Supplier<Float>> ret = new ArrayList<>(); + float currentLengthSum = 0; + for (int progressbarLength : progressbarLengthArray) { + float speed = lengthSum / progressbarLength; + float offset = currentLengthSum / lengthSum; + ret.add(() -> { + float current = progress.get(); + return (current - offset) * speed; + }); + currentLengthSum += progressbarLength; + } + return ret; + } + + @FunctionalInterface + public interface FrontendCreator { + + /** + * @see RecipeMapFrontend#RecipeMapFrontend + */ + RecipeMapFrontend create(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder); + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMaps.java b/src/main/java/gregtech/api/recipe/RecipeMaps.java new file mode 100644 index 0000000000..f11466a426 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMaps.java @@ -0,0 +1,1177 @@ +package gregtech.api.recipe; + +import static gregtech.api.enums.Mods.*; +import static gregtech.api.util.GT_RecipeConstants.ADDITIVE_AMOUNT; +import static gregtech.api.util.GT_RecipeConstants.FUEL_VALUE; +import static gregtech.api.util.GT_RecipeMapUtil.*; +import static gregtech.api.util.GT_Utility.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Optional; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import org.apache.commons.lang3.ArrayUtils; + +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IRecipeMap; +import gregtech.api.objects.ItemData; +import gregtech.api.recipe.maps.AssemblerBackend; +import gregtech.api.recipe.maps.AssemblyLineFrontend; +import gregtech.api.recipe.maps.DistillationTowerFrontend; +import gregtech.api.recipe.maps.FluidCannerBackend; +import gregtech.api.recipe.maps.FluidOnlyFrontend; +import gregtech.api.recipe.maps.FormingPressBackend; +import gregtech.api.recipe.maps.FuelBackend; +import gregtech.api.recipe.maps.FurnaceBackend; +import gregtech.api.recipe.maps.LargeBoilerFuelBackend; +import gregtech.api.recipe.maps.LargeBoilerFuelFrontend; +import gregtech.api.recipe.maps.LargeNEIFrontend; +import gregtech.api.recipe.maps.MicrowaveBackend; +import gregtech.api.recipe.maps.OilCrackerBackend; +import gregtech.api.recipe.maps.PrinterBackend; +import gregtech.api.recipe.maps.RecyclerBackend; +import gregtech.api.recipe.maps.ReplicatorBackend; +import gregtech.api.recipe.maps.SpaceProjectFrontend; +import gregtech.api.recipe.maps.TranscendentPlasmaMixerFrontend; +import gregtech.api.recipe.maps.UnpackagerBackend; +import gregtech.api.recipe.metadata.PCBFactoryTierKey; +import gregtech.api.util.GT_Config; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeConstants; +import gregtech.api.util.GT_RecipeMapUtil; +import gregtech.api.util.GT_Utility; +import gregtech.nei.formatter.FuelSpecialValueFormatter; +import gregtech.nei.formatter.FusionSpecialValueFormatter; +import gregtech.nei.formatter.HeatingCoilSpecialValueFormatter; +import gregtech.nei.formatter.SimpleSpecialValueFormatter; +import mods.railcraft.common.blocks.aesthetics.cube.EnumCube; +import mods.railcraft.common.items.RailcraftToolItems; + +@SuppressWarnings("SimplifyOptionalCallChains") +public final class RecipeMaps { + + public static final RecipeMap<RecipeMapBackend> oreWasherRecipes = RecipeMapBuilder.of("gt.recipe.orewasher") + .maxIO(1, 3, 1, 0) + .minInputs(1, 1) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isFluid) { + return null; + } + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_DUST; + } else { + return GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE; + } + }) + .progressBar(GT_UITextures.PROGRESSBAR_BATH, ProgressBar.Direction.CIRCULAR_CW) + .recipeConfigFile("orewasher", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> thermalCentrifugeRecipes = RecipeMapBuilder + .of("gt.recipe.thermalcentrifuge") + .maxIO(1, 3, 0, 0) + .minInputs(1, 0) + .amperage(2) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isFluid) { + return null; + } + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_DUST; + } else { + return GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE; + } + }) + .recipeConfigFile("thermalcentrifuge", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> compressorRecipes = RecipeMapBuilder.of("gt.recipe.compressor") + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_COMPRESSOR + : null) + .progressBar(GT_UITextures.PROGRESSBAR_COMPRESS) + .slotOverlaysSteam( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_COMPRESSOR_STEAM + : null) + .progressBarSteam(GT_UITextures.PROGRESSBAR_COMPRESS_STEAM) + // Avoid steam machine being used as handler icon + .neiHandlerInfo(builder -> builder.setDisplayStack(ItemList.Machine_LV_Compressor.get(1))) + .recipeConfigFile("compressor", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> extractorRecipes = RecipeMapBuilder.of("gt.recipe.extractor") + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CENTRIFUGE + : null) + .progressBar(GT_UITextures.PROGRESSBAR_EXTRACT) + .slotOverlaysSteam( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CENTRIFUGE_STEAM + : null) + .progressBarSteam(GT_UITextures.PROGRESSBAR_EXTRACT_STEAM) + // Avoid steam machine being used as handler icon + .neiHandlerInfo(builder -> builder.setDisplayStack(ItemList.Machine_LV_Extractor.get(1))) + .recipeConfigFile("extractor", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecyclerBackend> recyclerRecipes = RecipeMapBuilder + .of("ic.recipe.recycler", RecyclerBackend::new) + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_RECYCLE : null) + .progressBar(GT_UITextures.PROGRESSBAR_RECYCLE, ProgressBar.Direction.CIRCULAR_CW) + .neiTransferRectId("ic2.recycler") + .disableRegisterNEI() + .build(); + public static final RecipeMap<FurnaceBackend> furnaceRecipes = RecipeMapBuilder + .of("mc.recipe.furnace", FurnaceBackend::new) + .maxIO(1, 1, 0, 0) + .minInputs(1, 9) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_FURNACE : null) + .slotOverlaysSteam( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_FURNACE_STEAM + : null) + .progressBarSteam(GT_UITextures.PROGRESSBAR_ARROW_STEAM) + .neiTransferRectId("smelting") + .disableRegisterNEI() + .build(); + public static final RecipeMap<MicrowaveBackend> microwaveRecipes = RecipeMapBuilder + .of("gt.recipe.microwave", MicrowaveBackend::new) + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_FURNACE : null) + .neiTransferRectId("smelting") + .disableRegisterNEI() + .build(); + public static final RecipeMap<RecipeMapBackend> scannerFakeRecipes = RecipeMapBuilder.of("gt.recipe.scanner") + .maxIO(1, 1, 1, 0) + .minInputs(1, 0) + .useSpecialSlot() + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isSpecial) { + return GT_UITextures.OVERLAY_SLOT_DATA_ORB; + } + if (!isFluid && !isOutput) { + return GT_UITextures.OVERLAY_SLOT_MICROSCOPE; + } + return null; + }) + .build(); + public static final RecipeMap<RecipeMapBackend> rockBreakerFakeRecipes = RecipeMapBuilder + .of("gt.recipe.rockbreaker") + .maxIO(2, 1, 0, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE; + } else { + return GT_UITextures.OVERLAY_SLOT_DUST; + } + }) + .progressBar(GT_UITextures.PROGRESSBAR_MACERATE) + .build(); + public static final RecipeMap<ReplicatorBackend> replicatorRecipes = RecipeMapBuilder + .of("gt.recipe.replicator", ReplicatorBackend::new) + .maxIO(0, 1, 1, 1) + .minInputs(0, 1) + .useSpecialSlot() + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isSpecial) { + return GT_UITextures.OVERLAY_SLOT_DATA_ORB; + } + if (isFluid && !isOutput) { + return GT_UITextures.OVERLAY_SLOT_UUM; + } + return null; + }) + .build(); + /** + * Use {@link GT_RecipeConstants#AssemblyLine} for recipe addition. + */ + public static final RecipeMap<RecipeMapBackend> assemblylineVisualRecipes = RecipeMapBuilder + .of("gt.recipe.fakeAssemblylineProcess") + .maxIO(16, 1, 4, 0) + .minInputs(1, 0) + .useSpecialSlot() + .slotOverlays((index, isFluid, isOutput, isSpecial) -> isSpecial ? GT_UITextures.OVERLAY_SLOT_DATA_ORB : null) + .disableOptimize() + .neiTransferRect(88, 8, 18, 72) + .neiTransferRect(124, 8, 18, 72) + .neiTransferRect(142, 26, 18, 18) + .frontend(AssemblyLineFrontend::new) + .build(); + /** + * Usually, but not always, you should use {@link GT_RecipeConstants#UniversalArcFurnace} instead. + */ + public static final RecipeMap<RecipeMapBackend> plasmaArcFurnaceRecipes = RecipeMapBuilder + .of("gt.recipe.plasmaarcfurnace") + .maxIO(1, 9, 1, 1) + .minInputs(1, 1) + .recipeConfigFile("arcfurnace", FIRST_ITEM_INPUT) + .build(); + /** + * Usually, but not always, you should use {@link GT_RecipeConstants#UniversalArcFurnace} instead. + */ + public static final RecipeMap<RecipeMapBackend> arcFurnaceRecipes = RecipeMapBuilder.of("gt.recipe.arcfurnace") + .maxIO(1, 9, 1, 0) + .minInputs(1, 1) + .amperage(3) + .recipeConfigFile("arcfurnace", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<PrinterBackend> printerRecipes = RecipeMapBuilder + .of("gt.recipe.printer", PrinterBackend::new) + .maxIO(1, 1, 1, 0) + .minInputs(1, 1) + .useSpecialSlot() + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isSpecial) { + return GT_UITextures.OVERLAY_SLOT_DATA_STICK; + } + if (isFluid) { + return null; + } + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_PAGE_PRINTED; + } + return GT_UITextures.OVERLAY_SLOT_PAGE_BLANK; + }) + .recipeConfigFile("printer", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> sifterRecipes = RecipeMapBuilder.of("gt.recipe.sifter") + .maxIO(1, 9, 1, 1) + .progressBar(GT_UITextures.PROGRESSBAR_SIFT, ProgressBar.Direction.DOWN) + .recipeConfigFile("sifter", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<FormingPressBackend> formingPressRecipes = RecipeMapBuilder + .of("gt.recipe.press", FormingPressBackend::new) + .maxIO(6, 1, 0, 0) + .minInputs(2, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_PRESS_3; + } + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_PRESS_1; + } + return GT_UITextures.OVERLAY_SLOT_PRESS_2; + }) + .progressBar(GT_UITextures.PROGRESSBAR_COMPRESS) + .recipeConfigFile("press", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> laserEngraverRecipes = RecipeMapBuilder + .of("gt.recipe.laserengraver") + .maxIO(4, 4, 2, 2) + .slotOverlays( + (index, isFluid, isOutput, + isSpecial) -> !isFluid && !isOutput && index != 0 ? GT_UITextures.OVERLAY_SLOT_LENS : null) + .recipeConfigFile("laserengraving", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> mixerRecipes = RecipeMapBuilder.of("gt.recipe.mixer") + .maxIO(9, 4, 1, 1) + .minInputs(1, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> !isFluid ? GT_UITextures.OVERLAY_SLOT_DUST : null) + .progressBar(GT_UITextures.PROGRESSBAR_MIXER, ProgressBar.Direction.CIRCULAR_CW) + .recipeConfigFile("mixer", FIRST_ITEM_OR_FLUID_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> autoclaveRecipes = RecipeMapBuilder.of("gt.recipe.autoclave") + .maxIO(2, 4, 1, 1) + .minInputs(1, 1) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isFluid) { + return null; + } + if (isOutput) { + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_GEM; + } + return GT_UITextures.OVERLAY_SLOT_DUST; + } + return GT_UITextures.OVERLAY_SLOT_DUST; + }) + + .recipeConfigFile("autoclave", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> electroMagneticSeparatorRecipes = RecipeMapBuilder + .of("gt.recipe.electromagneticseparator") + .maxIO(1, 3, 0, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> isOutput ? GT_UITextures.OVERLAY_SLOT_DUST + : GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE) + .progressBar(GT_UITextures.PROGRESSBAR_MAGNET) + .recipeConfigFile("electromagneticseparator", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> polarizerRecipes = RecipeMapBuilder.of("gt.recipe.polarizer") + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .progressBar(GT_UITextures.PROGRESSBAR_MAGNET) + .recipeConfigFile("polarizer", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> maceratorRecipes = RecipeMapBuilder.of("gt.recipe.macerator") + .maxIO(1, 4, 0, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> isOutput ? GT_UITextures.OVERLAY_SLOT_DUST + : GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE) + .slotOverlaysSteam( + (index, isFluid, isOutput, isSpecial) -> isOutput ? GT_UITextures.OVERLAY_SLOT_DUST_STEAM + : GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE_STEAM) + .progressBar(GT_UITextures.PROGRESSBAR_MACERATE) + .progressBarSteam(GT_UITextures.PROGRESSBAR_MACERATE_STEAM) + // Avoid steam machine being used as handler icon + .neiHandlerInfo(builder -> builder.setDisplayStack(ItemList.Machine_LV_Macerator.get(1))) + .recipeConfigFile("pulveriser", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> chemicalBathRecipes = RecipeMapBuilder.of("gt.recipe.chemicalbath") + .maxIO(1, 3, 1, 1) + .minInputs(1, 1) + .progressBar(GT_UITextures.PROGRESSBAR_BATH, ProgressBar.Direction.CIRCULAR_CW) + .recipeConfigFile("chemicalbath", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<FluidCannerBackend> fluidCannerRecipes = RecipeMapBuilder + .of("gt.recipe.fluidcanner", FluidCannerBackend::new) + .maxIO(1, 1, 1, 1) + .minInputs(1, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> !isFluid ? GT_UITextures.OVERLAY_SLOT_CANISTER : null) + .progressBar(GT_UITextures.PROGRESSBAR_CANNER) + .recipeConfigFile("canning", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> brewingRecipes = RecipeMapBuilder.of("gt.recipe.brewer") + .maxIO(1, 0, 1, 1) + .minInputs(1, 1) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CAULDRON : null) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .recipeConfigFile("brewing", FIRST_FLUIDSTACK_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> fluidHeaterRecipes = RecipeMapBuilder.of("gt.recipe.fluidheater") + .maxIO(1, 0, 1, 1) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (!isFluid) { + return null; + } + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_HEATER_2; + } + return GT_UITextures.OVERLAY_SLOT_HEATER_1; + }) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .recipeConfigFile("fluidheater", FIRST_FLUIDSTACK_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> distilleryRecipes = RecipeMapBuilder.of("gt.recipe.distillery") + .maxIO(1, 1, 1, 1) + .minInputs(1, 1) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (!isFluid) { + return null; + } + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_BEAKER_2; + } + return GT_UITextures.OVERLAY_SLOT_BEAKER_1; + }) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .recipeTransformer(r -> { + int aInput = r.mFluidInputs[0].amount, aOutput = r.mFluidOutputs[0].amount, aDuration = r.mDuration; + + // reduce the batch size if fluid amount is exceeding + int tScale = (Math.max(aInput, aOutput) + 999) / 1000; + if (tScale <= 0) tScale = 1; + if (tScale > 1) { + // trying to find whether there is a better factor + for (int i = tScale; i <= 5; i++) { + if (aInput % i == 0 && aDuration % i == 0) { + tScale = i; + break; + } + } + for (int i = tScale; i <= 5; i++) { + if (aInput % i == 0 && aDuration % i == 0 && aOutput % i == 0) { + tScale = i; + break; + } + } + aInput = (aInput + tScale - 1) / tScale; + aOutput = aOutput / tScale; + if (!isArrayEmptyOrNull(r.mOutputs)) { + ItemData tData = GT_OreDictUnificator.getItemData(r.mOutputs[0]); + if (tData != null && (tData.mPrefix == OrePrefixes.dust + || OrePrefixes.dust.mFamiliarPrefixes.contains(tData.mPrefix))) { + r.mOutputs[0] = GT_OreDictUnificator.getDust( + tData.mMaterial.mMaterial, + tData.mMaterial.mAmount * r.mOutputs[0].stackSize / tScale); + } else { + if (r.mOutputs[0].stackSize / tScale == 0) r.mOutputs[0] = GT_Values.NI; + else r.mOutputs[0] = copyAmount(r.mOutputs[0].stackSize / tScale, r.mOutputs[0]); + } + } + aDuration = (aDuration + tScale - 1) / tScale; + r.mFluidInputs[0] = copyAmount(aInput, r.mFluidInputs[0]); + r.mFluidOutputs[0] = copyAmount(aOutput, r.mFluidOutputs[0]); + r.mDuration = aDuration; + } + }) + .recipeConfigFile("distillery", FIRST_FLUIDSTACK_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> fermentingRecipes = RecipeMapBuilder.of("gt.recipe.fermenter") + .maxIO(0, 0, 1, 1) + .minInputs(0, 1) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .recipeConfigFile("fermenting", FIRST_FLUIDSTACK_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> fluidSolidifierRecipes = RecipeMapBuilder + .of("gt.recipe.fluidsolidifier") + .maxIO(1, 1, 1, 0) + .minInputs(1, 1) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_MOLD : null) + .recipeTransformer(r -> { + if (ArrayUtils.isNotEmpty(r.mFluidInputs)) { + if (Materials.PhasedGold.getMolten(1) + .isFluidEqual(r.mFluidInputs[0])) + r.mFluidInputs = new FluidStack[] { Materials.VibrantAlloy.getMolten(r.mFluidInputs[0].amount) }; + else if (Materials.PhasedIron.getMolten(1) + .isFluidEqual(r.mFluidInputs[0])) + r.mFluidInputs = new FluidStack[] { Materials.PulsatingIron.getMolten(r.mFluidInputs[0].amount) }; + } + }) + .recipeConfigFile("fluidsolidifier", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> fluidExtractionRecipes = RecipeMapBuilder + .of("gt.recipe.fluidextractor") + .maxIO(1, 1, 0, 1) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CENTRIFUGE + : null) + .progressBar(GT_UITextures.PROGRESSBAR_EXTRACT) + .recipeTransformer(r -> { + if (ArrayUtils.isNotEmpty(r.mFluidInputs)) { + if (Materials.PhasedGold.getMolten(1) + .isFluidEqual(r.mFluidInputs[0])) + r.mFluidInputs = new FluidStack[] { Materials.VibrantAlloy.getMolten(r.mFluidInputs[0].amount) }; + else if (Materials.PhasedIron.getMolten(1) + .isFluidEqual(r.mFluidInputs[0])) + r.mFluidInputs = new FluidStack[] { Materials.PulsatingIron.getMolten(r.mFluidInputs[0].amount) }; + } + }) + .recipeConfigFile("fluidextractor", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> packagerRecipes = RecipeMapBuilder.of("gt.recipe.packager") + .maxIO(2, 1, 0, 0) + .minInputs(2, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_BOXED; + } + if (index != 0) { + return GT_UITextures.OVERLAY_SLOT_BOX; + } + return null; + }) + .recipeConfigFile("boxing", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<UnpackagerBackend> unpackagerRecipes = RecipeMapBuilder + .of("gt.recipe.unpackager", UnpackagerBackend::new) + .maxIO(1, 2, 0, 0) + .minInputs(1, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> !isOutput ? GT_UITextures.OVERLAY_SLOT_BOXED : null) + .recipeConfigFile("unboxing", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> fusionRecipes = RecipeMapBuilder.of("gt.recipe.fusionreactor") + .maxIO(0, 0, 2, 1) + .minInputs(0, 2) + .disableOptimize() + .useCustomFilterForNEI() + .neiSpecialInfoFormatter(FusionSpecialValueFormatter.INSTANCE) + .neiRecipeComparator( + Comparator + .<GT_Recipe, Integer>comparing( + recipe -> FusionSpecialValueFormatter.getFusionTier(recipe.mSpecialValue, recipe.mEUt)) + .thenComparing(GT_Recipe::compareTo)) + .frontend(FluidOnlyFrontend::new) + .recipeConfigFile("fusion", FIRST_FLUID_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> centrifugeRecipes = RecipeMapBuilder.of("gt.recipe.centrifuge") + .maxIO(2, 6, 1, 1) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + return null; + } + if (isFluid) { + return GT_UITextures.OVERLAY_SLOT_CENTRIFUGE_FLUID; + } else { + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_CENTRIFUGE; + } + return GT_UITextures.OVERLAY_SLOT_CANISTER; + } + }) + .progressBar(GT_UITextures.PROGRESSBAR_EXTRACT) + .recipeConfigFile("centrifuge", FIRST_ITEM_OR_FLUID_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> electrolyzerRecipes = RecipeMapBuilder.of("gt.recipe.electrolyzer") + .maxIO(2, 6, 1, 1) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + return null; + } + if (isFluid) { + return GT_UITextures.OVERLAY_SLOT_CHARGER_FLUID; + } else { + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_CHARGER; + } + return GT_UITextures.OVERLAY_SLOT_CANISTER; + } + }) + .progressBar(GT_UITextures.PROGRESSBAR_EXTRACT) + .recipeConfigFile("electrolyzer", FIRST_ITEM_OR_FLUID_INPUT) + .build(); + /** + * Use {@link GT_RecipeConstants#COIL_HEAT} as heat level. + */ + public static final RecipeMap<RecipeMapBackend> blastFurnaceRecipes = RecipeMapBuilder.of("gt.recipe.blastfurnace") + .maxIO(6, 6, 1, 1) + .minInputs(1, 0) + .neiSpecialInfoFormatter(HeatingCoilSpecialValueFormatter.INSTANCE) + .recipeConfigFile("blastfurnace", FIRST_ITEM_INPUT) + .build(); + /** + * Use {@link GT_RecipeConstants#COIL_HEAT} as heat level. + */ + public static final RecipeMap<RecipeMapBackend> plasmaForgeRecipes = RecipeMapBuilder.of("gt.recipe.plasmaforge") + .maxIO(9, 9, 9, 9) + .disableOptimize() + .neiSpecialInfoFormatter(HeatingCoilSpecialValueFormatter.INSTANCE) + .neiHandlerInfo( + builder -> builder.setDisplayStack(ItemList.Machine_Multi_PlasmaForge.get(1)) + .setMaxRecipesPerPage(1)) + .frontend(LargeNEIFrontend::new) + .build(); + public static final RecipeMap<RecipeMapBackend> transcendentPlasmaMixerRecipes = RecipeMapBuilder + .of("gt.recipe.transcendentplasmamixerrecipes") + .maxIO(1, 0, 20, 1) + .progressBarPos(86, 44) + .logoPos(87, 99) + .neiRecipeBackgroundSize(170, 118) + .neiHandlerInfo( + builder -> builder.setDisplayStack(ItemList.Machine_Multi_TranscendentPlasmaMixer.get(1)) + .setMaxRecipesPerPage(1)) + .frontend(TranscendentPlasmaMixerFrontend::new) + .disableOptimize() + .build(); + public static final RecipeMap<RecipeMapBackend> spaceProjectFakeRecipes = RecipeMapBuilder + .of("gt.recipe.fakespaceprojects") + .maxIO(12, 0, 4, 0) + .neiSpecialInfoFormatter(new SimpleSpecialValueFormatter("GT5U.nei.stages")) + .neiRecipeBackgroundOffset(3, 23) + .logo(UITexture.fullImage(GTNHIntergalactic.ID, "gui/picture/space_elevator_logo.png")) + .logoSize(18, 18) + .logoPos(152, 83) + .neiTransferRect(70, 28, 18, 72) + .neiTransferRect(106, 28, 18, 72) + .frontend(SpaceProjectFrontend::new) + .disableRenderRealStackSizes() + .disableOptimize() + .build(); + /** + * Uses {@link GT_RecipeConstants#ADDITIVE_AMOUNT} for coal/charcoal amount. + */ + public static final RecipeMap<RecipeMapBackend> primitiveBlastRecipes = RecipeMapBuilder + .of("gt.recipe.primitiveblastfurnace") + .maxIO(3, 3, 0, 0) + .minInputs(1, 0) + .recipeEmitter(builder -> { + Optional<GT_Recipe> rr = builder.eut(0) + .validateInputCount(1, 2) + .validateOutputCount(1, 2) + .validateNoInputFluid() + .validateNoOutputFluid() + .noOptimize() + .build(); + if (!rr.isPresent()) return Collections.emptyList(); + ItemStack aInput1 = builder.getItemInputBasic(0); + ItemStack aInput2 = builder.getItemInputBasic(1); + ItemStack aOutput1 = builder.getItemOutput(0); + ItemStack aOutput2 = builder.getItemOutput(1); + if ((aInput1 == null && aInput2 == null) || (aOutput1 == null && aOutput2 == null)) + return Collections.emptyList(); + int aCoalAmount = builder.getMetadataOrDefault(ADDITIVE_AMOUNT, 0); + if (aCoalAmount <= 0) return Collections.emptyList(); + GT_RecipeTemplate coll = asTemplate(rr.get()); + for (Materials coal : new Materials[] { Materials.Coal, Materials.Charcoal }) { + coll.derive() + .setInputs(aInput1, aInput2, coal.getGems(aCoalAmount)) + .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDustTiny(aCoalAmount)); + coll.derive() + .setInputs(aInput1, aInput2, coal.getDust(aCoalAmount)) + .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDustTiny(aCoalAmount)); + } + int aDuration = builder.getDuration(); + if (Railcraft.isModLoaded()) { + coll.derive() + .setInputs(aInput1, aInput2, RailcraftToolItems.getCoalCoke(aCoalAmount / 2)) + .setOutputs(aOutput1, aOutput2, Materials.Ash.getDustTiny(aCoalAmount / 2)) + .setDuration(aDuration * 2 / 3); + } + if (GTPlusPlus.isModLoaded()) { + ItemStack cactusCoke = GT_ModHandler.getModItem(GTPlusPlus.ID, "itemCactusCoke", aCoalAmount * 2L); + ItemStack sugarCoke = GT_ModHandler.getModItem(GTPlusPlus.ID, "itemSugarCoke", aCoalAmount * 2L); + coll.derive() + .setInputs(aInput1, aInput2, cactusCoke) + .setOutputs(aOutput1, aOutput2, Materials.Ash.getDustTiny(aCoalAmount * 2)) + .setDuration(aDuration * 2 / 3); + coll.derive() + .setInputs(aInput1, aInput2, sugarCoke) + .setOutputs(aOutput1, aOutput2, Materials.Ash.getDustTiny(aCoalAmount * 2)) + .setDuration(aDuration * 2 / 3); + } + if ((aInput1 == null || aInput1.stackSize <= 6) && (aInput2 == null || aInput2.stackSize <= 6) + && (aOutput1 == null || aOutput1.stackSize <= 6) + && (aOutput2 == null || aOutput2.stackSize <= 6)) { + // we don't use GT_Utility.mul() here. It does not have the truncating we need here. + aInput1 = multiplyStack(10, aInput1); + aInput2 = multiplyStack(10, aInput2); + aOutput1 = multiplyStack(10, aOutput1); + aOutput2 = multiplyStack(10, aOutput2); + for (Materials coal : new Materials[] { Materials.Coal, Materials.Charcoal }) { + coll.derive() + .setInputs(aInput1, aInput2, coal.getBlocks(aCoalAmount)) + .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDust(aCoalAmount)) + .setDuration(aDuration * 10); + coll.derive() + .setInputs(aInput1, aInput2, coal.getBlocks(aCoalAmount)) + .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDust(aCoalAmount)) + .setDuration(aDuration * 10); + } + if (Railcraft.isModLoaded()) { + coll.derive() + .setInputs(aInput1, aInput2, EnumCube.COKE_BLOCK.getItem(aCoalAmount / 2)) + .setOutputs(aOutput1, aOutput2, Materials.Ash.getDust(aCoalAmount / 2)) + .setDuration(aDuration * 20 / 3); + } + } + return coll.getAll(); + }) + .recipeConfigFile("primitiveblastfurnace", FIRST_ITEM_INPUT) + .build(); + /** + * Uses {@link GT_RecipeConstants#ADDITIVE_AMOUNT} for TNT/ITNT/... amount. Value is truncated to [0, 64] + */ + public static final RecipeMap<RecipeMapBackend> implosionRecipes = RecipeMapBuilder + .of("gt.recipe.implosioncompressor") + .maxIO(2, 2, 0, 0) + .minInputs(2, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (!isFluid && !isOutput) { + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_IMPLOSION; + } + return GT_UITextures.OVERLAY_SLOT_EXPLOSIVE; + } + return null; + }) + .progressBar(GT_UITextures.PROGRESSBAR_COMPRESS) + .disableOptimize() + .recipeEmitter(b -> { + switch (b.getItemInputsBasic().length) { + case 0: + return Collections.emptyList(); + case 1: + break; + default: + return b.build() + .map(Collections::singletonList) + .orElse(Collections.emptyList()); + } + Optional<GT_Recipe> t = b.noOptimize() + .duration(20) + .eut(30) + .validateInputCount(1, 1) + .validateOutputCount(1, 2) + .build(); + if (!t.isPresent()) return Collections.emptyList(); + ItemStack input = b.getItemInputBasic(0); + GT_RecipeTemplate coll = asTemplate(t.get()); + int tExplosives = Math.min(b.getMetadataOrDefault(ADDITIVE_AMOUNT, 0), 64); + int tGunpowder = tExplosives << 1; // Worst + int tDynamite = Math.max(1, tExplosives >> 1); // good + @SuppressWarnings("UnnecessaryLocalVariable") + int tTNT = tExplosives; // Slightly better + int tITNT = Math.max(1, tExplosives >> 2); // the best + if (tGunpowder < 65) coll.derive() + .setInputs(input, ItemList.Block_Powderbarrel.get(tGunpowder)); + if (tDynamite < 17) coll.derive() + .setInputs(input, GT_ModHandler.getIC2Item("dynamite", tDynamite, null)); + coll.derive() + .setInputs(input, new ItemStack(Blocks.tnt, tTNT)); + coll.derive() + .setInputs(input, GT_ModHandler.getIC2Item("industrialTnt", tITNT, null)); + return coll.getAll(); + }) + .recipeConfigFile("implosion", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> vacuumFreezerRecipes = RecipeMapBuilder + .of("gt.recipe.vacuumfreezer") + .maxIO(1, 1, 2, 1) + .recipeEmitter(b -> { + b.noOptimize(); + FluidStack in, out; + if (isArrayOfLength(b.getItemInputsBasic(), 1) && isArrayOfLength(b.getItemOutputs(), 1) + && isArrayEmptyOrNull(b.getFluidInputs()) + && isArrayEmptyOrNull(b.getFluidOutputs()) + && (in = getFluidForFilledItem(b.getItemInputBasic(0), true)) != null + && (out = getFluidForFilledItem(b.getItemOutput(0), true)) != null) { + Collection<GT_Recipe> ret = new ArrayList<>(); + b.build() + .ifPresent(ret::add); + b.itemInputs() + .itemOutputs() + .fluidInputs(in) + .fluidOutputs(out) + .build() + .ifPresent(ret::add); + return ret; + } + return buildOrEmpty(b); + }) + .recipeConfigFile("vacuumfreezer", FIRST_ITEM_INPUT) + .build(); + /** + * Using {@code .addTo(chemicalReactorRecipes)} will cause the recipe to be added to single block recipe map ONLY! + * Use {@link GT_RecipeConstants#UniversalChemical} to add to both. + */ + public static final RecipeMap<RecipeMapBackend> chemicalReactorRecipes = RecipeMapBuilder + .of("gt.recipe.chemicalreactor") + .maxIO(2, 2, 1, 1) + .minInputs(1, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isFluid) { + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_VIAL_2; + } + return GT_UITextures.OVERLAY_SLOT_MOLECULAR_3; + } else { + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_VIAL_1; + } + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_MOLECULAR_1; + } + return GT_UITextures.OVERLAY_SLOT_MOLECULAR_2; + } + }) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .disableOptimize() + .recipeConfigFile("chemicalreactor", FIRST_ITEM_OR_FLUID_OUTPUT) + .build(); + /** + * Using {@code .addTo(multiblockChemicalReactorRecipes)} will cause the recipe to be added to + * multiblock recipe map ONLY! Use {@link GT_RecipeConstants#UniversalChemical} to add to both. + */ + public static final RecipeMap<RecipeMapBackend> multiblockChemicalReactorRecipes = RecipeMapBuilder + .of("gt.recipe.largechemicalreactor") + .maxIO(6, 6, 6, 6) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .disableOptimize() + .frontend(LargeNEIFrontend::new) + .build(); + public static final RecipeMap<RecipeMapBackend> distillationTowerRecipes = RecipeMapBuilder + .of("gt.recipe.distillationtower") + .maxIO(2, 1, 1, 11) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (!isOutput) { + return null; + } + if (isFluid) { + return GT_UITextures.OVERLAY_SLOTS_NUMBER[index + 1]; + } else { + return GT_UITextures.OVERLAY_SLOTS_NUMBER[0]; + } + }) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .logoPos(80, 62) + .frontend(DistillationTowerFrontend::new) + .disableOptimize() + .recipeConfigFile("distillation", FIRST_FLUIDSTACK_INPUT) + .build(); + public static final RecipeMap<OilCrackerBackend> crackingRecipes = RecipeMapBuilder + .of("gt.recipe.craker", OilCrackerBackend::new) + .maxIO(1, 1, 2, 1) + .minInputs(1, 2) + .progressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE) + .recipeConfigFile("cracking", FIRST_FLUIDSTACK_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> pyrolyseRecipes = RecipeMapBuilder.of("gt.recipe.pyro") + .maxIO(2, 1, 1, 1) + .minInputs(1, 0) + .disableOptimize() + .recipeConfigFile("pyrolyse", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> wiremillRecipes = RecipeMapBuilder.of("gt.recipe.wiremill") + .maxIO(2, 1, 0, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_WIREMILL : null) + .progressBar(GT_UITextures.PROGRESSBAR_WIREMILL) + .recipeConfigFile("wiremill", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> benderRecipes = RecipeMapBuilder.of("gt.recipe.metalbender") + .maxIO(2, 1, 0, 0) + .minInputs(2, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_BENDER : null) + .progressBar(GT_UITextures.PROGRESSBAR_BENDING) + .recipeConfigFile("bender", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> alloySmelterRecipes = RecipeMapBuilder.of("gt.recipe.alloysmelter") + .maxIO(2, 1, 0, 0) + .minInputs(2, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_FURNACE : null) + .slotOverlaysSteam((index, isFluid, isOutput, isSpecial) -> GT_UITextures.OVERLAY_SLOT_FURNACE_STEAM) + .progressBarSteam(GT_UITextures.PROGRESSBAR_ARROW_STEAM) + .recipeEmitter(b -> { + if (Materials.Graphite.contains(b.getItemInputBasic(0))) return Collections.emptyList(); + if (GT_Utility.isArrayOfLength(b.getItemInputsBasic(), 1)) { + ItemStack aInput1 = b.getItemInputBasic(0); + if (((OrePrefixes.ingot.contains(aInput1)) || (OrePrefixes.dust.contains(aInput1)) + || (OrePrefixes.gem.contains(aInput1)))) return Collections.emptyList(); + } + return buildOrEmpty( + b.validateNoInputFluid() + .validateNoOutputFluid() + .validateInputCount(1, 2) + .validateOutputCount(1, 1)); + }) + // Avoid steam machine being used as handler icon + .neiHandlerInfo(builder -> builder.setDisplayStack(ItemList.Machine_LV_AlloySmelter.get(1))) + .recipeConfigFile( + "alloysmelting", + r -> GT_Config.getStackConfigName(GT_Utility.isArrayOfLength(r.mInputs, 1) ? r.mInputs[0] : r.mOutputs[0])) + .build(); + public static final RecipeMap<AssemblerBackend> assemblerRecipes = RecipeMapBuilder + .of("gt.recipe.assembler", AssemblerBackend::new) + .maxIO(9, 1, 1, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CIRCUIT : null) + .progressBar(GT_UITextures.PROGRESSBAR_ASSEMBLE) + .disableOptimize() + .recipeConfigFile("assembling", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> circuitAssemblerRecipes = RecipeMapBuilder + .of("gt.recipe.circuitassembler") + .maxIO(6, 1, 1, 0) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_CIRCUIT : null) + .progressBar(GT_UITextures.PROGRESSBAR_CIRCUIT_ASSEMBLER) + .unificateOutputNEI(!NEICustomDiagrams.isModLoaded()) + .recipeConfigFile("circuitassembler", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> cannerRecipes = RecipeMapBuilder.of("gt.recipe.canner") + .maxIO(2, 2, 0, 0) + .minInputs(1, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + return null; + } + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_CANNER; + } + return GT_UITextures.OVERLAY_SLOT_CANISTER; + }) + .progressBar(GT_UITextures.PROGRESSBAR_CANNER) + .recipeConfigFile("canning", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> latheRecipes = RecipeMapBuilder.of("gt.recipe.lathe") + .maxIO(1, 2, 0, 0) + .minInputs(1, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_ROD_2; + } + return GT_UITextures.OVERLAY_SLOT_DUST; + } + return GT_UITextures.OVERLAY_SLOT_ROD_1; + }) + .progressBar(GT_UITextures.PROGRESSBAR_LATHE) + .addSpecialTexture(98, 24, 5, 18, GT_UITextures.PROGRESSBAR_LATHE_BASE) + .recipeConfigFile("lathe", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> cutterRecipes = RecipeMapBuilder.of("gt.recipe.cuttingsaw") + .maxIO(2, 4, 1, 0) + .minInputs(1, 1) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isFluid) { + return null; + } + if (isOutput) { + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_CUTTER_SLICED; + } + return GT_UITextures.OVERLAY_SLOT_DUST; + } + return GT_UITextures.OVERLAY_SLOT_BOX; + }) + .progressBar(GT_UITextures.PROGRESSBAR_CUT) + .recipeEmitter(b -> { + b.validateInputCount(1, 2) + .validateOutputCount(1, 4) + .validateNoOutputFluid(); + if ((b.getFluidInputs() != null && b.getFluidInputs().length > 0) || !b.isValid()) + return buildOrEmpty(b.validateInputFluidCount(1, 1)); + int aDuration = b.getDuration(), aEUt = b.getEUt(); + Collection<GT_Recipe> ret = new ArrayList<>(); + b.copy() + .fluidInputs(Materials.Water.getFluid(clamp(aDuration * aEUt / 320, 4, 1000))) + .duration(aDuration * 2) + .build() + .ifPresent(ret::add); + b.copy() + .fluidInputs(GT_ModHandler.getDistilledWater(clamp(aDuration * aEUt / 426, 3, 750))) + .duration(aDuration * 2) + .build() + .ifPresent(ret::add); + b.fluidInputs(Materials.Lubricant.getFluid(clamp(aDuration * aEUt / 1280, 1, 250))) + .duration(aDuration) + .build() + .ifPresent(ret::add); + return ret; + }) + .recipeConfigFile("cutting", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> slicerRecipes = RecipeMapBuilder.of("gt.recipe.slicer") + .maxIO(2, 1, 0, 0) + .minInputs(2, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_SLICER_SLICED; + } + if (index == 0) { + return GT_UITextures.OVERLAY_SLOT_SQUARE; + } + return GT_UITextures.OVERLAY_SLOT_SLICE_SHAPE; + }) + .progressBar(GT_UITextures.PROGRESSBAR_SLICE) + .recipeConfigFile("slicer", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> extruderRecipes = RecipeMapBuilder.of("gt.recipe.extruder") + .maxIO(2, 1, 0, 0) + .minInputs(2, 0) + .slotOverlays( + (index, isFluid, isOutput, + isSpecial) -> !isFluid && !isOutput && index != 0 ? GT_UITextures.OVERLAY_SLOT_EXTRUDER_SHAPE : null) + .progressBar(GT_UITextures.PROGRESSBAR_EXTRUDE) + .recipeConfigFile("extruder", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> hammerRecipes = RecipeMapBuilder.of("gt.recipe.hammer") + .maxIO(2, 2, 2, 2) + .minInputs(1, 0) + .slotOverlays( + (index, isFluid, isOutput, isSpecial) -> !isFluid && !isOutput ? GT_UITextures.OVERLAY_SLOT_HAMMER : null) + .progressBar(GT_UITextures.PROGRESSBAR_HAMMER, ProgressBar.Direction.DOWN) + .addSpecialTexture(78, 42, 20, 6, GT_UITextures.PROGRESSBAR_HAMMER_BASE) + .slotOverlaysSteam( + (index, isFluid, isOutput, isSpecial) -> !isOutput ? GT_UITextures.OVERLAY_SLOT_HAMMER_STEAM : null) + .progressBarSteam(GT_UITextures.PROGRESSBAR_HAMMER_STEAM) + .addSpecialTextureSteam(78, 42, 20, 6, GT_UITextures.PROGRESSBAR_HAMMER_BASE_STEAM) + // Avoid steam machine being used as handler icon + .neiHandlerInfo(builder -> builder.setDisplayStack(ItemList.Machine_LV_Hammer.get(1))) + .recipeConfigFile("forgehammer", FIRST_ITEM_OUTPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> amplifierRecipes = RecipeMapBuilder.of("gt.recipe.uuamplifier") + .maxIO(1, 0, 0, 1) + .minInputs(1, 0) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (isFluid) { + return GT_UITextures.OVERLAY_SLOT_UUA; + } + if (!isOutput) { + return GT_UITextures.OVERLAY_SLOT_CENTRIFUGE; + } + return null; + }) + .progressBar(GT_UITextures.PROGRESSBAR_EXTRACT) + .recipeConfigFile("amplifier", FIRST_ITEM_INPUT) + .build(); + public static final RecipeMap<RecipeMapBackend> massFabFakeRecipes = RecipeMapBuilder.of("gt.recipe.massfab") + .maxIO(1, 0, 1, 1) + .minInputs(1, 0) + .amperage(8) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (!isFluid) { + return null; + } + if (isOutput) { + return GT_UITextures.OVERLAY_SLOT_UUM; + } + return GT_UITextures.OVERLAY_SLOT_UUA; + }) + .build(); + public static final RecipeMap<FuelBackend> dieselFuels = RecipeMapBuilder + .of("gt.recipe.dieselgeneratorfuel", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> extremeDieselFuels = RecipeMapBuilder + .of("gt.recipe.extremedieselgeneratorfuel", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> gasTurbineFuels = RecipeMapBuilder + .of("gt.recipe.gasturbinefuel", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> hotFuels = RecipeMapBuilder + .of("gt.recipe.thermalgeneratorfuel", FuelBackend::new) + .maxIO(1, 4, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> denseLiquidFuels = RecipeMapBuilder + .of("gt.recipe.semifluidboilerfuels", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> plasmaFuels = RecipeMapBuilder + .of("gt.recipe.plasmageneratorfuels", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> magicFuels = RecipeMapBuilder + .of("gt.recipe.magicfuels", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> smallNaquadahReactorFuels = RecipeMapBuilder + .of("gt.recipe.smallnaquadahreactor", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> largeNaquadahReactorFuels = RecipeMapBuilder + .of("gt.recipe.largenaquadahreactor", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> hugeNaquadahReactorFuels = RecipeMapBuilder + .of("gt.recipe.fluidnaquadahreactor", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> extremeNaquadahReactorFuels = RecipeMapBuilder + .of("gt.recipe.hugenaquadahreactor", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> ultraHugeNaquadahReactorFuels = RecipeMapBuilder + .of("gt.recipe.extrahugenaquadahreactor", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<FuelBackend> fluidNaquadahReactorFuels = RecipeMapBuilder + .of("gt.recipe.fluidfuelnaquadahreactor", FuelBackend::new) + .maxIO(1, 1, 0, 0) + .neiSpecialInfoFormatter(FuelSpecialValueFormatter.INSTANCE) + .build(); + public static final RecipeMap<RecipeMapBackend> electrolyzerNonCellRecipes = RecipeMapBuilder + .of("gt.recipe.largeelectrolyzer") + .maxIO(1, 6, 1, 6) + .disableRegisterNEI() + .recipeEmitter(GT_RecipeMapUtil::buildRecipeForMultiblock) + .build(); + public static final RecipeMap<RecipeMapBackend> centrifugeNonCellRecipes = RecipeMapBuilder + .of("gt.recipe.largecentrifuge") + .maxIO(2, 6, 1, 6) + .disableOptimize() + .disableRegisterNEI() + .recipeEmitter(GT_RecipeMapUtil::buildRecipeForMultiblock) + .build(); + public static final RecipeMap<RecipeMapBackend> mixerNonCellRecipes = RecipeMapBuilder.of("gt.recipe.largemixer") + .maxIO(9, 4, 6, 4) + .disableOptimize() + .disableRegisterNEI() + .recipeEmitter(GT_RecipeMapUtil::buildRecipeForMultiblockNoCircuit) + .build(); + public static final RecipeMap<LargeBoilerFuelBackend> largeBoilerFakeFuels = RecipeMapBuilder + .of("gt.recipe.largeboilerfakefuels", LargeBoilerFuelBackend::new) + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .disableOptimize() + .frontend(LargeBoilerFuelFrontend::new) + .build(); + public static final RecipeMap<RecipeMapBackend> nanoForgeRecipes = RecipeMapBuilder.of("gt.recipe.nanoforge") + .maxIO(6, 2, 3, 0) + .minInputs(2, 1) + .slotOverlays( + (index, isFluid, isOutput, + isSpecial) -> !isFluid && !isOutput && index == 0 ? GT_UITextures.OVERLAY_SLOT_LENS : null) + .progressBar(GT_UITextures.PROGRESSBAR_ASSEMBLE) + .disableOptimize() + .neiSpecialInfoFormatter(new SimpleSpecialValueFormatter("GT5U.nei.tier")) + .build(); + public static final RecipeMap<RecipeMapBackend> pcbFactoryRecipes = RecipeMapBuilder.of("gt.recipe.pcbfactory") + .maxIO(6, 9, 3, 0) + .minInputs(3, 1) + .progressBar(GT_UITextures.PROGRESSBAR_ASSEMBLE) + .disableOptimize() + .neiRecipeComparator( + Comparator + .<GT_Recipe, Integer>comparing(recipe -> recipe.getMetadataOrDefault(PCBFactoryTierKey.INSTANCE, 1)) + .thenComparing(GT_Recipe::compareTo)) + .build(); + public static final RecipeMap<RecipeMapBackend> ic2NuclearFakeRecipes = RecipeMapBuilder.of("gt.recipe.ic2nuke") + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .disableOptimize() + .logo(GT_UITextures.PICTURE_RADIATION_WARNING) + .logoPos(152, 41) + .neiRecipeBackgroundSize(170, 60) + .neiHandlerInfo(builder -> builder.setDisplayStack(GT_ModHandler.getIC2Item("nuclearReactor", 1, null))) + .build(); + + static { + RecipeMaps.centrifugeRecipes.addDownstream(RecipeMaps.centrifugeNonCellRecipes.deepCopyInput()); + RecipeMaps.mixerRecipes.addDownstream(RecipeMaps.mixerNonCellRecipes.deepCopyInput()); + RecipeMaps.electrolyzerRecipes.addDownstream(RecipeMaps.electrolyzerNonCellRecipes.deepCopyInput()); + RecipeMaps.dieselFuels.addDownstream( + IRecipeMap.newRecipeMap( + b -> b.build() + .map( + r -> RecipeMaps.largeBoilerFakeFuels.getBackend() + .addDieselRecipe(r)) + .map(Collections::singletonList) + .orElse(Collections.emptyList()))); + RecipeMaps.dieselFuels.addDownstream(IRecipeMap.newRecipeMap(b -> { + if (b.getMetadataOrDefault(FUEL_VALUE, 0) < 1500) return Collections.emptyList(); + return b.addTo(RecipeMaps.extremeDieselFuels); + })); + RecipeMaps.denseLiquidFuels.addDownstream( + IRecipeMap.newRecipeMap( + b -> b.build() + .map( + r -> RecipeMaps.largeBoilerFakeFuels.getBackend() + .addDenseLiquidRecipe(r)) + .map(Collections::singletonList) + .orElse(Collections.emptyList()))); + } +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMetadataKey.java b/src/main/java/gregtech/api/recipe/RecipeMetadataKey.java new file mode 100644 index 0000000000..2156421835 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/RecipeMetadataKey.java @@ -0,0 +1,84 @@ +package gregtech.api.recipe; + +import java.util.HashSet; +import java.util.Set; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.jetbrains.annotations.Contract; + +import gregtech.api.recipe.metadata.IRecipeMetadataStorage; +import gregtech.api.util.FieldsAreNonnullByDefault; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +/** + * Unique key for the {@link IRecipeMetadataStorage}. It's also responsible for drawing metadata info on NEI. + * <p> + * You can use {@link gregtech.api.recipe.metadata.SimpleRecipeMetadataKey} if your metadata does not need NEI handling. + * + * @param <T> Type of the metadata to use. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +public abstract class RecipeMetadataKey<T> { + + private static final Set<RecipeMetadataKey<?>> allIdentifiers = new HashSet<>(); + private final Class<T> clazz; + private final String identifier; + + protected RecipeMetadataKey(Class<T> clazz, String identifier) { + this.clazz = clazz; + this.identifier = identifier; + if (allIdentifiers.contains(this)) { + throw new IllegalArgumentException( + "Cannot register metadata key with exact same properties: " + identifier + "@" + clazz); + } + allIdentifiers.add(this); + } + + /** + * Draws info about the metadata. + * + * @param recipeInfo Object to use for drawing text. + * @param value Metadata stored in the recipe. Can be safely {@link #cast}ed to the desired type. + */ + public abstract void drawInfo(RecipeDisplayInfo recipeInfo, @Nullable Object value); + + @Nullable + public T cast(@Nullable Object o) { + return clazz.cast(o); + } + + @Contract("_, !null -> !null") + @Nullable + public T cast(@Nullable Object o, @Nullable T defaultValue) { + T val = cast(o); + return val != null ? val : defaultValue; + } + + @Override + public String toString() { + return "RecipeMetadataKey{" + "clazz=" + clazz.getName() + ", identifier=" + identifier + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RecipeMetadataKey<?> that = (RecipeMetadataKey<?>) o; + + if (!clazz.equals(that.clazz)) return false; + return identifier.equals(that.identifier); + } + + @Override + public int hashCode() { + int result = clazz.hashCode(); + result = 31 * result + identifier.hashCode(); + return result; + } +} diff --git a/src/main/java/gregtech/api/recipe/check/FindRecipeResult.java b/src/main/java/gregtech/api/recipe/check/FindRecipeResult.java deleted file mode 100644 index fa0e251fa1..0000000000 --- a/src/main/java/gregtech/api/recipe/check/FindRecipeResult.java +++ /dev/null @@ -1,125 +0,0 @@ -package gregtech.api.recipe.check; - -import java.util.Objects; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.jetbrains.annotations.NotNull; - -import gregtech.api.util.GT_Recipe; - -/** - * Wrapper class to get result of recipe search for recipemap. Note that this only validates recipe input and voltage, - * and does not involve in actual check in the machine such as output space or special value. - */ -public class FindRecipeResult { - - @Nonnull - private final State state; - @Nullable - private final GT_Recipe recipe; - @Nullable - private RecipeValidator recipeValidator; - - private FindRecipeResult(@Nonnull State state, @Nullable GT_Recipe recipe) { - this.state = state; - this.recipe = recipe; - } - - @Nonnull - public State getState() { - return state; - } - - public boolean isSuccessful() { - return state.success; - } - - /** - * If you already checked {@link #isSuccessful()}, you can use {@link #getRecipeNonNull()} instead. - */ - @Nullable - public GT_Recipe getRecipe() { - return recipe; - } - - /** - * You should use this ONLY WHEN state == FOUND. - */ - @Nonnull - public GT_Recipe getRecipeNonNull() { - return Objects.requireNonNull(recipe); - } - - /** - * Gets recipeValidator if it is not null. - * Be sure to call hasRecipeValidator before to determine if recipeValidator exists - * - * @return not null recipe validator - */ - @NotNull - public RecipeValidator getRecipeValidator() { - return Objects.requireNonNull(recipeValidator); - } - - /** - * Sets recipeValidator which used to get this result - */ - public void setRecipeValidator(@Nullable RecipeValidator recipeValidator) { - this.recipeValidator = recipeValidator; - } - - /** - * Gets if this result has recipeValidator - */ - public boolean hasRecipeValidator() { - return recipeValidator != null; - } - - /** - * Successfully found recipe. - */ - public static FindRecipeResult ofSuccess(@Nonnull GT_Recipe recipe) { - return new FindRecipeResult(State.FOUND, Objects.requireNonNull(recipe)); - } - - /** - * No recipe found. - */ - public static final FindRecipeResult NOT_FOUND = new FindRecipeResult(State.NOT_FOUND, null); - /** - * For Microwave. - */ - public static final FindRecipeResult EXPLODE = new FindRecipeResult(State.EXPLODE, null); - /** - * For Microwave. - */ - public static final FindRecipeResult ON_FIRE = new FindRecipeResult(State.ON_FIRE, null); - - public enum State { - - /** - * Successfully found recipe. - */ - FOUND(true), - /** - * No recipe found. - */ - NOT_FOUND(false), - /** - * For Microwave. - */ - EXPLODE(false), - /** - * For Microwave. - */ - ON_FIRE(false); - - private final boolean success; - - State(boolean success) { - this.success = success; - } - } -} diff --git a/src/main/java/gregtech/api/recipe/check/RecipeValidator.java b/src/main/java/gregtech/api/recipe/check/RecipeValidator.java deleted file mode 100644 index 8fb7b87cfe..0000000000 --- a/src/main/java/gregtech/api/recipe/check/RecipeValidator.java +++ /dev/null @@ -1,80 +0,0 @@ -package gregtech.api.recipe.check; - -import java.util.function.Function; -import java.util.function.Predicate; - -import gregtech.api.util.GT_OverclockCalculator; -import gregtech.api.util.GT_ParallelHelper; -import gregtech.api.util.GT_Recipe; - -/** - * Predicate for simple recipe validation. - * Also store some validation results for reusing it - */ -public class RecipeValidator implements Predicate<GT_Recipe> { - - private CheckRecipeResult firstCheckResult; - private CheckRecipeResult lastCheckResult; - private GT_ParallelHelper lastParallelHelper; - private GT_OverclockCalculator lastOverclockCalculator; - private boolean wasExecutedAtLeastOnce = false; - private final Function<GT_Recipe, CheckRecipeResult> recipeValidator; - private final Function<GT_Recipe, GT_ParallelHelper> parallelHelperFactory; - private final Function<GT_Recipe, GT_OverclockCalculator> overclockCalculatorFactory; - - public RecipeValidator(Function<GT_Recipe, CheckRecipeResult> recipeValidator, - Function<GT_Recipe, GT_ParallelHelper> parallelHelperFactory, - Function<GT_Recipe, GT_OverclockCalculator> overclockCalculatorFactory) { - this.recipeValidator = recipeValidator; - this.parallelHelperFactory = parallelHelperFactory; - this.overclockCalculatorFactory = overclockCalculatorFactory; - } - - @Override - public boolean test(GT_Recipe recipe) { - wasExecutedAtLeastOnce = true; - CheckRecipeResult checkRecipeResult = checkRecipe(recipe); - if (firstCheckResult == null) { - firstCheckResult = checkRecipeResult; - } - return checkRecipeResult.wasSuccessful(); - } - - private CheckRecipeResult checkRecipe(GT_Recipe recipe) { - lastCheckResult = recipeValidator.apply(recipe); - - if (!lastCheckResult.wasSuccessful()) { - return lastCheckResult; - } - - lastParallelHelper = parallelHelperFactory.apply(recipe); - lastOverclockCalculator = overclockCalculatorFactory.apply(recipe); - lastParallelHelper.setCalculator(lastOverclockCalculator); - lastParallelHelper.build(); - - return lastParallelHelper.getResult(); - } - - public Boolean isExecutedAtLeastOnce() { - return wasExecutedAtLeastOnce; - } - - /** - * Gets first check result in case if nothing matching recipe found. - */ - public CheckRecipeResult getFirstCheckResult() { - return firstCheckResult; - } - - public CheckRecipeResult getLastCheckResult() { - return lastCheckResult; - } - - public GT_ParallelHelper getLastParallelHelper() { - return lastParallelHelper; - } - - public GT_OverclockCalculator getLastOverclockCalculator() { - return lastOverclockCalculator; - } -} diff --git a/src/main/java/gregtech/api/recipe/check/SingleRecipeCheck.java b/src/main/java/gregtech/api/recipe/check/SingleRecipeCheck.java index d0a952b8d5..8683812d84 100644 --- a/src/main/java/gregtech/api/recipe/check/SingleRecipeCheck.java +++ b/src/main/java/gregtech/api/recipe/check/SingleRecipeCheck.java @@ -23,6 +23,7 @@ import net.minecraftforge.fluids.FluidStack; import com.google.common.collect.ImmutableMap; import gregtech.api.enums.GT_Values; +import gregtech.api.recipe.RecipeMap; import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Utility.ItemId; @@ -34,7 +35,7 @@ import gregtech.api.util.GT_Utility.ItemId; * <ul> * Normal recipe check: * <ul> - * {@link GT_Recipe.GT_Recipe_Map#findRecipeWithResult Find recipe from recipemap}: O(NCR) + * {@link gregtech.api.recipe.FindRecipeQuery#find Find recipe from recipemap}: O(NCR) * where N = number of machine inputs, C = average amount of recipe candidates found for specific input, * R = computation time to {@link GT_Recipe#isRecipeInputEqual check if inputs match to recipe} * </ul> @@ -53,7 +54,7 @@ public class SingleRecipeCheck { @Nonnull private final GT_Recipe recipe; @Nonnull - private final GT_Recipe.GT_Recipe_Map recipeMap; + private final RecipeMap<?> recipeMap; @Nonnull private final ImmutableMap<ItemId, Integer> itemCost; @Nonnull @@ -62,7 +63,7 @@ public class SingleRecipeCheck { private final int totalItemCost; private final int totalFluidCost; - private SingleRecipeCheck(@Nonnull GT_Recipe recipe, @Nonnull GT_Recipe.GT_Recipe_Map recipeMap, + private SingleRecipeCheck(@Nonnull GT_Recipe recipe, @Nonnull RecipeMap<?> recipeMap, @Nonnull ImmutableMap<ItemId, Integer> itemCost, @Nonnull ImmutableMap<Fluid, Integer> fluidCost) { this.recipe = recipe; this.recipeMap = recipeMap; @@ -85,7 +86,7 @@ public class SingleRecipeCheck { } @Nonnull - public GT_Recipe.GT_Recipe_Map getRecipeMap() { + public RecipeMap<?> getRecipeMap() { return recipeMap; } @@ -189,7 +190,7 @@ public class SingleRecipeCheck { // we don't yet have a mean to uniquely name a recipe, this will have to make do. // Consider move serialization code to GT_Recipe once this has been proven to work NBTTagCompound tag = new NBTTagCompound(); - tag.setString("recipemap", recipeMap.mUnlocalizedName); + tag.setString("recipemap", recipeMap.unlocalizedName); if (recipe.mInputs != null) { tag.setTag("inputs", writeList(recipe.mInputs, GT_Utility::saveItem)); } @@ -250,13 +251,13 @@ public class SingleRecipeCheck { } @Nullable - public static SingleRecipeCheck tryLoad(GT_Recipe.GT_Recipe_Map recipeMap, NBTTagCompound tag) { + public static SingleRecipeCheck tryLoad(RecipeMap<?> recipeMap, NBTTagCompound tag) { if (tag == null || tag.hasNoTags()) return null; - GT_Recipe.GT_Recipe_Map mapToUse; + RecipeMap<?> mapToUse; if (tag.hasKey("recipemap")) { String mapName = tag.getString("recipemap"); - GT_Recipe.GT_Recipe_Map foundMap = GT_Recipe.GT_Recipe_Map.findRecipeMap(mapName); + RecipeMap<?> foundMap = RecipeMap.ALL_RECIPE_MAPS.get(mapName); if (foundMap != null) { mapToUse = foundMap; } else { @@ -288,7 +289,7 @@ public class SingleRecipeCheck { .toImmutableMapSerial(t -> ItemId.create(t.getCompoundTag("id")), t -> t.getInteger("count"))); } - private static GT_Recipe tryFindRecipe(@Nonnull GT_Recipe.GT_Recipe_Map recipeMap, NBTTagCompound tag) { + private static GT_Recipe tryFindRecipe(@Nonnull RecipeMap<?> recipeMap, NBTTagCompound tag) { ItemStack[] inputs = GT_Utility.streamCompounds(tag.getTagList("inputs", Constants.NBT.TAG_COMPOUND)) .map(GT_Utility::loadItem) .toArray(ItemStack[]::new); @@ -334,13 +335,13 @@ public class SingleRecipeCheck { return ImmutableMap.copyOf(fluidMap); } - public static Builder builder(@Nonnull GT_Recipe.GT_Recipe_Map recipeMap) { + public static Builder builder(@Nonnull RecipeMap<?> recipeMap) { return new Builder(Objects.requireNonNull(recipeMap)); } public static class Builder { - private final GT_Recipe.GT_Recipe_Map recipeMap; + private final RecipeMap<?> recipeMap; // In order to compute which items and fluids are consumed by the recipe, we compare the // multi-block's items and fluids before and after inputs are consumed by the recipe. @@ -351,7 +352,7 @@ public class SingleRecipeCheck { private GT_Recipe recipe; - private Builder(@Nonnull GT_Recipe.GT_Recipe_Map recipeMap) { + private Builder(@Nonnull RecipeMap<?> recipeMap) { this.recipeMap = recipeMap; } diff --git a/src/main/java/gregtech/api/recipe/maps/AssemblerBackend.java b/src/main/java/gregtech/api/recipe/maps/AssemblerBackend.java new file mode 100644 index 0000000000..cfa25e9fe2 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/AssemblerBackend.java @@ -0,0 +1,35 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.ItemList; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class AssemblerBackend extends RecipeMapBackend { + + public AssemblerBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe modifyFoundRecipe(GT_Recipe recipe, ItemStack[] items, FluidStack[] fluids, + @Nullable ItemStack specialSlot) { + for (ItemStack item : items) { + if (ItemList.Paper_Printed_Pages.isStackEqual(item, false, true)) { + recipe = recipe.copy(); + recipe.mCanBeBuffered = false; + recipe.mOutputs[0].setTagCompound(item.getTagCompound()); + } + } + return recipe; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/AssemblyLineFrontend.java b/src/main/java/gregtech/api/recipe/maps/AssemblyLineFrontend.java new file mode 100644 index 0000000000..3d56c96b82 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/AssemblyLineFrontend.java @@ -0,0 +1,76 @@ +package gregtech.api.recipe.maps; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.recipe.BasicUIPropertiesBuilder; +import gregtech.api.recipe.NEIRecipePropertiesBuilder; +import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class AssemblyLineFrontend extends RecipeMapFrontend { + + public AssemblyLineFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + super(uiPropertiesBuilder, neiPropertiesBuilder); + } + + @Override + public List<Pos2d> getItemInputPositions(int itemInputCount) { + return UIHelper.getGridPositions(itemInputCount, 16, 8, 4); + } + + @Override + public List<Pos2d> getItemOutputPositions(int itemOutputCount) { + return Collections.singletonList(new Pos2d(142, 8)); + } + + @Override + public Pos2d getSpecialItemPosition() { + return new Pos2d(142, 44); + } + + @Override + public List<Pos2d> getFluidInputPositions(int fluidInputCount) { + return UIHelper.getGridPositions(fluidInputCount, 106, 8, 1); + } + + @Override + public void addProgressBar(ModularWindow.Builder builder, Supplier<Float> progressSupplier, Pos2d windowOffset) { + int bar1Width = 17; + int bar2Width = 18; + List<Supplier<Float>> splitProgress = splitProgress(progressSupplier, bar1Width, bar2Width); + builder.widget( + new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_1, bar1Width) + .setDirection(ProgressBar.Direction.RIGHT) + .setProgress(splitProgress.get(0)) + .setSynced(false, false) + .setPos(new Pos2d(88, 8).add(windowOffset)) + .setSize(bar1Width, 72)); + builder.widget( + new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_2, bar2Width) + .setDirection(ProgressBar.Direction.RIGHT) + .setProgress(splitProgress.get(1)) + .setSynced(false, false) + .setPos(new Pos2d(124, 8).add(windowOffset)) + .setSize(bar2Width, 72)); + builder.widget( + new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_3, 18) + .setDirection(ProgressBar.Direction.UP) + .setProgress(progressSupplier) + .setSynced(false, false) + .setPos(new Pos2d(146, 26).add(windowOffset)) + .setSize(10, 18)); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/DistillationTowerFrontend.java b/src/main/java/gregtech/api/recipe/maps/DistillationTowerFrontend.java new file mode 100644 index 0000000000..b061d10d55 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/DistillationTowerFrontend.java @@ -0,0 +1,38 @@ +package gregtech.api.recipe.maps; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.gtnewhorizons.modularui.api.math.Pos2d; + +import gregtech.api.recipe.BasicUIPropertiesBuilder; +import gregtech.api.recipe.NEIRecipePropertiesBuilder; +import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class DistillationTowerFrontend extends RecipeMapFrontend { + + public DistillationTowerFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + super(uiPropertiesBuilder, neiPropertiesBuilder); + } + + @Override + public List<Pos2d> getItemOutputPositions(int itemOutputCount) { + return Collections.singletonList(new Pos2d(106, 62)); + } + + @Override + public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { + List<Pos2d> results = new ArrayList<>(); + for (int i = 1; i < fluidOutputCount + 1; i++) { + results.add(new Pos2d(106 + (i % 3) * 18, 62 - (i / 3) * 18)); + } + return results; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/FluidCannerBackend.java b/src/main/java/gregtech/api/recipe/maps/FluidCannerBackend.java new file mode 100644 index 0000000000..e5681f59aa --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/FluidCannerBackend.java @@ -0,0 +1,73 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; + +import gregtech.api.enums.GT_Values; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class FluidCannerBackend extends RecipeMapBackend { + + public FluidCannerBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe findFallback(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot) { + if (items.length == 0 || items[0] == null) { + return null; + } + + if (fluids.length > 0 && fluids[0] != null) { + ItemStack filledItem = GT_Utility.fillFluidContainer(fluids[0], items[0], false, true); + FluidStack fluidToTake = GT_Utility.getFluidForFilledItem(filledItem, true); + if (fluidToTake != null) { + return GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, items[0])) + .itemOutputs(filledItem) + .fluidInputs(fluidToTake) + .duration(Math.max(fluidToTake.amount / 64, 16)) + .eut(1) + .noOptimize() + .noBuffer() + .build() + .orElse(null); + } + } + FluidStack drainedFluid = GT_Utility.getFluidForFilledItem(items[0], true); + if (drainedFluid != null) { + return GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, items[0])) + .itemOutputs(GT_Utility.getContainerItem(items[0], true)) + .fluidOutputs(drainedFluid) + .duration(Math.max(drainedFluid.amount / 64, 16)) + .eut(1) + .noBuffer() + .build() + .orElse(null); + } + return null; + } + + @Override + public boolean containsInput(ItemStack item) { + return super.containsInput(item) || (item.getItem() instanceof IFluidContainerItem + && ((IFluidContainerItem) item.getItem()).getCapacity(item) > 0); + } + + @Override + public boolean containsInput(Fluid fluid) { + return true; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/FluidOnlyFrontend.java b/src/main/java/gregtech/api/recipe/maps/FluidOnlyFrontend.java new file mode 100644 index 0000000000..8b37f6388c --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/FluidOnlyFrontend.java @@ -0,0 +1,33 @@ +package gregtech.api.recipe.maps; + +import java.util.List; + +import com.gtnewhorizons.modularui.api.math.Pos2d; + +import gregtech.api.recipe.BasicUIPropertiesBuilder; +import gregtech.api.recipe.NEIRecipePropertiesBuilder; +import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; + +/** + * Display fluids where normally items are placed on NEI. + */ +@MethodsReturnNonnullByDefault +public class FluidOnlyFrontend extends RecipeMapFrontend { + + public FluidOnlyFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + super(uiPropertiesBuilder, neiPropertiesBuilder); + } + + @Override + public List<Pos2d> getFluidInputPositions(int fluidInputCount) { + return UIHelper.getItemInputPositions(fluidInputCount); + } + + @Override + public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { + return UIHelper.getItemOutputPositions(fluidOutputCount); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/FormingPressBackend.java b/src/main/java/gregtech/api/recipe/maps/FormingPressBackend.java new file mode 100644 index 0000000000..ce3ea3e89c --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/FormingPressBackend.java @@ -0,0 +1,92 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Special Class for Forming Press handling. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class FormingPressBackend extends RecipeMapBackend { + + public FormingPressBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe modifyFoundRecipe(GT_Recipe recipe, ItemStack[] items, FluidStack[] fluids, + @Nullable ItemStack specialSlot) { + for (ItemStack mold : items) { + if (ItemList.Shape_Mold_Credit.isStackEqual(mold, false, true)) { + NBTTagCompound nbt = mold.getTagCompound(); + if (nbt == null) nbt = new NBTTagCompound(); + if (!nbt.hasKey("credit_security_id")) nbt.setLong("credit_security_id", System.nanoTime()); + mold.setTagCompound(nbt); + + recipe = recipe.copy(); + recipe.mCanBeBuffered = false; + recipe.mOutputs[0].setTagCompound(nbt); + return recipe; + } + } + return recipe; + } + + @Override + protected GT_Recipe findFallback(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot) { + if (items.length < 2) { + return null; + } + return findRenamingRecipe(items); + } + + @Nullable + private GT_Recipe findRenamingRecipe(ItemStack[] inputs) { + ItemStack mold = findNameMoldIndex(inputs); + if (mold == null) return null; + ItemStack input = findStackToRename(inputs, mold); + if (input == null) return null; + ItemStack output = GT_Utility.copyAmount(1, input); + if (output == null) return null; + output.setStackDisplayName(mold.getDisplayName()); + return GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(0, mold), GT_Utility.copyAmount(1, input)) + .itemOutputs(output) + .duration(128) + .eut(8) + .noBuffer() + .nbtSensitive() + .build() + .orElse(null); + } + + @Nullable + private ItemStack findNameMoldIndex(ItemStack[] inputs) { + for (ItemStack stack : inputs) { + if (ItemList.Shape_Mold_Name.isStackEqual(stack, false, true)) return stack; + } + return null; + } + + @Nullable + private ItemStack findStackToRename(ItemStack[] inputs, ItemStack mold) { + for (ItemStack stack : inputs) { + if (stack == mold || stack == null) continue; + return stack; + } + return null; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/FuelBackend.java b/src/main/java/gregtech/api/recipe/maps/FuelBackend.java new file mode 100644 index 0000000000..49c989e174 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/FuelBackend.java @@ -0,0 +1,75 @@ +package gregtech.api.recipe.maps; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class FuelBackend extends RecipeMapBackend { + + private final Map<String, GT_Recipe> recipesByFluidInput = new HashMap<>(); + + public FuelBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder.disableOptimize()); + } + + @Override + protected Collection<GT_Recipe> doAdd(GT_RecipeBuilder builder) { + if (builder.getDuration() == -1) { + builder.duration(0); + } + if (builder.getEUt() == -1) { + builder.eut(0); + } + return super.doAdd(builder); + } + + @Override + public GT_Recipe compileRecipe(GT_Recipe recipe) { + super.compileRecipe(recipe); + if (recipe.mInputs != null && GT_Utility.getNonnullElementCount(recipe.mInputs) == 1 + && (recipe.mFluidInputs == null || GT_Utility.getNonnullElementCount(recipe.mFluidInputs) == 0)) { + FluidStack fluidStack = GT_Utility.getFluidForFilledItem(recipe.mInputs[0], true); + if (fluidStack != null) { + fluidStack.amount = 0; + recipesByFluidInput.put( + fluidStack.getFluid() + .getName(), + recipe); + } + } else if ((recipe.mInputs == null || GT_Utility.getNonnullElementCount(recipe.mInputs) == 0) + && recipe.mFluidInputs != null + && GT_Utility.getNonnullElementCount(recipe.mFluidInputs) >= 1 + && recipe.mFluidInputs[0] != null) { + recipesByFluidInput.put( + recipe.mFluidInputs[0].getFluid() + .getName(), + recipe); + } + return recipe; + } + + @Nullable + public GT_Recipe findFuel(FluidStack fluidStack) { + return findFuel(fluidStack.getFluid()); + } + + @Nullable + public GT_Recipe findFuel(Fluid fluid) { + return recipesByFluidInput.get(fluid.getName()); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/FurnaceBackend.java b/src/main/java/gregtech/api/recipe/maps/FurnaceBackend.java new file mode 100644 index 0000000000..c4095eeb4e --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/FurnaceBackend.java @@ -0,0 +1,52 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.GT_Values; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Special Class for Furnace Recipe handling. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class FurnaceBackend extends NonGTBackend { + + public FurnaceBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe overwriteFindRecipe(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot, + @Nullable GT_Recipe cachedRecipe) { + if (items.length == 0 || items[0] == null) { + return null; + } + if (cachedRecipe != null && cachedRecipe.isRecipeInputEqual(false, true, fluids, items)) { + return cachedRecipe; + } + ItemStack output = GT_ModHandler.getSmeltingOutput(items[0], false, null); + return output == null ? null + : GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, items[0])) + .itemOutputs(output) + .duration(128) + .eut(4) + .noOptimize() + .build() + .orElse(null); + } + + @Override + public boolean containsInput(ItemStack item) { + return GT_ModHandler.getSmeltingOutput(item, false, null) != null; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/LargeBoilerFuelBackend.java b/src/main/java/gregtech/api/recipe/maps/LargeBoilerFuelBackend.java new file mode 100644 index 0000000000..53152312f4 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/LargeBoilerFuelBackend.java @@ -0,0 +1,132 @@ +package gregtech.api.recipe.maps; + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.ConfigCategories; +import gregtech.api.enums.GT_Values; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@SuppressWarnings({ "unused", "UnusedReturnValue" }) +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class LargeBoilerFuelBackend extends RecipeMapBackend { + + private static boolean addedGeneralDesc = false; + + private static final List<String> ALLOWED_SOLID_FUELS = Arrays.asList( + GregTech_API.sMachineFile.mConfig.getStringList( + "LargeBoiler.allowedFuels", + ConfigCategories.machineconfig.toString(), + new String[] { "gregtech:gt.blockreinforced:6", "gregtech:gt.blockreinforced:7" }, + "Allowed fuels for the Large Titanium Boiler and Large Tungstensteel Boiler")); + + public LargeBoilerFuelBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + public static boolean isAllowedSolidFuel(ItemStack stack) { + return isAllowedSolidFuel(Item.itemRegistry.getNameForObject(stack.getItem()), stack.getItemDamage()); + } + + public static boolean isAllowedSolidFuel(String itemRegistryName, int meta) { + return ALLOWED_SOLID_FUELS.contains(itemRegistryName + ":" + meta); + } + + public static boolean addAllowedSolidFuel(ItemStack stack) { + return addAllowedSolidFuel(Item.itemRegistry.getNameForObject(stack.getItem()), stack.getItemDamage()); + } + + public static boolean addAllowedSolidFuel(String itemregistryName, int meta) { + return ALLOWED_SOLID_FUELS.add(itemregistryName + ":" + meta); + } + + public GT_Recipe addDenseLiquidRecipe(GT_Recipe recipe) { + return addRecipe(recipe, ((double) recipe.mSpecialValue) / 10, false); + } + + public GT_Recipe addDieselRecipe(GT_Recipe recipe) { + return addRecipe(recipe, ((double) recipe.mSpecialValue) / 40, false); + } + + public void addSolidRecipes(ItemStack... itemStacks) { + for (ItemStack itemStack : itemStacks) { + addSolidRecipe(itemStack); + } + } + + @Nullable + public GT_Recipe addSolidRecipe(@Nullable ItemStack fuelItemStack) { + if (fuelItemStack == null) { + return null; + } + if (!addedGeneralDesc) { + GT_Values.RA.stdBuilder() + .duration(1) + .eut(1) + .specialValue(1) + .setNEIDesc( + "Not all solid fuels are listed.", + "Any item that burns in a", + "vanilla furnace will burn in", + "a Large Bronze or Steel Boiler.") + .build() + .map(this::compileRecipe); + addedGeneralDesc = true; + } + + String registryName = Item.itemRegistry.getNameForObject(fuelItemStack.getItem()); + boolean isHighTierAllowed = ALLOWED_SOLID_FUELS.contains(registryName + ":" + fuelItemStack.getItemDamage()); + return GT_Values.RA.stdBuilder() + .itemInputs(fuelItemStack) + .duration(1) + .eut(0) + .specialValue(GT_ModHandler.getFuelValue(fuelItemStack) / 1600) + .build() + .map(r -> addRecipe(r, ((double) GT_ModHandler.getFuelValue(fuelItemStack)) / 1600, isHighTierAllowed)) + .orElse(null); + } + + private GT_Recipe addRecipe(GT_Recipe recipe, double baseBurnTime, boolean isHighTierAllowed) { + // Some recipes will have a burn time like 15.9999999 and % always rounds down + double floatErrorCorrection = 0.0001; + + double bronzeBurnTime = baseBurnTime * 2 + floatErrorCorrection; + bronzeBurnTime -= bronzeBurnTime % 0.05; + double steelBurnTime = baseBurnTime + floatErrorCorrection; + steelBurnTime -= steelBurnTime % 0.05; + double titaniumBurnTime = baseBurnTime * 0.3 + floatErrorCorrection; + titaniumBurnTime -= titaniumBurnTime % 0.05; + double tungstensteelBurnTime = baseBurnTime * 0.15 + floatErrorCorrection; + tungstensteelBurnTime -= tungstensteelBurnTime % 0.05; + + if (isHighTierAllowed) { + recipe.setNeiDesc( + "Burn time in seconds:", + String.format("Bronze Boiler: %.4f", bronzeBurnTime), + String.format("Steel Boiler: %.4f", steelBurnTime), + String.format("Titanium Boiler: %.4f", titaniumBurnTime), + String.format("Tungstensteel Boiler: %.4f", tungstensteelBurnTime)); + } else { + recipe.setNeiDesc( + "Burn time in seconds:", + String.format("Bronze Boiler: %.4f", bronzeBurnTime), + String.format("Steel Boiler: %.4f", steelBurnTime), + "Titanium Boiler: Not allowed", + "Tungstenst. Boiler: Not allowed"); + } + + return compileRecipe(recipe); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/LargeBoilerFuelFrontend.java b/src/main/java/gregtech/api/recipe/maps/LargeBoilerFuelFrontend.java new file mode 100644 index 0000000000..dbe7f6fe2f --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/LargeBoilerFuelFrontend.java @@ -0,0 +1,25 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.api.recipe.BasicUIPropertiesBuilder; +import gregtech.api.recipe.NEIRecipePropertiesBuilder; +import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class LargeBoilerFuelFrontend extends RecipeMapFrontend { + + public LargeBoilerFuelFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + super(uiPropertiesBuilder, neiPropertiesBuilder); + } + + @Override + protected void drawEnergyInfo(RecipeDisplayInfo recipeInfo) {} + + @Override + protected void drawDurationInfo(RecipeDisplayInfo recipeInfo) {} +} diff --git a/src/main/java/gregtech/api/recipe/maps/LargeNEIFrontend.java b/src/main/java/gregtech/api/recipe/maps/LargeNEIFrontend.java new file mode 100644 index 0000000000..70184a83de --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/LargeNEIFrontend.java @@ -0,0 +1,65 @@ +package gregtech.api.recipe.maps; + +import java.util.List; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; + +import gregtech.api.recipe.BasicUIPropertiesBuilder; +import gregtech.api.recipe.NEIRecipePropertiesBuilder; +import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; + +/** + * Nicely display NEI with many items and fluids. Remember to call + * If row count >= 6, it doesn't fit in 2 recipes per page, so change it via IMC. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class LargeNEIFrontend extends RecipeMapFrontend { + + private static final int xDirMaxCount = 3; + private static final int yOrigin = 8; + + private final int itemRowCount; + private final int fluidRowCount; + + public LargeNEIFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + super(uiPropertiesBuilder.logoPos(new Pos2d(80, 62)), neiPropertiesBuilder); + this.itemRowCount = getItemRowCount(); + this.fluidRowCount = getFluidRowCount(); + neiProperties.recipeBackgroundSize = new Size(170, 82 + (Math.max(itemRowCount + fluidRowCount - 4, 0)) * 18); + } + + @Override + public List<Pos2d> getItemInputPositions(int itemInputCount) { + return UIHelper.getGridPositions(itemInputCount, 16, yOrigin, xDirMaxCount); + } + + @Override + public List<Pos2d> getItemOutputPositions(int itemOutputCount) { + return UIHelper.getGridPositions(itemOutputCount, 106, yOrigin, xDirMaxCount); + } + + @Override + public List<Pos2d> getFluidInputPositions(int fluidInputCount) { + return UIHelper.getGridPositions(fluidInputCount, 16, yOrigin + itemRowCount * 18, xDirMaxCount); + } + + @Override + public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { + return UIHelper.getGridPositions(fluidOutputCount, 106, yOrigin + itemRowCount * 18, xDirMaxCount); + } + + private int getItemRowCount() { + return (Math.max(uiProperties.maxItemInputs, uiProperties.maxItemOutputs) - 1) / xDirMaxCount + 1; + } + + private int getFluidRowCount() { + return (Math.max(uiProperties.maxFluidInputs, uiProperties.maxFluidOutputs) - 1) / xDirMaxCount + 1; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/MicrowaveBackend.java b/src/main/java/gregtech/api/recipe/maps/MicrowaveBackend.java new file mode 100644 index 0000000000..53623cb0c7 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/MicrowaveBackend.java @@ -0,0 +1,145 @@ +package gregtech.api.recipe.maps; + +import static gregtech.api.enums.GT_Values.W; +import static gregtech.api.util.GT_RecipeConstants.EXPLODE; +import static gregtech.api.util.GT_RecipeConstants.ON_FIRE; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntityFurnace; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.SubTag; +import gregtech.api.objects.ItemData; +import gregtech.api.objects.MaterialStack; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Special Class for Microwave Recipe handling. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class MicrowaveBackend extends NonGTBackend { + + public MicrowaveBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe overwriteFindRecipe(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot, + @Nullable GT_Recipe cachedRecipe) { + if (items.length == 0 || items[0] == null) { + return null; + } + if (cachedRecipe != null && cachedRecipe.isRecipeInputEqual(false, true, fluids, items)) { + return cachedRecipe; + } + + ItemStack output = GT_ModHandler.getSmeltingOutput(items[0], false, null); + + if (GT_Utility.areStacksEqual(items[0], new ItemStack(Items.book, 1, W))) { + return GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, items[0])) + .itemOutputs(GT_Utility.getWrittenBook("Manual_Microwave", ItemList.Book_Written_03.get(1))) + .duration(32) + .eut(4) + .noOptimize() + .build() + .orElse(null); + } + + // Check Container Item of Input since it is around the Input, then the Input itself, then Container Item of + // Output and last check the Output itself + for (ItemStack item : new ItemStack[] { GT_Utility.getContainerItem(items[0], true), items[0], + GT_Utility.getContainerItem(output, true), output }) { + if (item == null) continue; + if (GT_Utility.areStacksEqual(item, new ItemStack(Blocks.netherrack, 1, W), true) + || GT_Utility.areStacksEqual(item, new ItemStack(Blocks.tnt, 1, W), true) + || GT_Utility.areStacksEqual(item, new ItemStack(Items.egg, 1, W), true) + || GT_Utility.areStacksEqual(item, new ItemStack(Items.firework_charge, 1, W), true) + || GT_Utility.areStacksEqual(item, new ItemStack(Items.fireworks, 1, W), true) + || GT_Utility.areStacksEqual(item, new ItemStack(Items.fire_charge, 1, W), true)) { + GT_Log.exp + .println("Microwave Explosion due to TNT || EGG || FIREWORKCHARGE || FIREWORK || FIRE CHARGE"); + return GT_RecipeBuilder.empty() + .metadata(EXPLODE, true) + .build() + .orElse(null); + } + + ItemData itemData = GT_OreDictUnificator.getItemData(item); + if (itemData != null) { + if (itemData.mMaterial != null && itemData.mMaterial.mMaterial != null) { + if (itemData.mMaterial.mMaterial.contains(SubTag.METAL) + || itemData.mMaterial.mMaterial.contains(SubTag.EXPLOSIVE)) { + GT_Log.exp.println("Microwave Explosion due to METAL insertion"); + return GT_RecipeBuilder.empty() + .metadata(EXPLODE, true) + .build() + .orElse(null); + } + if (itemData.mMaterial.mMaterial.contains(SubTag.FLAMMABLE)) { + GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); + return GT_RecipeBuilder.empty() + .metadata(ON_FIRE, true) + .build() + .orElse(null); + } + } + for (MaterialStack materialStack : itemData.mByProducts) { + if (materialStack == null) continue; + if (materialStack.mMaterial.contains(SubTag.METAL) + || materialStack.mMaterial.contains(SubTag.EXPLOSIVE)) { + GT_Log.exp.println("Microwave Explosion due to METAL insertion"); + return GT_RecipeBuilder.empty() + .metadata(EXPLODE, true) + .build() + .orElse(null); + } + if (materialStack.mMaterial.contains(SubTag.FLAMMABLE)) { + GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); + return GT_RecipeBuilder.empty() + .metadata(ON_FIRE, true) + .build() + .orElse(null); + } + } + } + if (TileEntityFurnace.getItemBurnTime(item) > 0) { + GT_Log.exp.println("Microwave INFLAMMATION due to BURNABLE insertion"); + return GT_RecipeBuilder.empty() + .metadata(ON_FIRE, true) + .build() + .orElse(null); + } + } + + return output == null ? null + : GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, items[0])) + .itemOutputs(output) + .duration(32) + .eut(4) + .noOptimize() + .build() + .orElse(null); + } + + @Override + public boolean containsInput(ItemStack item) { + return GT_ModHandler.getSmeltingOutput(item, false, null) != null; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/NonGTBackend.java b/src/main/java/gregtech/api/recipe/maps/NonGTBackend.java new file mode 100644 index 0000000000..1e871df372 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/NonGTBackend.java @@ -0,0 +1,52 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Abstract class for general recipe handling of non GT recipes + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public abstract class NonGTBackend extends RecipeMapBackend { + + public NonGTBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected abstract GT_Recipe overwriteFindRecipe(ItemStack[] items, FluidStack[] fluids, + @Nullable ItemStack specialSlot, @Nullable GT_Recipe cachedRecipe); + + @Override + protected boolean doesOverwriteFindRecipe() { + return true; + } + + @Override + public boolean containsInput(ItemStack item) { + return false; + } + + @Override + public boolean containsInput(Fluid fluid) { + return false; + } + + @Override + public void reInit() {} + + @Override + protected GT_Recipe addToItemMap(GT_Recipe recipe) { + return recipe; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/OilCrackerBackend.java b/src/main/java/gregtech/api/recipe/maps/OilCrackerBackend.java new file mode 100644 index 0000000000..c2c312a48a --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/OilCrackerBackend.java @@ -0,0 +1,41 @@ +package gregtech.api.recipe.maps; + +import java.util.HashSet; +import java.util.Set; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class OilCrackerBackend extends RecipeMapBackend { + + private final Set<String> validCatalystFluidNames = new HashSet<>(); + + public OilCrackerBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + public GT_Recipe compileRecipe(GT_Recipe recipe) { + super.compileRecipe(recipe); + if (recipe.mFluidInputs != null && recipe.mFluidInputs.length > 1 && recipe.mFluidInputs[1] != null) { + validCatalystFluidNames.add( + recipe.mFluidInputs[1].getFluid() + .getName()); + } + return recipe; + } + + public boolean isValidCatalystFluid(FluidStack fluid) { + return validCatalystFluidNames.contains( + fluid.getFluid() + .getName()); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/PrinterBackend.java b/src/main/java/gregtech/api/recipe/maps/PrinterBackend.java new file mode 100644 index 0000000000..a933886447 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/PrinterBackend.java @@ -0,0 +1,142 @@ +package gregtech.api.recipe.maps; + +import static gregtech.api.enums.GT_Values.L; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.Dyes; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Special Class for Printer handling. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class PrinterBackend extends RecipeMapBackend { + + public PrinterBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe modifyFoundRecipe(GT_Recipe recipe, ItemStack[] items, FluidStack[] fluids, + @Nullable ItemStack specialSlot) { + if (items[0].getItem() == Items.paper) { + assert specialSlot != null; + if (!ItemList.Tool_DataStick.isStackEqual(specialSlot, false, true)) return null; + NBTTagCompound nbt = specialSlot.getTagCompound(); + if (nbt == null || GT_Utility.isStringInvalid(nbt.getString("title")) + || GT_Utility.isStringInvalid(nbt.getString("author"))) return null; + + recipe = recipe.copy(); + recipe.mCanBeBuffered = false; + recipe.mOutputs[0].setTagCompound(nbt); + return recipe; + } + if (items[0].getItem() == Items.map) { + assert specialSlot != null; + if (!ItemList.Tool_DataStick.isStackEqual(specialSlot, false, true)) return null; + NBTTagCompound nbt = specialSlot.getTagCompound(); + if (nbt == null || !nbt.hasKey("map_id")) return null; + + recipe = recipe.copy(); + recipe.mCanBeBuffered = false; + recipe.mOutputs[0].setItemDamage(nbt.getShort("map_id")); + return recipe; + } + if (ItemList.Paper_Punch_Card_Empty.isStackEqual(items[0], false, true)) { + assert specialSlot != null; + if (!ItemList.Tool_DataStick.isStackEqual(specialSlot, false, true)) return null; + NBTTagCompound nbt = specialSlot.getTagCompound(); + if (nbt == null || !nbt.hasKey("GT.PunchCardData")) return null; + + recipe = recipe.copy(); + recipe.mCanBeBuffered = false; + recipe.mOutputs[0].setTagCompound( + GT_Utility.getNBTContainingString( + new NBTTagCompound(), + "GT.PunchCardData", + nbt.getString("GT.PunchCardData"))); + return recipe; + } + return recipe; + } + + @Override + protected GT_Recipe findFallback(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot) { + if (items.length == 0 || items[0] == null || fluids.length == 0 || fluids[0] == null) { + return null; + } + Dyes dye = null; + for (Dyes tDye : Dyes.VALUES) if (tDye.isFluidDye(fluids[0])) { + dye = tDye; + break; + } + if (dye == null) return null; + + ItemStack batchRecolorOutput = GT_ModHandler.getAllRecipeOutput( + null, + items[0], + items[0], + items[0], + items[0], + ItemList.DYE_ONLY_ITEMS[dye.mIndex].get(1), + items[0], + items[0], + items[0], + items[0]); + if (batchRecolorOutput != null) { + return GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(8, items[0])) + .itemOutputs(batchRecolorOutput) + .fluidInputs(new FluidStack(fluids[0].getFluid(), (int) L)) + .duration(256) + .eut(2) + .hidden() + .build() + .map(this::compileRecipe) + .orElse(null); + } + + ItemStack singleRecolorOutput = GT_ModHandler + .getAllRecipeOutput(null, items[0], ItemList.DYE_ONLY_ITEMS[dye.mIndex].get(1)); + if (singleRecolorOutput != null) { + return GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, items[0])) + .itemOutputs(singleRecolorOutput) + .fluidInputs(new FluidStack(fluids[0].getFluid(), (int) L)) + .duration(32) + .eut(2) + .hidden() + .build() + .map(this::compileRecipe) + .orElse(null); + } + + return null; + } + + @Override + public boolean containsInput(ItemStack item) { + return true; + } + + @Override + public boolean containsInput(Fluid fluid) { + return super.containsInput(fluid) || Dyes.isAnyFluidDye(fluid); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/RecyclerBackend.java b/src/main/java/gregtech/api/recipe/maps/RecyclerBackend.java new file mode 100644 index 0000000000..5d65468004 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/RecyclerBackend.java @@ -0,0 +1,51 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.GT_Values; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Special Class for Recycler Recipe handling. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class RecyclerBackend extends NonGTBackend { + + public RecyclerBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe overwriteFindRecipe(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot, + @Nullable GT_Recipe cachedRecipe) { + if (items.length == 0 || items[0] == null) { + return null; + } + if (cachedRecipe != null && cachedRecipe.isRecipeInputEqual(false, true, fluids, items)) { + return cachedRecipe; + } + return GT_Values.RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, items[0])) + .itemOutputs(GT_ModHandler.getRecyclerOutput(items[0], 0)) + .outputChances(1250) + .duration(45) + .eut(1) + .noOptimize() + .build() + .orElse(null); + } + + @Override + public boolean containsInput(ItemStack item) { + return GT_ModHandler.getRecyclerOutput(item, 0) != null; + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/ReplicatorBackend.java b/src/main/java/gregtech/api/recipe/maps/ReplicatorBackend.java new file mode 100644 index 0000000000..f201698457 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/ReplicatorBackend.java @@ -0,0 +1,100 @@ +package gregtech.api.recipe.maps; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.GT_Mod; +import gregtech.api.enums.Element; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.TierEU; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_RecipeBuilder; +import gregtech.api.util.GT_RecipeConstants; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.items.behaviors.Behaviour_DataOrb; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class ReplicatorBackend extends RecipeMapBackend { + + private final Map<Materials, GT_Recipe> recipesByMaterial = new HashMap<>(); + + public ReplicatorBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder.recipeEmitter(ReplicatorBackend::replicatorRecipeEmitter)); + } + + @Override + public GT_Recipe compileRecipe(GT_Recipe recipe) { + super.compileRecipe(recipe); + Materials material = recipe.getMetadata(GT_RecipeConstants.MATERIAL); + assert material != null; // checked by replicatorRecipeEmitter + recipesByMaterial.put(material, recipe); + return recipe; + } + + @Override + protected boolean doesOverwriteFindRecipe() { + return true; + } + + @Override + protected GT_Recipe overwriteFindRecipe(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot, + @Nullable GT_Recipe cachedRecipe) { + if (specialSlot == null) { + return null; + } + Materials foundMaterial = getMaterialFromDataOrb(specialSlot); + if (foundMaterial == null) { + return null; + } + return recipesByMaterial.getOrDefault(foundMaterial, null); + } + + @Nullable + private static Materials getMaterialFromDataOrb(ItemStack stack) { + if (ItemList.Tool_DataOrb.isStackEqual(stack, false, true) && Behaviour_DataOrb.getDataTitle(stack) + .equals("Elemental-Scan")) { + return Element.get(Behaviour_DataOrb.getDataName(stack)).mLinkedMaterials.stream() + .findFirst() + .orElse(null); + } + return null; + } + + private static Collection<GT_Recipe> replicatorRecipeEmitter(GT_RecipeBuilder builder) { + Materials material = builder.getMetadata(GT_RecipeConstants.MATERIAL); + if (material == null) { + throw new IllegalStateException("GT_RecipeConstants.MATERIAL must be set for replicator recipe"); + } + return Optional.of(material) + .map(material1 -> material1.mElement) + .map(Element::getMass) + .map(ReplicatorBackend::getUUMAmountFromMass) + .flatMap( + uum -> builder.fluidInputs(Materials.UUMatter.getFluid(uum)) + .duration(GT_Utility.safeInt(uum * 512L, 1)) + .eut(TierEU.RECIPE_LV) + .ignoreCollision() + .noOptimize() + .build()) + .map(Collections::singletonList) + .orElse(Collections.emptyList()); + } + + private static int getUUMAmountFromMass(long mass) { + return GT_Utility.safeInt((long) Math.pow(mass, GT_Mod.gregtechproxy.replicatorExponent), 1); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/SpaceProjectFrontend.java b/src/main/java/gregtech/api/recipe/maps/SpaceProjectFrontend.java new file mode 100644 index 0000000000..98463dcc4d --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/SpaceProjectFrontend.java @@ -0,0 +1,131 @@ +package gregtech.api.recipe.maps; + +import static gregtech.api.util.GT_Utility.formatNumbers; +import static net.minecraft.util.EnumChatFormatting.GRAY; +import static net.minecraft.util.StatCollector.translateToLocal; + +import java.util.List; +import java.util.function.Supplier; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.util.EnumChatFormatting; + +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import appeng.util.ReadableNumberConverter; +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.PositionedStack; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.recipe.BasicUIPropertiesBuilder; +import gregtech.api.recipe.NEIRecipePropertiesBuilder; +import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; +import gregtech.common.misc.spaceprojects.SpaceProjectManager; +import gregtech.common.misc.spaceprojects.SpaceProjectManager.FakeSpaceProjectRecipe; +import gregtech.common.misc.spaceprojects.interfaces.ISpaceProject; +import gregtech.nei.GT_NEI_DefaultHandler; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class SpaceProjectFrontend extends RecipeMapFrontend { + + IDrawable projectTexture; + + public SpaceProjectFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + super(uiPropertiesBuilder, neiPropertiesBuilder); + } + + @Override + public ModularWindow.Builder createNEITemplate(IItemHandlerModifiable itemInputsInventory, + IItemHandlerModifiable itemOutputsInventory, IItemHandlerModifiable specialSlotInventory, + IItemHandlerModifiable fluidInputsInventory, IItemHandlerModifiable fluidOutputsInventory, + Supplier<Float> progressSupplier, Pos2d windowOffset) { + ModularWindow.Builder builder = super.createNEITemplate( + itemInputsInventory, + itemOutputsInventory, + specialSlotInventory, + fluidInputsInventory, + fluidOutputsInventory, + progressSupplier, + windowOffset); + builder.widget( + new DrawableWidget().setDrawable(() -> projectTexture) + .setSize(18, 18) + .setPos(new Pos2d(124, 28).add(windowOffset))); + return builder; + } + + @Override + public List<Pos2d> getItemInputPositions(int itemInputCount) { + return UIHelper.getGridPositions(itemInputCount, 16, 28, 3); + } + + @Override + public List<Pos2d> getFluidInputPositions(int fluidInputCount) { + return UIHelper.getGridPositions(fluidInputCount, 88, 28, 1); + } + + @Override + protected List<String> handleNEIItemInputTooltip(List<String> currentTip, + GT_NEI_DefaultHandler.FixedPositionedStack pStack) { + super.handleNEIItemOutputTooltip(currentTip, pStack); + if (pStack.isFluid()) return currentTip; + currentTip.add(GRAY + translateToLocal("Item Count: ") + formatNumbers(pStack.realStackSize)); + return currentTip; + } + + @Override + public void drawNEIOverlays(GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) { + for (PositionedStack stack : neiCachedRecipe.mInputs) { + if (stack instanceof GT_NEI_DefaultHandler.FixedPositionedStack pStack && stack.item != null + && !pStack.isFluid()) { + int stackSize = ((GT_NEI_DefaultHandler.FixedPositionedStack) stack).realStackSize; + String displayString; + if (stack.item.stackSize > 9999) { + displayString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize); + } else { + displayString = String.valueOf(stackSize); + } + drawNEIOverlayText(displayString, stack, 0xffffff, 0.5f, true, Alignment.BottomRight); + } + } + if (neiCachedRecipe.mRecipe instanceof FakeSpaceProjectRecipe) { + ISpaceProject project = SpaceProjectManager + .getProject(((FakeSpaceProjectRecipe) neiCachedRecipe.mRecipe).projectName); + if (project != null) { + projectTexture = project.getTexture(); + GuiDraw.drawStringC(EnumChatFormatting.BOLD + project.getLocalizedName(), 85, 0, 0x404040, false); + } + } + } + + @Override + public void addProgressBar(ModularWindow.Builder builder, Supplier<Float> progressSupplier, Pos2d windowOffset) { + int bar1Width = 17; + int bar2Width = 18; + List<Supplier<Float>> splitProgress = splitProgress(progressSupplier, bar1Width, bar2Width); + builder.widget( + new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_1, 17) + .setDirection(ProgressBar.Direction.RIGHT) + .setProgress(splitProgress.get(0)) + .setSynced(false, false) + .setPos(new Pos2d(70, 28).add(windowOffset)) + .setSize(bar1Width, 72)); + builder.widget( + new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_2, 18) + .setDirection(ProgressBar.Direction.RIGHT) + .setProgress(splitProgress.get(1)) + .setSynced(false, false) + .setPos(new Pos2d(106, 28).add(windowOffset)) + .setSize(bar2Width, 72)); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/TranscendentPlasmaMixerFrontend.java b/src/main/java/gregtech/api/recipe/maps/TranscendentPlasmaMixerFrontend.java new file mode 100644 index 0000000000..7a5d7ff164 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/TranscendentPlasmaMixerFrontend.java @@ -0,0 +1,56 @@ +package gregtech.api.recipe.maps; + +import static gregtech.api.util.GT_Utility.formatNumbers; + +import java.util.List; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.gtnewhorizons.modularui.api.math.Pos2d; + +import gregtech.api.recipe.BasicUIPropertiesBuilder; +import gregtech.api.recipe.NEIRecipePropertiesBuilder; +import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; +import gregtech.nei.RecipeDisplayInfo; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class TranscendentPlasmaMixerFrontend extends RecipeMapFrontend { + + public TranscendentPlasmaMixerFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, + NEIRecipePropertiesBuilder neiPropertiesBuilder) { + super(uiPropertiesBuilder, neiPropertiesBuilder); + } + + @Override + public List<Pos2d> getItemInputPositions(int itemInputCount) { + return UIHelper.getGridPositions(itemInputCount, 60, 8, 1); + } + + @Override + public List<Pos2d> getFluidInputPositions(int fluidInputCount) { + return UIHelper.getGridPositions(fluidInputCount, 6, 26, 4, 5); + } + + @Override + public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { + return UIHelper.getGridPositions(fluidOutputCount, 114, 44, 1); + } + + @Override + protected void drawEnergyInfo(RecipeDisplayInfo recipeInfo) { + // These look odd because recipeInfo.recipe.mEUt is actually the EU per litre of fluid processed, not + // the EU/t. + recipeInfo.drawText( + GT_Utility.trans("152", "Total: ") + + formatNumbers(1000L * recipeInfo.recipe.mDuration / 100L * recipeInfo.recipe.mEUt) + + " EU"); + // 1000 / (20 ticks * 5 seconds) = 10L/t. 10L/t * x EU/L = 10 * x EU/t. + long averageUsage = 10L * recipeInfo.recipe.mEUt; + recipeInfo.drawText( + "Average: " + formatNumbers(averageUsage) + " EU/t" + GT_Utility.getTierNameWithParentheses(averageUsage)); + } +} diff --git a/src/main/java/gregtech/api/recipe/maps/UnpackagerBackend.java b/src/main/java/gregtech/api/recipe/maps/UnpackagerBackend.java new file mode 100644 index 0000000000..e7297f0609 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/maps/UnpackagerBackend.java @@ -0,0 +1,53 @@ +package gregtech.api.recipe.maps; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBackendPropertiesBuilder; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class UnpackagerBackend extends RecipeMapBackend { + + public UnpackagerBackend(RecipeMapBackendPropertiesBuilder propertiesBuilder) { + super(propertiesBuilder); + } + + @Override + protected GT_Recipe findFallback(ItemStack[] items, FluidStack[] fluids, @Nullable ItemStack specialSlot) { + if (items.length == 0 || !ItemList.IC2_Scrapbox.isStackEqual(items[0], false, true)) { + return null; + } + + ItemStack output = GT_ModHandler.getRandomScrapboxDrop(); + if (output == null) { + return null; + } + return GT_Values.RA.stdBuilder() + .itemInputs(ItemList.IC2_Scrapbox.get(1)) + .itemOutputs(output) + .duration(16) + .eut(1) + // It is not allowed to be buffered due to the random Output + .noBuffer() + // Due to its randomness it is not good if there are Items in the Output Slot, because those Items could + // manipulate the outcome. + .needsEmptyOutput() + .build() + .orElse(null); + } + + @Override + public boolean containsInput(ItemStack item) { + return ItemList.IC2_Scrapbox.isStackEqual(item, false, true) || super.containsInput(item); + } +} diff --git a/src/main/java/gregtech/api/recipe/metadata/EmptyRecipeMetadataStorage.java b/src/main/java/gregtech/api/recipe/metadata/EmptyRecipeMetadataStorage.java new file mode 100644 index 0000000000..f7831f1485 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/EmptyRecipeMetadataStorage.java @@ -0,0 +1,50 @@ +package gregtech.api.recipe.metadata; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.jetbrains.annotations.Contract; + +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public final class EmptyRecipeMetadataStorage implements IRecipeMetadataStorage { + + public static EmptyRecipeMetadataStorage INSTANCE = new EmptyRecipeMetadataStorage(); + + private EmptyRecipeMetadataStorage() {} + + @Override + public <T> void store(RecipeMetadataKey<T> key, @Nullable T value) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public <T> T getMetadata(RecipeMetadataKey<T> key) { + return null; + } + + @Contract("_, !null -> !null") + @Nullable + @Override + public <T> T getMetadataOrDefault(RecipeMetadataKey<T> key, @Nullable T defaultValue) { + return defaultValue; + } + + @Override + public Set<Map.Entry<RecipeMetadataKey<?>, Object>> getEntries() { + return Collections.emptySet(); + } + + @Override + public IRecipeMetadataStorage copy() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/gregtech/api/recipe/metadata/IRecipeMetadataStorage.java b/src/main/java/gregtech/api/recipe/metadata/IRecipeMetadataStorage.java new file mode 100644 index 0000000000..52141937cf --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/IRecipeMetadataStorage.java @@ -0,0 +1,34 @@ +package gregtech.api.recipe.metadata; + +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.jetbrains.annotations.Contract; + +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +/** + * Stores set of metadata for the recipe with key {@link RecipeMetadataKey}. More explicit way to store various info + * on recipe than special value or special object. Type of the metadata can be anything. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public interface IRecipeMetadataStorage { + + <T> void store(RecipeMetadataKey<T> key, @Nullable T value); + + @Nullable + <T> T getMetadata(RecipeMetadataKey<T> key); + + @Contract("_, !null -> !null") + @Nullable + <T> T getMetadataOrDefault(RecipeMetadataKey<T> key, @Nullable T defaultValue); + + Set<Map.Entry<RecipeMetadataKey<?>, Object>> getEntries(); + + IRecipeMetadataStorage copy(); +} diff --git a/src/main/java/gregtech/api/recipe/metadata/PCBFactoryTierKey.java b/src/main/java/gregtech/api/recipe/metadata/PCBFactoryTierKey.java new file mode 100644 index 0000000000..05db919b57 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/PCBFactoryTierKey.java @@ -0,0 +1,30 @@ +package gregtech.api.recipe.metadata; + +import static gregtech.api.util.GT_Utility.trans; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +/** + * Minimum tier required for the PCB factory recipe. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class PCBFactoryTierKey extends RecipeMetadataKey<Integer> { + + public static final PCBFactoryTierKey INSTANCE = new PCBFactoryTierKey(); + + private PCBFactoryTierKey() { + super(Integer.class, "pcb_factory_tier"); + } + + @Override + public void drawInfo(RecipeDisplayInfo recipeInfo, @Nullable Object value) { + int tier = cast(value, 1); + recipeInfo.drawText(trans("336", "PCB Factory Tier: ") + tier); + } +} diff --git a/src/main/java/gregtech/api/recipe/metadata/PCBFactoryUpgrade.java b/src/main/java/gregtech/api/recipe/metadata/PCBFactoryUpgrade.java new file mode 100644 index 0000000000..6d76ae05c3 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/PCBFactoryUpgrade.java @@ -0,0 +1,7 @@ +package gregtech.api.recipe.metadata; + +public enum PCBFactoryUpgrade { + + NONE, + BIO +} diff --git a/src/main/java/gregtech/api/recipe/metadata/PCBFactoryUpgradeKey.java b/src/main/java/gregtech/api/recipe/metadata/PCBFactoryUpgradeKey.java new file mode 100644 index 0000000000..8257f1e6ef --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/PCBFactoryUpgradeKey.java @@ -0,0 +1,32 @@ +package gregtech.api.recipe.metadata; + +import static gregtech.api.util.GT_Utility.trans; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +/** + * If bio upgrade is required for the PCB factory recipe. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class PCBFactoryUpgradeKey extends RecipeMetadataKey<PCBFactoryUpgrade> { + + public static final PCBFactoryUpgradeKey INSTANCE = new PCBFactoryUpgradeKey(); + + private PCBFactoryUpgradeKey() { + super(PCBFactoryUpgrade.class, "pcb_factory_bio_upgrade"); + } + + @Override + public void drawInfo(RecipeDisplayInfo recipeInfo, @Nullable Object value) { + PCBFactoryUpgrade upgrade = cast(value); + if (upgrade == PCBFactoryUpgrade.BIO) { + recipeInfo.drawText(trans("337", "Upgrade Required: ") + trans("338", "Bio")); + } + } +} diff --git a/src/main/java/gregtech/api/recipe/metadata/RecipeMetadataStorage.java b/src/main/java/gregtech/api/recipe/metadata/RecipeMetadataStorage.java new file mode 100644 index 0000000000..5b65d8a600 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/RecipeMetadataStorage.java @@ -0,0 +1,56 @@ +package gregtech.api.recipe.metadata; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.jetbrains.annotations.Contract; + +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.util.FieldsAreNonnullByDefault; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +public final class RecipeMetadataStorage implements IRecipeMetadataStorage { + + private final Map<RecipeMetadataKey<?>, Object> metadata = new HashMap<>(); + + public RecipeMetadataStorage() {} + + private RecipeMetadataStorage(Map<RecipeMetadataKey<?>, Object> metadata) { + this.metadata.putAll(metadata); + } + + @Override + public <T> void store(RecipeMetadataKey<T> key, @Nullable T value) { + metadata.put(key, key.cast(value)); + } + + @Nullable + @Override + public <T> T getMetadata(RecipeMetadataKey<T> key) { + return key.cast(metadata.get(key)); + } + + @Contract("_, !null -> !null") + @Nullable + @Override + public <T> T getMetadataOrDefault(RecipeMetadataKey<T> key, @Nullable T defaultValue) { + return key.cast(metadata.getOrDefault(key, defaultValue)); + } + + @Override + public Set<Map.Entry<RecipeMetadataKey<?>, Object>> getEntries() { + return metadata.entrySet(); + } + + @Override + public IRecipeMetadataStorage copy() { + return new RecipeMetadataStorage(metadata); + } +} diff --git a/src/main/java/gregtech/api/recipe/metadata/SimpleRecipeMetadataKey.java b/src/main/java/gregtech/api/recipe/metadata/SimpleRecipeMetadataKey.java new file mode 100644 index 0000000000..19395f11a0 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/SimpleRecipeMetadataKey.java @@ -0,0 +1,27 @@ +package gregtech.api.recipe.metadata; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.nei.RecipeDisplayInfo; + +/** + * Simple metadata key that does not draw anything on NEI. + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class SimpleRecipeMetadataKey<T> extends RecipeMetadataKey<T> { + + private SimpleRecipeMetadataKey(Class<T> clazz, String identifier) { + super(clazz, identifier); + } + + public static <T> RecipeMetadataKey<T> create(Class<T> clazz, String identifier) { + return new SimpleRecipeMetadataKey<>(clazz, identifier); + } + + @Override + public void drawInfo(RecipeDisplayInfo recipeInfo, @Nullable Object value) {} +} diff --git a/src/main/java/gregtech/api/util/FieldsAreNonnullByDefault.java b/src/main/java/gregtech/api/util/FieldsAreNonnullByDefault.java new file mode 100644 index 0000000000..1f51aa39a7 --- /dev/null +++ b/src/main/java/gregtech/api/util/FieldsAreNonnullByDefault.java @@ -0,0 +1,18 @@ +package gregtech.api.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.annotation.Nonnull; +import javax.annotation.meta.TypeQualifierDefault; + +/** + * This annotation can be applied to a package or class to indicate that + * the fields in that element are nonnull by default unless there is an explicit nullness annotation. + * </ul> + */ +@Nonnull +@TypeQualifierDefault({ ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface FieldsAreNonnullByDefault {} diff --git a/src/main/java/gregtech/api/util/GT_Config.java b/src/main/java/gregtech/api/util/GT_Config.java index 36585559c2..dc56def68f 100644 --- a/src/main/java/gregtech/api/util/GT_Config.java +++ b/src/main/java/gregtech/api/util/GT_Config.java @@ -139,6 +139,20 @@ public class GT_Config implements Runnable { return rResult; } + public String getWithValidValues(Object aCategory, String aName, String[] validValues, String aDefault) { + if (GT_Utility.isStringInvalid(aName)) return aDefault; + Property tProperty = mConfig.get( + aCategory.toString() + .replaceAll("\\|", "_"), + aName.replaceAll("\\|", "_"), + aDefault, + null, + validValues); + String rResult = tProperty.getString(); + if (!tProperty.wasRead() && GregTech_API.sPostloadFinished) mConfig.save(); + return rResult; + } + @Override public void run() { mConfig.save(); diff --git a/src/main/java/gregtech/api/util/GT_Forestry_Compat.java b/src/main/java/gregtech/api/util/GT_Forestry_Compat.java index 933c379db1..427703e6f7 100644 --- a/src/main/java/gregtech/api/util/GT_Forestry_Compat.java +++ b/src/main/java/gregtech/api/util/GT_Forestry_Compat.java @@ -11,12 +11,13 @@ import forestry.api.recipes.RecipeManagers; import gregtech.api.enums.GT_Values; import gregtech.api.enums.ItemList; import gregtech.api.enums.Materials; +import gregtech.api.recipe.RecipeMaps; public class GT_Forestry_Compat { public static void populateFakeNeiRecipes() { if (ItemList.FR_Bee_Drone.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Bee_Drone.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Bee_Drone.getWithName(1L, "Scanned Drone") }, @@ -28,7 +29,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_Bee_Princess.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Bee_Princess.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Bee_Princess.getWithName(1L, "Scanned Princess") }, @@ -40,7 +41,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_Bee_Queen.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Bee_Queen.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Bee_Queen.getWithName(1L, "Scanned Queen") }, @@ -52,7 +53,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_Tree_Sapling.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Tree_Sapling.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Tree_Sapling.getWithName(1L, "Scanned Sapling") }, @@ -64,7 +65,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_Butterfly.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Butterfly.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Butterfly.getWithName(1L, "Scanned Butterfly") }, @@ -76,7 +77,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_Larvae.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Larvae.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Larvae.getWithName(1L, "Scanned Larvae") }, @@ -88,7 +89,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_Serum.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Serum.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Serum.getWithName(1L, "Scanned Serum") }, @@ -100,7 +101,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_Caterpillar.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_Caterpillar.getWildcard(1L) }, new ItemStack[] { ItemList.FR_Caterpillar.getWithName(1L, "Scanned Caterpillar") }, @@ -112,7 +113,7 @@ public class GT_Forestry_Compat { 0); } if (ItemList.FR_PollenFertile.get(1L) != null) { - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { ItemList.FR_PollenFertile.getWildcard(1L) }, new ItemStack[] { ItemList.FR_PollenFertile.getWithName(1L, "Scanned Pollen") }, @@ -138,7 +139,7 @@ public class GT_Forestry_Compat { .copy(); i++; } - GT_Recipe.GT_Recipe_Map.sCentrifugeRecipes.addRecipe( + RecipeMaps.centrifugeRecipes.addRecipe( true, new ItemStack[] { tRecipe.getInput() }, tOutputs, @@ -149,7 +150,7 @@ public class GT_Forestry_Compat { 128, 5, 0); - GT_Recipe.GT_Recipe_Map.sMultiblockCentrifugeRecipes.addRecipe( + RecipeMaps.centrifugeNonCellRecipes.addRecipe( true, new ItemStack[] { tRecipe.getInput() }, tOutputs, @@ -172,7 +173,7 @@ public class GT_Forestry_Compat { try { for (ISqueezerRecipe tRecipe : RecipeManagers.squeezerManager.recipes()) { if ((tRecipe.getResources().length == 1) && (tRecipe.getFluidOutput() != null)) { - GT_Recipe.GT_Recipe_Map.sFluidExtractionRecipes.addRecipe( + RecipeMaps.fluidExtractionRecipes.addRecipe( true, new ItemStack[] { tRecipe.getResources()[0] }, new ItemStack[] { tRecipe.getRemnants() }, diff --git a/src/main/java/gregtech/api/util/GT_LanguageManager.java b/src/main/java/gregtech/api/util/GT_LanguageManager.java index 76e59eed22..ed82befbcc 100644 --- a/src/main/java/gregtech/api/util/GT_LanguageManager.java +++ b/src/main/java/gregtech/api/util/GT_LanguageManager.java @@ -315,7 +315,6 @@ public class GT_LanguageManager { addStringLocalization("Interaction_DESCRIPTION_Index_151.2", "Outputs 1 specific Fluid"); addStringLocalization("Interaction_DESCRIPTION_Index_151.4", "Successfully locked Fluid to %s"); addStringLocalization("Interaction_DESCRIPTION_Index_152", "Total: "); - addStringLocalization("Interaction_DESCRIPTION_Index_152.1", "Max EU: "); addStringLocalization("Interaction_DESCRIPTION_Index_153", "Usage: "); addStringLocalization("Interaction_DESCRIPTION_Index_154", "Voltage: "); addStringLocalization("Interaction_DESCRIPTION_Index_155", "Amperage: "); diff --git a/src/main/java/gregtech/api/util/GT_ModHandler.java b/src/main/java/gregtech/api/util/GT_ModHandler.java index e16e559360..b83c70d7de 100644 --- a/src/main/java/gregtech/api/util/GT_ModHandler.java +++ b/src/main/java/gregtech/api/util/GT_ModHandler.java @@ -9,9 +9,9 @@ import static gregtech.api.enums.GT_Values.M; import static gregtech.api.enums.GT_Values.RA; import static gregtech.api.enums.GT_Values.V; import static gregtech.api.enums.GT_Values.W; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sAlloySmelterRecipes; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sExtractorRecipes; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sOreWasherRecipes; +import static gregtech.api.recipe.RecipeMaps.alloySmelterRecipes; +import static gregtech.api.recipe.RecipeMaps.extractorRecipes; +import static gregtech.api.recipe.RecipeMaps.oreWasherRecipes; import static gregtech.api.util.GT_RecipeBuilder.SECONDS; import static gregtech.api.util.GT_RecipeBuilder.TICKS; @@ -70,6 +70,8 @@ import gregtech.api.items.GT_MetaBase_Item; import gregtech.api.objects.GT_HashSet; import gregtech.api.objects.GT_ItemStack; import gregtech.api.objects.ItemData; +import gregtech.api.recipe.RecipeCategories; +import gregtech.api.recipe.RecipeMap; import ic2.api.item.IBoxable; import ic2.api.item.IC2Items; import ic2.api.item.IElectricItem; @@ -569,11 +571,12 @@ public class GT_ModHandler { } recipeBuilder.itemOutputs(aOutput) .duration(duration * TICKS) - .eut(3); + .eut(3) + .recipeCategory(RecipeCategories.alloySmelterRecycling); if (hidden) { recipeBuilder.hidden(); } - recipeBuilder.addTo(sAlloySmelterRecipes); + recipeBuilder.addTo(alloySmelterRecipes); return true; } @@ -617,7 +620,7 @@ public class GT_ModHandler { .itemOutputs(aOutput) .duration(15 * SECONDS) .eut(2) - .addTo(sExtractorRecipes); + .addTo(extractorRecipes); return true; } @@ -733,7 +736,7 @@ public class GT_ModHandler { .itemOutputs(aOutput1) .duration(aDuration) .eut(aEUt) - .addTo(sAlloySmelterRecipes); + .addTo(alloySmelterRecipes); return true; } @@ -759,9 +762,8 @@ public class GT_ModHandler { /** * Adds GT versions of the IC2 recipes from the supplied IC2RecipeList. */ - public static void addIC2RecipesToGT(Map<IRecipeInput, RecipeOutput> aIC2RecipeList, - GT_Recipe.GT_Recipe_Map aGTRecipeMap, boolean aAddGTRecipe, boolean aRemoveIC2Recipe, - boolean aExcludeGTIC2Items) { + public static void addIC2RecipesToGT(Map<IRecipeInput, RecipeOutput> aIC2RecipeList, RecipeMap<?> aGTRecipeMap, + boolean aAddGTRecipe, boolean aRemoveIC2Recipe, boolean aExcludeGTIC2Items) { Map<ItemStack, ItemStack> aRecipesToRemove = new HashMap<>(); for (Entry<IRecipeInput, RecipeOutput> iRecipeInputRecipeOutputEntry : aIC2RecipeList.entrySet()) { if (iRecipeInputRecipeOutputEntry.getValue().items.isEmpty()) { @@ -773,7 +775,7 @@ public class GT_ModHandler { continue; } - if (aAddGTRecipe && (aGTRecipeMap.findRecipe(null, false, Long.MAX_VALUE, null, tStack) == null)) { + if (aAddGTRecipe) { try { if (aExcludeGTIC2Items && ((tStack.getUnlocalizedName() .contains("gt.metaitem.01") @@ -784,7 +786,7 @@ public class GT_ModHandler { || tStack.getUnlocalizedName() .contains("ic2.itemPurifiedCrushed")))) continue; - switch (aGTRecipeMap.mUnlocalizedName) { + switch (aGTRecipeMap.unlocalizedName) { case "gt.recipe.macerator", "gt.recipe.extractor", "gt.recipe.compressor" -> aGTRecipeMap .addRecipe( true, @@ -928,7 +930,7 @@ public class GT_ModHandler { .fluidInputs(GT_ModHandler.getWater(aWaterAmount)) .duration(25 * SECONDS) .eut(16) - .addTo(sOreWasherRecipes); + .addTo(oreWasherRecipes); RA.stdBuilder() .itemInputs(aInput) @@ -937,7 +939,7 @@ public class GT_ModHandler { .fluidInputs(GT_ModHandler.getDistilledWater(aWaterAmount / 5)) .duration(15 * SECONDS) .eut(16) - .addTo(sOreWasherRecipes); + .addTo(oreWasherRecipes); return true; } @@ -950,7 +952,7 @@ public class GT_ModHandler { .fluidInputs(GT_ModHandler.getWater(aWaterAmount)) .duration(25 * SECONDS) .eut(16) - .addTo(sOreWasherRecipes); + .addTo(oreWasherRecipes); RA.stdBuilder() .itemInputs(aInput) @@ -958,7 +960,7 @@ public class GT_ModHandler { .fluidInputs(GT_ModHandler.getDistilledWater(aWaterAmount / 5)) .duration(15 * SECONDS) .eut(16) - .addTo(sOreWasherRecipes); + .addTo(oreWasherRecipes); return true; } diff --git a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java index 582b65e7ec..8e896fd8de 100644 --- a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java +++ b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java @@ -198,14 +198,6 @@ public class GT_OverclockCalculator { } /** - * Use {@link #setHeatOC(boolean)} - */ - @Deprecated - public GT_OverclockCalculator enableHeatOC() { - return setHeatOC(true); - } - - /** * Set if we should be calculating overclocking using EBF's perfectOC */ public GT_OverclockCalculator setHeatOC(boolean heatOC) { @@ -214,14 +206,6 @@ public class GT_OverclockCalculator { } /** - * Use {@link #setHeatDiscount(boolean)} - */ - @Deprecated - public GT_OverclockCalculator enableHeatDiscount() { - return setHeatDiscount(true); - } - - /** * Sets if we should add a heat discount at the end of calculating an overclock, just like the EBF */ public GT_OverclockCalculator setHeatDiscount(boolean heatDiscount) { @@ -238,14 +222,6 @@ public class GT_OverclockCalculator { } /** - * Use {@link #setMachineHeat(int)} - */ - @Deprecated - public GT_OverclockCalculator setMultiHeat(int machineHeat) { - return setMachineHeat(machineHeat); - } - - /** * Sets the heat of the coils on the machine */ public GT_OverclockCalculator setMachineHeat(int machineHeat) { @@ -313,14 +289,6 @@ public class GT_OverclockCalculator { } /** - * Use {@link #setOneTickDiscount(boolean)} - */ - @Deprecated - public GT_OverclockCalculator enableOneTickDiscount() { - return setOneTickDiscount(true); - } - - /** * Set One Tick Discount on EUt based on Duration Decrease Per Overclock. This functions the same as single * blocks. */ @@ -556,7 +524,7 @@ public class GT_OverclockCalculator { /** * Returns the EUt consumption one would get from overclocking under 1 tick * This Doesn't count as calculating - * + * * @param originalMaxParallel Parallels which are of the actual machine before the overclocking extra ones */ public long calculateEUtConsumptionUnderOneTick(int originalMaxParallel, int currentParallel) { diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java index d3921b613d..8a5cd0b9f8 100644 --- a/src/main/java/gregtech/api/util/GT_ParallelHelper.java +++ b/src/main/java/gregtech/api/util/GT_ParallelHelper.java @@ -10,8 +10,8 @@ import net.minecraftforge.fluids.FluidStack; import gregtech.api.interfaces.tileentity.IRecipeLockable; import gregtech.api.interfaces.tileentity.IVoidable; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; import gregtech.api.objects.XSTR; +import gregtech.api.recipe.RecipeMap; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.recipe.check.SingleRecipeCheck; @@ -124,27 +124,6 @@ public class GT_ParallelHelper { public GT_ParallelHelper() {} /** - * Sets MetaTE controller, with current configuration for void protection mode. - * - * @deprecated Use {@link #setMachine(IVoidable)} - */ - @Deprecated - public GT_ParallelHelper setController(GT_MetaTileEntity_MultiBlockBase machineMeta) { - return setMachine(machineMeta, machineMeta.protectsExcessItem(), machineMeta.protectsExcessFluid()); - } - - /** - * Sets MetaTE controller, with void protection mode forcibly. - * - * @deprecated Use {@link #setMachine(IVoidable, boolean, boolean)} - */ - @Deprecated - public GT_ParallelHelper setController(GT_MetaTileEntity_MultiBlockBase machineMeta, boolean protectExcessItem, - boolean protectExcessFluid) { - return setMachine(machineMeta, protectExcessItem, protectExcessFluid); - } - - /** * Sets machine, with current configuration for void protection mode. */ public GT_ParallelHelper setMachine(IVoidable machine) { @@ -213,14 +192,6 @@ public class GT_ParallelHelper { } /** - * Use {@link #setConsumption(boolean)} - */ - @Deprecated - public GT_ParallelHelper enableConsumption() { - return setConsumption(true); - } - - /** * Set if we should consume inputs or not when trying for parallels * * @param consume Should we consume inputs @@ -249,14 +220,6 @@ public class GT_ParallelHelper { } /** - * Use {@link #setOutputCalculation(boolean)} - */ - @Deprecated - public GT_ParallelHelper enableOutputCalculation() { - return setOutputCalculation(true); - } - - /** * Sets if we should calculate outputs with the parallels we found or not * * @param calculateOutputs Should we calculate outputs with the helper or not @@ -339,14 +302,6 @@ public class GT_ParallelHelper { } /** - * @deprecated Use {@link #getDurationMultiplierDouble()} - */ - @Deprecated - public float getDurationMultiplier() { - return (float) getDurationMultiplierDouble(); - } - - /** * @return The ItemOutputs from the recipe */ @Nonnull @@ -382,23 +337,6 @@ public class GT_ParallelHelper { } /** - * @deprecated Use {@link #setMaxParallelCalculator} and {@link #setInputConsumer} - */ - @Deprecated - protected boolean tryConsumeRecipeInputs(GT_Recipe recipe, FluidStack[] fluids, ItemStack[] items) { - return false; - } - - /** - * @deprecated Use {@link #setMaxParallelCalculator} and {@link #setInputConsumer} - */ - @Deprecated - protected boolean tryConsumeRecipeInputs(GT_Recipe recipe, FluidStack[] fluids, ItemStack[] items, - int minParallel) { - return false; - } - - /** * Called by build(). Determines the parallels and everything else that needs to be done at build time */ protected void determineParallel() { @@ -446,7 +384,7 @@ public class GT_ParallelHelper { if (recipeCheck == null) { // Machine is configured to lock to a single recipe, but haven't built the recipe checker yet. // Build the checker on next successful recipe. - GT_Recipe.GT_Recipe_Map recipeMap = singleRecipeMachine.getRecipeMap(); + RecipeMap<?> recipeMap = singleRecipeMachine.getRecipeMap(); if (recipeMap != null) { tSingleRecipeCheckBuilder = SingleRecipeCheck.builder(recipeMap) .setBefore(itemInputs, fluidInputs); diff --git a/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java b/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java index 7ff37a927c..ead9393d0e 100644 --- a/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java +++ b/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java @@ -5,24 +5,24 @@ import java.util.HashMap; import net.minecraft.item.ItemStack; import gregtech.api.enums.SoundResource; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; +import gregtech.api.recipe.RecipeMap; @Deprecated public class GT_ProcessingArray_Manager { - private static final HashMap<String, GT_Recipe_Map> mRecipeSaves = new HashMap<>(); + private static final HashMap<String, RecipeMap<?>> mRecipeSaves = new HashMap<>(); private static final HashMap<String, SoundResource> machineSounds = new HashMap<>(); // Adds recipe Maps to the PA using the machines unlocalized name. // Example: basicmachine.electrolyzer, with its recipe map will add the electrolyzer's recipe map to the PA - public static void addRecipeMapToPA(String aMachineName, GT_Recipe_Map aMap) { + public static void addRecipeMapToPA(String aMachineName, RecipeMap<?> aMap) { if (aMachineName != null) { mRecipeSaves.put(aMachineName, aMap); } } // Allows the PA to extract the recipe map for the machine inside it. - public static GT_Recipe_Map giveRecipeMap(String aMachineName) { + public static RecipeMap<?> giveRecipeMap(String aMachineName) { if (aMachineName != null) { return mRecipeSaves.get(aMachineName); } diff --git a/src/main/java/gregtech/api/util/GT_Recipe.java b/src/main/java/gregtech/api/util/GT_Recipe.java index 535da25934..a444a16ef2 100644 --- a/src/main/java/gregtech/api/util/GT_Recipe.java +++ b/src/main/java/gregtech/api/util/GT_Recipe.java @@ -1,148 +1,38 @@ package gregtech.api.util; -import static gregtech.api.enums.GT_Values.D1; import static gregtech.api.enums.GT_Values.D2; -import static gregtech.api.enums.GT_Values.E; -import static gregtech.api.enums.GT_Values.L; -import static gregtech.api.enums.GT_Values.W; -import static gregtech.api.enums.Mods.GTPlusPlus; -import static gregtech.api.enums.Mods.GregTech; -import static gregtech.api.enums.Mods.NEICustomDiagrams; -import static gregtech.api.enums.Mods.Railcraft; -import static gregtech.api.recipe.check.FindRecipeResult.EXPLODE; -import static gregtech.api.recipe.check.FindRecipeResult.NOT_FOUND; -import static gregtech.api.recipe.check.FindRecipeResult.ON_FIRE; -import static gregtech.api.recipe.check.FindRecipeResult.ofSuccess; -import static gregtech.api.util.GT_RecipeBuilder.handleRecipeCollision; -import static gregtech.api.util.GT_RecipeConstants.ADDITIVE_AMOUNT; -import static gregtech.api.util.GT_RecipeMapUtil.FIRST_FLUIDSTACK_INPUT; -import static gregtech.api.util.GT_RecipeMapUtil.FIRST_FLUIDSTACK_OUTPUT; -import static gregtech.api.util.GT_RecipeMapUtil.FIRST_FLUID_OUTPUT; -import static gregtech.api.util.GT_RecipeMapUtil.FIRST_ITEM_INPUT; -import static gregtech.api.util.GT_RecipeMapUtil.FIRST_ITEM_OR_FLUID_INPUT; -import static gregtech.api.util.GT_RecipeMapUtil.FIRST_ITEM_OR_FLUID_OUTPUT; -import static gregtech.api.util.GT_RecipeMapUtil.FIRST_ITEM_OUTPUT; -import static gregtech.api.util.GT_RecipeMapUtil.GT_RecipeTemplate; -import static gregtech.api.util.GT_RecipeMapUtil.SPECIAL_VALUE_ALIASES; -import static gregtech.api.util.GT_RecipeMapUtil.asTemplate; -import static gregtech.api.util.GT_RecipeMapUtil.buildOrEmpty; -import static gregtech.api.util.GT_Utility.formatNumbers; -import static gregtech.api.util.GT_Utility.isArrayEmptyOrNull; -import static gregtech.api.util.GT_Utility.isArrayOfLength; -import static net.minecraft.util.EnumChatFormatting.GRAY; -import static net.minecraft.util.StatCollector.translateToLocal; -import java.awt.Rectangle; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.tileentity.TileEntityFurnace; -import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidContainerRegistry; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidContainerItem; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Contract; -import com.google.common.collect.Iterables; -import com.gtnewhorizons.modularui.api.GlStateManager; -import com.gtnewhorizons.modularui.api.ModularUITextures; -import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; -import com.gtnewhorizons.modularui.api.drawable.IDrawable; -import com.gtnewhorizons.modularui.api.drawable.UITexture; -import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; -import com.gtnewhorizons.modularui.api.math.Alignment; -import com.gtnewhorizons.modularui.api.math.Pos2d; -import com.gtnewhorizons.modularui.api.math.Size; -import com.gtnewhorizons.modularui.api.screen.ModularWindow; -import com.gtnewhorizons.modularui.common.widget.DrawableWidget; -import com.gtnewhorizons.modularui.common.widget.ProgressBar; -import com.gtnewhorizons.modularui.common.widget.SlotWidget; - -import appeng.util.ReadableNumberConverter; -import codechicken.lib.gui.GuiDraw; -import codechicken.nei.PositionedStack; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; -import gnu.trove.map.TByteObjectMap; -import gnu.trove.map.hash.TByteObjectHashMap; import gregtech.GT_Mod; import gregtech.api.GregTech_API; -import gregtech.api.enums.ConfigCategories; -import gregtech.api.enums.Dyes; -import gregtech.api.enums.Element; -import gregtech.api.enums.GT_Values; import gregtech.api.enums.ItemList; import gregtech.api.enums.Materials; -import gregtech.api.enums.OrePrefixes; -import gregtech.api.enums.SteamVariant; -import gregtech.api.enums.SubTag; -import gregtech.api.gui.GT_GUIColorOverride; -import gregtech.api.gui.modularui.FallbackableSteamTexture; -import gregtech.api.gui.modularui.GT_UITextures; -import gregtech.api.gui.modularui.SteamTexture; -import gregtech.api.interfaces.IGT_RecipeMap; -import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; import gregtech.api.objects.GT_ItemStack; -import gregtech.api.objects.ItemData; -import gregtech.api.objects.MaterialStack; -import gregtech.api.recipe.check.FindRecipeResult; +import gregtech.api.recipe.RecipeCategory; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.recipe.metadata.EmptyRecipeMetadataStorage; +import gregtech.api.recipe.metadata.IRecipeMetadataStorage; import gregtech.api.util.extensions.ArrayExt; -import gregtech.common.gui.modularui.UIHelper; -import gregtech.common.items.GT_FluidDisplayItem; -import gregtech.common.misc.spaceprojects.SpaceProjectManager; -import gregtech.common.misc.spaceprojects.interfaces.ISpaceProject; -import gregtech.common.power.EUPower; -import gregtech.common.power.Power; -import gregtech.common.power.UnspecifiedEUPower; -import gregtech.common.tileentities.machines.basic.GT_MetaTileEntity_Replicator; -import gregtech.nei.FusionSpecialValueFormatter; -import gregtech.nei.GT_NEI_DefaultHandler; -import gregtech.nei.HeatingCoilSpecialValueFormatter; -import gregtech.nei.INEISpecialInfoFormatter; -import gregtech.nei.NEIRecipeInfo; import ic2.core.Ic2Items; -import mods.railcraft.common.blocks.aesthetics.cube.EnumCube; -import mods.railcraft.common.items.RailcraftToolItems; -/** - * NEVER INCLUDE THIS FILE IN YOUR MOD!!! - * <p/> - * This File contains the functions used for Recipes. Please do not include this File AT ALL in your Moddownload as it - * ruins compatibility This is just the Core of my Recipe System, if you just want to GET the Recipes I add, then you - * can access this File. Do NOT add Recipes using the Constructors inside this Class, The GregTech_API File calls the - * correct Functions for these Constructors. - * <p/> - * I know this File causes some Errors, because of missing Main Functions, but if you just need to compile Stuff, then - * remove said erroreous Functions. - */ public class GT_Recipe implements Comparable<GT_Recipe> { /** @@ -200,13 +90,24 @@ public class GT_Recipe implements Comparable<GT_Recipe> { */ private String[] neiDesc = null; /** + * Holds a set of metadata for this recipe. + */ + @Nonnull + private final IRecipeMetadataStorage metadataStorage; + /** + * Category this recipe belongs to. Recipes belonging to recipemap are forced to have non-null category when added, + * otherwise it can be null. + */ + private RecipeCategory recipeCategory; + /** * Stores which mod added this recipe */ public List<ModContainer> owners = new ArrayList<>(); /** * Stores stack traces where this recipe was added */ - public List<List<StackTraceElement>> stackTraces = new ArrayList<>(); + // BW wants to overwrite it, so no final + public List<List<String>> stackTraces = new ArrayList<>(); private GT_Recipe(GT_Recipe aRecipe, boolean shallow) { mInputs = shallow ? aRecipe.mInputs : GT_Utility.copyItemArray(aRecipe.mInputs); @@ -219,18 +120,23 @@ public class GT_Recipe implements Comparable<GT_Recipe> { mSpecialValue = aRecipe.mSpecialValue; mEUt = aRecipe.mEUt; mNeedsEmptyOutput = aRecipe.mNeedsEmptyOutput; + isNBTSensitive = aRecipe.isNBTSensitive; mCanBeBuffered = aRecipe.mCanBeBuffered; mFakeRecipe = aRecipe.mFakeRecipe; mEnabled = aRecipe.mEnabled; mHidden = aRecipe.mHidden; + metadataStorage = EmptyRecipeMetadataStorage.INSTANCE; owners = new ArrayList<>(aRecipe.owners); reloadOwner(); } - // only used for GT_RecipeBuilder. Should not be called otherwise + /** + * Only for {@link GT_RecipeBuilder}. + */ GT_Recipe(ItemStack[] mInputs, ItemStack[] mOutputs, FluidStack[] mFluidInputs, FluidStack[] mFluidOutputs, int[] mChances, Object mSpecialItems, int mDuration, int mEUt, int mSpecialValue, boolean mEnabled, - boolean mHidden, boolean mFakeRecipe, boolean mCanBeBuffered, boolean mNeedsEmptyOutput, String[] neiDesc) { + boolean mHidden, boolean mFakeRecipe, boolean mCanBeBuffered, boolean mNeedsEmptyOutput, boolean nbtSensitive, + String[] neiDesc, @Nullable IRecipeMetadataStorage metadataStorage, RecipeCategory recipeCategory) { this.mInputs = mInputs; this.mOutputs = mOutputs; this.mFluidInputs = mFluidInputs; @@ -245,7 +151,10 @@ public class GT_Recipe implements Comparable<GT_Recipe> { this.mFakeRecipe = mFakeRecipe; this.mCanBeBuffered = mCanBeBuffered; this.mNeedsEmptyOutput = mNeedsEmptyOutput; + this.isNBTSensitive = nbtSensitive; this.neiDesc = neiDesc; + this.metadataStorage = metadataStorage == null ? EmptyRecipeMetadataStorage.INSTANCE : metadataStorage.copy(); + this.recipeCategory = recipeCategory; reloadOwner(); } @@ -311,19 +220,11 @@ public class GT_Recipe implements Comparable<GT_Recipe> { mDuration = aDuration; mSpecialValue = aSpecialValue; mEUt = aEUt; + metadataStorage = EmptyRecipeMetadataStorage.INSTANCE; // checkCellBalance(); reloadOwner(); } - public GT_Recipe(ItemStack aInput1, ItemStack aOutput1, int aFuelValue, int aType) { - this(aInput1, aOutput1, null, null, null, aFuelValue, aType); - } - - private static FluidStack[] tryGetFluidInputsFromCells(ItemStack aInput) { - FluidStack tFluid = GT_Utility.getFluidForFilledItem(aInput, true); - return tFluid == null ? null : new FluidStack[] { tFluid }; - } - // aSpecialValue = EU per Liter! If there is no Liquid for this Object, then it gets multiplied with 1000! public GT_Recipe(ItemStack aInput1, ItemStack aOutput1, ItemStack aOutput2, ItemStack aOutput3, ItemStack aOutput4, int aSpecialValue, int aType) { @@ -343,208 +244,32 @@ public class GT_Recipe implements Comparable<GT_Recipe> { switch (aType) { // Diesel Generator case 0 -> { - GT_Recipe_Map.sDieselFuels.addRecipe(this); - GT_Recipe_Map.sLargeBoilerFakeFuels.addDieselRecipe(this); + RecipeMaps.dieselFuels.addRecipe(this); + RecipeMaps.largeBoilerFakeFuels.getBackend() + .addDieselRecipe(this); } // Gas Turbine - case 1 -> GT_Recipe_Map.sTurbineFuels.addRecipe(this); + case 1 -> RecipeMaps.gasTurbineFuels.addRecipe(this); // Thermal Generator - case 2 -> GT_Recipe_Map.sHotFuels.addRecipe(this); + case 2 -> RecipeMaps.hotFuels.addRecipe(this); // Plasma Generator - case 4 -> GT_Recipe_Map.sPlasmaFuels.addRecipe(this); + case 4 -> RecipeMaps.plasmaFuels.addRecipe(this); // Magic Generator - case 5 -> GT_Recipe_Map.sMagicFuels.addRecipe(this); + case 5 -> RecipeMaps.magicFuels.addRecipe(this); // Fluid Generator. Usually 3. Every wrong Type ends up in the Semifluid Generator default -> { - GT_Recipe_Map.sDenseLiquidFuels.addRecipe(this); - GT_Recipe_Map.sLargeBoilerFakeFuels.addDenseLiquidRecipe(this); + RecipeMaps.denseLiquidFuels.addRecipe(this); + RecipeMaps.largeBoilerFakeFuels.getBackend() + .addDenseLiquidRecipe(this); } } } } - public GT_Recipe(FluidStack aInput1, FluidStack aInput2, FluidStack aOutput1, int aDuration, int aEUt, - int aSpecialValue) { - this( - true, - null, - null, - null, - null, - new FluidStack[] { aInput1, aInput2 }, - new FluidStack[] { aOutput1 }, - Math.max(aDuration, 1), - aEUt, - Math.max(Math.min(aSpecialValue, 160000000), 0)); - if (mInputs.length > 1) { - GT_Recipe_Map.sFusionRecipes.addRecipe(this); - } - } - - public GT_Recipe(ItemStack aInput1, ItemStack aOutput1, ItemStack aOutput2, int aDuration, int aEUt) { - this( - true, - new ItemStack[] { aInput1 }, - new ItemStack[] { aOutput1, aOutput2 }, - null, - null, - null, - null, - aDuration, - aEUt, - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sLatheRecipes.addRecipe(this); - } - } - - public GT_Recipe(ItemStack aInput1, int aCellAmount, ItemStack aOutput1, ItemStack aOutput2, ItemStack aOutput3, - ItemStack aOutput4, int aDuration, int aEUt) { - this( - true, - new ItemStack[] { aInput1, - aCellAmount > 0 ? ItemList.Cell_Empty.get(Math.min(64, Math.max(1, aCellAmount))) : null }, - new ItemStack[] { aOutput1, aOutput2, aOutput3, aOutput4 }, - null, - null, - null, - null, - Math.max(aDuration, 1), - Math.max(aEUt, 1), - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sDistillationRecipes.addRecipe(this); - } - } - - public GT_Recipe(ItemStack aInput1, int aInput2, ItemStack aOutput1, ItemStack aOutput2) { - this( - true, - new ItemStack[] { aInput1, - GT_ModHandler.getIC2Item( - "industrialTnt", - aInput2 > 0 ? Math.min(aInput2, 64) : 1, - new ItemStack(Blocks.tnt, aInput2 > 0 ? Math.min(aInput2, 64) : 1)) }, - new ItemStack[] { aOutput1, aOutput2 }, - null, - null, - null, - null, - 20, - 30, - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sImplosionRecipes.addRecipe(this); - } - } - - public GT_Recipe(int aEUt, int aDuration, ItemStack aInput1, ItemStack aOutput1) { - this( - true, - new ItemStack[] { aInput1, ItemList.Circuit_Integrated.getWithDamage(0, aInput1.stackSize) }, - new ItemStack[] { aOutput1 }, - null, - null, - null, - null, - Math.max(aDuration, 1), - Math.max(aEUt, 1), - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sBenderRecipes.addRecipe(this); - } - } - - public GT_Recipe(ItemStack aInput1, ItemStack aInput2, int aEUt, int aDuration, ItemStack aOutput1) { - this( - true, - aInput2 == null ? new ItemStack[] { aInput1 } : new ItemStack[] { aInput1, aInput2 }, - new ItemStack[] { aOutput1 }, - null, - null, - null, - null, - Math.max(aDuration, 1), - Math.max(aEUt, 1), - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sAlloySmelterRecipes.addRecipe(this); - } - } - - public GT_Recipe(ItemStack aInput1, int aEUt, ItemStack aInput2, int aDuration, ItemStack aOutput1, - ItemStack aOutput2) { - this( - true, - aInput2 == null ? new ItemStack[] { aInput1 } : new ItemStack[] { aInput1, aInput2 }, - new ItemStack[] { aOutput1, aOutput2 }, - null, - null, - null, - null, - Math.max(aDuration, 1), - Math.max(aEUt, 1), - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sCannerRecipes.addRecipe(this); - } - } - - public GT_Recipe(ItemStack aInput1, ItemStack aOutput1, int aDuration) { - this( - true, - new ItemStack[] { aInput1 }, - new ItemStack[] { aOutput1 }, - null, - null, - null, - null, - Math.max(aDuration, 1), - 120, - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sVacuumRecipes.addRecipe(this); - } - } - - public GT_Recipe(ItemStack aInput1, ItemStack aOutput1, int aDuration, int aEUt, int VACUUM) { - this( - true, - new ItemStack[] { aInput1 }, - new ItemStack[] { aOutput1 }, - null, - null, - null, - null, - Math.max(aDuration, 1), - aEUt, - 0); - if (mInputs.length > 0 && mOutputs[0] != null) { - GT_Recipe_Map.sVacuumRecipes.addRecipe(this); - } - } - - public GT_Recipe(FluidStack aInput1, FluidStack aOutput1, int aDuration, int aEUt) { - this( - false, - null, - null, - null, - null, - new FluidStack[] { aInput1 }, - new FluidStack[] { aOutput1 }, - Math.max(aDuration, 1), - aEUt, - 0); - if (mFluidInputs.length > 0 && mFluidOutputs[0] != null) { - GT_Recipe_Map.sVacuumRecipes.addRecipe(this); - } - } - // Dummy GT_Recipe maker... public GT_Recipe(ItemStack[] aInputs, ItemStack[] aOutputs, Object aSpecialItems, int[] aChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue) { @@ -561,15 +286,17 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aSpecialValue); } + /** + * Re-unificates all the items present in recipes. + */ public static void reInit() { GT_Log.out.println("GT_Mod: Re-Unificating Recipes."); - for (GT_Recipe_Map tMapEntry : GT_Recipe_Map.sMappings) tMapEntry.reInit(); + for (RecipeMap<?> map : RecipeMap.ALL_RECIPE_MAPS.values()) { + map.getBackend() + .reInit(); + } } - // ----- - // Old Constructors, do not use! - // ----- - public ItemStack getRepresentativeInput(int aIndex) { if (aIndex < 0 || aIndex >= mInputs.length) return null; return GT_Utility.copyOrNull(mInputs[aIndex]); @@ -580,16 +307,14 @@ public class GT_Recipe implements Comparable<GT_Recipe> { return GT_Utility.copyOrNull(mOutputs[aIndex]); } - /*** + /** * Dictates the ItemStacks displayed in the output slots of any NEI page handled by the default GT NEI handler. * Override to make shown items differ from a GT_Recipe's item output array * * @see gregtech.nei.GT_NEI_DefaultHandler * @param i Slot index * @return ItemStack to be displayed in the slot - * */ - // public ItemStack getRepresentativeOutput(int i) { return getOutput(i); } @@ -851,59 +576,100 @@ public class GT_Recipe implements Comparable<GT_Recipe> { /** * Sets description shown on NEI. <br> * If you have a large number of recipes for the recipemap, this is not efficient memory wise, so use - * {@link GT_Recipe_Map#setNEISpecialInfoFormatter} instead. + * {@link gregtech.api.recipe.RecipeMapBuilder#neiSpecialInfoFormatter} instead. */ - protected void setNeiDesc(String... neiDesc) { + public void setNeiDesc(String... neiDesc) { this.neiDesc = neiDesc; } + // region metadata + + // Don't try implementing setMetadata, as metadataStorage can be EmptyRecipeMetadataStorage + + /** + * Gets metadata associated with this recipe. Can return null. Use + * {@link #getMetadataOrDefault(RecipeMetadataKey, Object)} + * if you want to specify default value. + */ + @Nullable + public <T> T getMetadata(RecipeMetadataKey<T> key) { + return key.cast(metadataStorage.getMetadata(key)); + } + /** - * Use {@link GT_Recipe_Map#getItemInputPositions} or {@link GT_Recipe_Map#getSpecialItemPosition} or - * {@link GT_Recipe_Map#getFluidInputPositions} instead + * Gets metadata associated with this recipe with default value. Does not return null unless default value is null. */ - @SuppressWarnings("DeprecatedIsStillUsed") - @Deprecated - public ArrayList<PositionedStack> getInputPositionedStacks() { - return null; + @Contract("_, !null -> !null") + @Nullable + public <T> T getMetadataOrDefault(RecipeMetadataKey<T> key, @Nullable T defaultValue) { + return key.cast(metadataStorage.getMetadataOrDefault(key, defaultValue)); + } + + @Nonnull + public IRecipeMetadataStorage getMetadataStorage() { + return metadataStorage; + } + + // endregion + + public RecipeCategory getRecipeCategory() { + return recipeCategory; } /** - * Use {@link GT_Recipe_Map#getItemOutputPositions} or {@link GT_Recipe_Map#getFluidOutputPositions} instead + * Exists only for recipe copying from external. For ordinal use case, use {@link GT_RecipeBuilder#recipeCategory}. */ - @SuppressWarnings("DeprecatedIsStillUsed") - @Deprecated - public ArrayList<PositionedStack> getOutputPositionedStacks() { - return null; + public void setRecipeCategory(RecipeCategory recipeCategory) { + this.recipeCategory = recipeCategory; } + private static final List<String> excludedStacktraces = Arrays.asList( + "java.lang.Thread", + "gregtech.api.interfaces.IRecipeMap", + "gregtech.api.interfaces.IRecipeMap$1", + "gregtech.api.recipe.RecipeMap", + "gregtech.api.recipe.RecipeMapBackend", + "gregtech.api.recipe.RecipeMapBackendPropertiesBuilder", + "gregtech.api.util.GT_Recipe", + "gregtech.api.util.GT_RecipeBuilder", + "gregtech.api.util.GT_RecipeConstants", + "gregtech.api.util.GT_RecipeMapUtil", + "gregtech.common.GT_RecipeAdder"); + public void reloadOwner() { setOwner( Loader.instance() .activeModContainer()); - final List<String> excludedClasses = Arrays.asList( - "java.lang.Thread", - "gregtech.api.util.GT_Recipe", - "gregtech.api.util.GT_RecipeBuilder", - "gregtech.api.util.GT_Recipe$GT_Recipe_Map", - "gregtech.common.GT_RecipeAdder"); if (GT_Mod.gregtechproxy.mNEIRecipeOwnerStackTrace) { - List<StackTraceElement> toAdd = new ArrayList<>(); + List<String> toAdd = new ArrayList<>(); for (StackTraceElement stackTrace : Thread.currentThread() .getStackTrace()) { - if (excludedClasses.stream() + if (excludedStacktraces.stream() .noneMatch( c -> stackTrace.getClassName() .equals(c))) { - toAdd.add(stackTrace); + toAdd.add(formatStackTrace(stackTrace)); } } stackTraces.add(toAdd); } } + private static String formatStackTrace(StackTraceElement stackTraceElement) { + String raw = stackTraceElement.toString(); + int startParen = raw.lastIndexOf('('); + int colon = raw.lastIndexOf(':'); + if (colon == -1) { + // native or unknown source + return raw; + } + // strip class name and leave line number, as class name is already shown + return raw.substring(0, startParen + 1) + raw.substring(colon); + } + public void setOwner(ModContainer newOwner) { - ModContainer oldOwner = owners.size() > 0 ? this.owners.get(owners.size() - 1) : null; + ModContainer oldOwner = !owners.isEmpty() ? this.owners.get(owners.size() - 1) : null; if (newOwner != null && newOwner != oldOwner) { owners.add(newOwner); } @@ -1144,5146 +910,19 @@ public class GT_Recipe implements Comparable<GT_Recipe> { } } - @SuppressWarnings("StaticInitializerReferencesSubClass") - public static class GT_Recipe_Map implements IGT_RecipeMap { - - /** - * Contains all Recipe Maps - */ - public static final Collection<GT_Recipe_Map> sMappings = new ArrayList<>(); - /** - * All recipe maps indexed by their {@link #mUniqueIdentifier}. - */ - public static final Map<String, GT_Recipe_Map> sIndexedMappings = new HashMap<>(); - - static final String TEXTURES_GUI_BASICMACHINES = "textures/gui/basicmachines"; - public static final GT_Recipe_Map sOreWasherRecipes = new GT_Recipe_Map( - new HashSet<>(500), - "gt.recipe.orewasher", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "OreWasher"), - 1, - 3, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_DUST) - .setRecipeConfigFile("orewasher", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_BATH, ProgressBar.Direction.CIRCULAR_CW); - public static final GT_Recipe_Map sThermalCentrifugeRecipes = new GT_Recipe_Map( - new HashSet<>(1000), - "gt.recipe.thermalcentrifuge", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "ThermalCentrifuge"), - 1, - 3, - 1, - 0, - 2, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_DUST) - .setRecipeConfigFile("thermalcentrifuge", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sCompressorRecipes = new GT_Recipe_Map( - new HashSet<>(750), - "gt.recipe.compressor", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Compressor"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_COMPRESSOR) - .setRecipeConfigFile("compressor", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_COMPRESS, ProgressBar.Direction.RIGHT) - .setSlotOverlaySteam(false, GT_UITextures.OVERLAY_SLOT_COMPRESSOR_STEAM) - .setProgressBarSteam(GT_UITextures.PROGRESSBAR_COMPRESS_STEAM); - public static final GT_Recipe_Map sExtractorRecipes = new GT_Recipe_Map( - new HashSet<>(250), - "gt.recipe.extractor", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Extractor"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CENTRIFUGE) - .setRecipeConfigFile("extractor", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_EXTRACT, ProgressBar.Direction.RIGHT) - .setSlotOverlaySteam(false, GT_UITextures.OVERLAY_SLOT_CENTRIFUGE_STEAM) - .setProgressBarSteam(GT_UITextures.PROGRESSBAR_EXTRACT_STEAM); - public static final GT_Recipe_Map sRecyclerRecipes = new GT_Recipe_Map_Recycler( - new HashSet<>(0), - "ic.recipe.recycler", - null, - "ic2.recycler", - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Recycler"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - false).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_RECYCLE) - .setProgressBar(GT_UITextures.PROGRESSBAR_RECYCLE, ProgressBar.Direction.CIRCULAR_CW); - public static final GT_Recipe_Map sFurnaceRecipes = new GT_Recipe_Map_Furnace( - new HashSet<>(0), - "mc.recipe.furnace", - "Furnace", - "smelting", - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "E_Furnace"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - false).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_FURNACE) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setSlotOverlaySteam(false, GT_UITextures.OVERLAY_SLOT_FURNACE_STEAM) - .setProgressBarSteam(GT_UITextures.PROGRESSBAR_ARROW_STEAM); - public static final GT_Recipe_Map sMicrowaveRecipes = new GT_Recipe_Map_Microwave( - new HashSet<>(0), - "gt.recipe.microwave", - null, - "smelting", - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "E_Furnace"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - false).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_FURNACE) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - - public static final GT_Recipe_Map sScannerFakeRecipes = new GT_Recipe_Map( - new HashSet<>(300), - "gt.recipe.scanner", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Scanner"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_MICROSCOPE) - .setSlotOverlay(false, false, true, true, GT_UITextures.OVERLAY_SLOT_DATA_ORB) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sRockBreakerFakeRecipes = new GT_Recipe_Map( - new HashSet<>(200), - "gt.recipe.rockbreaker", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "RockBreaker"), - 2, - 1, - 0, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_DUST) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE) - .setProgressBar(GT_UITextures.PROGRESSBAR_MACERATE, ProgressBar.Direction.RIGHT); - @Deprecated - public static final GT_Recipe_Map sByProductList = new GT_Recipe_Map( - new HashSet<>(1000), - "gt.recipe.byproductlist", - "Ore Byproduct List", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 6, - 1, - 0, - 1, - E, - 1, - E, - true, - false).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sReplicatorFakeRecipes = new ReplicatorFakeMap( - new HashSet<>(100), - "gt.recipe.replicator", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Replicator"), - 0, - 1, - 0, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CANISTER) - .setSlotOverlay(true, false, GT_UITextures.OVERLAY_SLOT_UUM) - .setSlotOverlay(false, false, true, true, GT_UITextures.OVERLAY_SLOT_DATA_ORB) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sAssemblylineVisualRecipes = new GT_Recipe_Map_AssemblyLineFake( - new HashSet<>(110), - "gt.recipe.fakeAssemblylineProcess", - "Assemblyline Process", - null, - GregTech.getResourcePath("textures", "gui", "FakeAssemblyline"), - 16, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, true, GT_UITextures.OVERLAY_SLOT_DATA_ORB) - .setUsualFluidInputCount(4) - .setDisableOptimize(true); - /** - * Usually, but not always, you should use {@link GT_RecipeConstants#UniversalArcFurnace} instead. - */ - public static final GT_Recipe_Map sPlasmaArcFurnaceRecipes = new GT_Recipe_Map( - new HashSet<>(20000), - "gt.recipe.plasmaarcfurnace", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "PlasmaArcFurnace"), - 1, - 9, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("arcfurnace", FIRST_ITEM_INPUT); - /** - * Usually, but not always, you should use {@link GT_RecipeConstants#UniversalArcFurnace} instead. - */ - public static final GT_Recipe_Map sArcFurnaceRecipes = new GT_Recipe_Map( - new HashSet<>(20000), - "gt.recipe.arcfurnace", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "ArcFurnace"), - 1, - 9, - 1, - 1, - 3, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("arcfurnace", FIRST_ITEM_INPUT); - public static final GT_Recipe_Map sPrinterRecipes = new GT_Recipe_Map_Printer( - new HashSet<>(5), - "gt.recipe.printer", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Printer"), - 1, - 1, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_PAGE_BLANK) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_PAGE_PRINTED) - .setSlotOverlay(false, false, true, true, GT_UITextures.OVERLAY_SLOT_DATA_STICK) - .setRecipeConfigFile("printer", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sSifterRecipes = new GT_Recipe_Map( - new HashSet<>(105), - "gt.recipe.sifter", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Sifter"), - 1, - 9, - 0, - 0, - 1, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_SIFT, ProgressBar.Direction.DOWN) - .setRecipeConfigFile("sifter", FIRST_ITEM_INPUT); - public static final GT_Recipe_Map sPressRecipes = new GT_Recipe_Map_FormingPress( - new HashSet<>(300), - "gt.recipe.press", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Press3"), - 6, - 1, - 2, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_PRESS_1) - .setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_PRESS_2) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_PRESS_3) - .setRecipeConfigFile("press", FIRST_ITEM_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_COMPRESS, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sLaserEngraverRecipes = new GT_Recipe_Map( - new HashSet<>(810), - "gt.recipe.laserengraver", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "LaserEngraver2"), - 4, - 4, - 0, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_LENS) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("laserengraving", FIRST_ITEM_OUTPUT) - .setUsualFluidInputCount(2) - .setUsualFluidOutputCount(2); - public static final GT_Recipe_Map sMixerRecipes = new GT_Recipe_Map( - new HashSet<>(900), - "gt.recipe.mixer", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Mixer6"), - 9, - 4, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_DUST) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_DUST) - .setRecipeConfigFile("mixer", FIRST_ITEM_OR_FLUID_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_MIXER, ProgressBar.Direction.CIRCULAR_CW); - public static final GT_Recipe_Map sAutoclaveRecipes = new GT_Recipe_Map( - new HashSet<>(300), - "gt.recipe.autoclave", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Autoclave4"), - 2, - 4, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_DUST) - .setSlotOverlay(false, true, true, GT_UITextures.OVERLAY_SLOT_GEM) - .setSlotOverlay(false, true, false, GT_UITextures.OVERLAY_SLOT_DUST) - .setRecipeConfigFile("autoclave", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sElectroMagneticSeparatorRecipes = new GT_Recipe_Map( - new HashSet<>(50), - "gt.recipe.electromagneticseparator", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "ElectromagneticSeparator"), - 1, - 3, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_DUST) - .setRecipeConfigFile("electromagneticseparator", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_MAGNET, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sPolarizerRecipes = new GT_Recipe_Map( - new HashSet<>(300), - "gt.recipe.polarizer", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Polarizer"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_MAGNET, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("polarizer", FIRST_ITEM_INPUT); - public static final GT_Recipe_Map sMaceratorRecipes = new GT_Recipe_Map_Macerator( - new HashSet<>(16600), - "gt.recipe.macerator", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Macerator4"), - 1, - 4, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_DUST) - .setProgressBar(GT_UITextures.PROGRESSBAR_MACERATE, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("pulveriser", FIRST_ITEM_INPUT) - .setSlotOverlaySteam(false, GT_UITextures.OVERLAY_SLOT_CRUSHED_ORE_STEAM) - .setSlotOverlaySteam(true, GT_UITextures.OVERLAY_SLOT_DUST_STEAM) - .setProgressBarSteam(GT_UITextures.PROGRESSBAR_MACERATE_STEAM); - public static final GT_Recipe_Map sChemicalBathRecipes = new GT_Recipe_Map( - new HashSet<>(2550), - "gt.recipe.chemicalbath", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "ChemicalBath"), - 1, - 3, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_BATH, ProgressBar.Direction.CIRCULAR_CW) - .setRecipeConfigFile("chemicalbath", FIRST_ITEM_INPUT); - public static final GT_Recipe_Map sFluidCannerRecipes = new GT_Recipe_Map_FluidCanner( - new HashSet<>(2100), - "gt.recipe.fluidcanner", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "FluidCanner"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CANISTER) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_CANISTER) - .setRecipeConfigFile("canning", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_CANNER, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sBrewingRecipes = new GT_Recipe_Map( - new HashSet<>(450), - "gt.recipe.brewer", - "Brewing Machine", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "PotionBrewer"), - 1, - 0, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CAULDRON) - .setRecipeConfigFile("brewing", FIRST_FLUIDSTACK_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sFluidHeaterRecipes = new GT_Recipe_Map( - new HashSet<>(10), - "gt.recipe.fluidheater", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "FluidHeater"), - 1, - 0, - 0, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(true, false, GT_UITextures.OVERLAY_SLOT_HEATER_1) - .setSlotOverlay(true, true, GT_UITextures.OVERLAY_SLOT_HEATER_2) - .setRecipeConfigFile("fluidheater", FIRST_FLUIDSTACK_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sDistilleryRecipes = new GT_Recipe_Map( - new HashSet<>(400), - "gt.recipe.distillery", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Distillery"), - 1, - 1, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(true, false, GT_UITextures.OVERLAY_SLOT_BEAKER_1) - .setSlotOverlay(true, true, GT_UITextures.OVERLAY_SLOT_BEAKER_2) - .setRecipeConfigFile("distillery", FIRST_FLUIDSTACK_OUTPUT) - .setRecipeSpecialHandler(r -> { - int aInput = r.mFluidInputs[0].amount, aOutput = r.mFluidOutputs[0].amount, aDuration = r.mDuration; - - // reduce the batch size if fluid amount is exceeding - int tScale = (Math.max(aInput, aOutput) + 999) / 1000; - if (tScale <= 0) tScale = 1; - if (tScale > 1) { - // trying to find whether there is a better factor - for (int i = tScale; i <= 5; i++) { - if (aInput % i == 0 && aDuration % i == 0) { - tScale = i; - break; - } - } - for (int i = tScale; i <= 5; i++) { - if (aInput % i == 0 && aDuration % i == 0 && aOutput % i == 0) { - tScale = i; - break; - } - } - aInput = (aInput + tScale - 1) / tScale; - aOutput = aOutput / tScale; - if (!isArrayEmptyOrNull(r.mOutputs)) { - ItemData tData = GT_OreDictUnificator.getItemData(r.mOutputs[0]); - if (tData != null && (tData.mPrefix == OrePrefixes.dust - || OrePrefixes.dust.mFamiliarPrefixes.contains(tData.mPrefix))) { - r.mOutputs[0] = GT_OreDictUnificator.getDust( - tData.mMaterial.mMaterial, - tData.mMaterial.mAmount * r.mOutputs[0].stackSize / tScale); - } else { - if (r.mOutputs[0].stackSize / tScale == 0) r.mOutputs[0] = GT_Values.NI; - else r.mOutputs[0] = GT_Utility - .copyAmount(r.mOutputs[0].stackSize / tScale, r.mOutputs[0]); - } - } - aDuration = (aDuration + tScale - 1) / tScale; - r.mFluidInputs[0] = GT_Utility.copyAmount(aInput, r.mFluidInputs[0]); - r.mFluidOutputs[0] = GT_Utility.copyAmount(aOutput, r.mFluidOutputs[0]); - r.mDuration = aDuration; - } - }) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sFermentingRecipes = new GT_Recipe_Map( - new HashSet<>(50), - "gt.recipe.fermenter", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Fermenter"), - 0, - 0, - 0, - 1, - 1, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("fermenting", FIRST_FLUIDSTACK_OUTPUT); - public static final GT_Recipe_Map sFluidSolidficationRecipes = new GT_Recipe_Map( - new HashSet<>(35000), - "gt.recipe.fluidsolidifier", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "FluidSolidifier"), - 1, - 1, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_MOLD) - .setRecipeConfigFile("fluidsolidifier", FIRST_ITEM_OUTPUT) - .setRecipeSpecialHandler(r -> { - if (ArrayUtils.isNotEmpty(r.mFluidInputs)) { - if (Materials.PhasedGold.getMolten(1) - .isFluidEqual(r.mFluidInputs[0])) - r.mFluidInputs = new FluidStack[] { - Materials.VibrantAlloy.getMolten(r.mFluidInputs[0].amount) }; - else if (Materials.PhasedIron.getMolten(1) - .isFluidEqual(r.mFluidInputs[0])) - r.mFluidInputs = new FluidStack[] { - Materials.PulsatingIron.getMolten(r.mFluidInputs[0].amount) }; - } - }) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sFluidExtractionRecipes = new GT_Recipe_Map( - new HashSet<>(15000), - "gt.recipe.fluidextractor", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "FluidExtractor"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CENTRIFUGE) - .setRecipeConfigFile("fluidextractor", FIRST_ITEM_INPUT) - .setRecipeSpecialHandler(r -> { - if (ArrayUtils.isNotEmpty(r.mFluidInputs)) { - if (Materials.PhasedGold.getMolten(1) - .isFluidEqual(r.mFluidInputs[0])) - r.mFluidInputs = new FluidStack[] { - Materials.VibrantAlloy.getMolten(r.mFluidInputs[0].amount) }; - else if (Materials.PhasedIron.getMolten(1) - .isFluidEqual(r.mFluidInputs[0])) - r.mFluidInputs = new FluidStack[] { - Materials.PulsatingIron.getMolten(r.mFluidInputs[0].amount) }; - } - }) - .setProgressBar(GT_UITextures.PROGRESSBAR_EXTRACT, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sBoxinatorRecipes = new GT_Recipe_Map( - new HashSet<>(2500), - "gt.recipe.packager", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Packager"), - 2, - 1, - 2, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_BOX) - .setRecipeConfigFile("boxing", FIRST_ITEM_OUTPUT) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_BOXED) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sUnboxinatorRecipes = new GT_Recipe_Map_Unboxinator( - new HashSet<>(2500), - "gt.recipe.unpackager", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Unpackager"), - 1, - 2, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_BOXED) - .setRecipeConfigFile("unboxing", FIRST_ITEM_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - /** - * Usually, but not always, you should use {@link GT_RecipeConstants#Fusion} instead. - */ - public static final GT_Recipe_Map sFusionRecipes = new GT_Recipe_Map_FluidOnly( - new HashSet<>(50), - "gt.recipe.fusionreactor", - "Fusion Reactor", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "FusionReactor"), - 0, - 0, - 0, - 2, - 1, - "Start: ", - 1, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .useComparatorForNEI(true) - .setUsualFluidInputCount(2) - .setRecipeConfigFile("fusion", FIRST_FLUID_OUTPUT) - .setDisableOptimize(true) - .setNEISpecialInfoFormatter(FusionSpecialValueFormatter.INSTANCE); - /** - * Usually, but not always, you should use {@link GT_RecipeConstants#Fusion} instead. - */ - public static final GT_Recipe_Map sComplexFusionRecipes = new GT_Recipe_Map_ComplexFusion( - new HashSet<>(50), - "gt.recipe.complexfusionreactor", - "Complex Fusion Reactor", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "ComplexFusionReactor"), - 3, - 0, - 0, - 2, - 1, - "Start: ", - 1, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setUsualFluidInputCount(16) - .setUsualFluidOutputCount(16) - .setNEITransferRect(new Rectangle(79, 34, 18, 18)) - .setLogoPos(80, 61) - .setNEISpecialInfoFormatter(FusionSpecialValueFormatter.INSTANCE) - .setDisableOptimize(true); - public static final GT_Recipe_Map sCentrifugeRecipes = new GT_Recipe_Map( - new HashSet<>(1200), - "gt.recipe.centrifuge", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Centrifuge"), - 2, - 6, - 0, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_CENTRIFUGE) - .setRecipeConfigFile("centrifuge", FIRST_ITEM_OR_FLUID_INPUT) - .setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_CANISTER) - .setSlotOverlay(true, false, GT_UITextures.OVERLAY_SLOT_CENTRIFUGE_FLUID) - .setProgressBar(GT_UITextures.PROGRESSBAR_EXTRACT, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sElectrolyzerRecipes = new GT_Recipe_Map( - new HashSet<>(300), - "gt.recipe.electrolyzer", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Electrolyzer"), - 2, - 6, - 0, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_CHARGER) - .setRecipeConfigFile("electrolyzer", FIRST_ITEM_OR_FLUID_INPUT) - .setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_CANISTER) - .setSlotOverlay(true, false, GT_UITextures.OVERLAY_SLOT_CHARGER_FLUID) - .setProgressBar(GT_UITextures.PROGRESSBAR_EXTRACT, ProgressBar.Direction.RIGHT); - /** - * Use {@link GT_RecipeConstants#COIL_HEAT} as heat level. - */ - public static final GT_Recipe_Map sBlastRecipes = new GT_Recipe_Map( - new HashSet<>(800), - "gt.recipe.blastfurnace", - "Blast Furnace", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 6, - 6, - 1, - 0, - 1, - "Heat Capacity: ", - 1, - " K", - false, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("blastfurnace", FIRST_ITEM_INPUT) - .setNEISpecialInfoFormatter(HeatingCoilSpecialValueFormatter.INSTANCE); - /** - * Use {@link GT_RecipeConstants#COIL_HEAT} as heat level. - */ - public static final GT_Recipe_Map sPlasmaForgeRecipes = new GT_Recipe_Map_LargeNEI( - new HashSet<>(20), - "gt.recipe.plasmaforge", - "DTPF", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "PlasmaForge"), - 9, - 9, - 0, - 0, - 1, - "Heat Capacity: ", - 1, - " K", - false, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setUsualFluidInputCount(9) - .setUsualFluidOutputCount(9) - .setDisableOptimize(true) - .setNEISpecialInfoFormatter(HeatingCoilSpecialValueFormatter.INSTANCE); - - public static final GT_Recipe_Map sTranscendentPlasmaMixerRecipes = new TranscendentPlasmaMixerRecipeMap( - new HashSet<>(20), - "gt.recipe.transcendentplasmamixerrecipes", - "Transcendent Plasma Mixer", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "PlasmaForge"), - 1, - 0, - 0, - 0, - 1, - "", - 0, - "", - false, - true).setDisableOptimize(true); - - public static class GT_FakeSpaceProjectRecipe extends GT_Recipe { - - public final String projectName; - - public GT_FakeSpaceProjectRecipe(boolean aOptimize, ItemStack[] aInputs, FluidStack[] aFluidInputs, - int aDuration, int aEUt, int aSpecialValue, String projectName) { - super(aOptimize, aInputs, null, null, null, aFluidInputs, null, aDuration, aEUt, aSpecialValue); - this.projectName = projectName; - } - } - - public static final GT_Recipe_Map sFakeSpaceProjectRecipes = new GT_Recipe_Map( - new HashSet<>(20), - "gt.recipe.fakespaceprojects", - "Space Projects", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 12, - 0, - 0, - 0, - 1, - translateToLocal("gt.specialvalue.stages") + " ", - 1, - "", - false, - true) { - - IDrawable projectTexture; - - @Override - public ModularWindow.Builder createNEITemplate(IItemHandlerModifiable itemInputsInventory, - IItemHandlerModifiable itemOutputsInventory, IItemHandlerModifiable specialSlotInventory, - IItemHandlerModifiable fluidInputsInventory, IItemHandlerModifiable fluidOutputsInventory, - Supplier<Float> progressSupplier, Pos2d windowOffset) { - ModularWindow.Builder builder = super.createNEITemplate( - itemInputsInventory, - itemOutputsInventory, - specialSlotInventory, - fluidInputsInventory, - fluidOutputsInventory, - progressSupplier, - windowOffset); - addRecipeSpecificDrawable( - builder, - windowOffset, - () -> projectTexture, - new Pos2d(124, 28), - new Size(18, 18)); - return builder; - } - - @Override - public List<Pos2d> getItemInputPositions(int itemInputCount) { - return UIHelper.getGridPositions(itemInputCount, 16, 28, 3); - } - - @Override - public List<Pos2d> getFluidInputPositions(int fluidInputCount) { - return UIHelper.getGridPositions(fluidInputCount, 88, 28, 1); - } - - @Override - protected List<String> handleNEIItemInputTooltip(List<String> currentTip, - GT_NEI_DefaultHandler.FixedPositionedStack pStack) { - super.handleNEIItemOutputTooltip(currentTip, pStack); - if (pStack.item != null && pStack.item.getItem() instanceof GT_FluidDisplayItem) return currentTip; - currentTip.add(GRAY + translateToLocal("Item Count: ") + formatNumbers(pStack.realStackSize)); - return currentTip; - } - - @Override - public void drawNEIOverlays(GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) { - for (PositionedStack stack : neiCachedRecipe.mInputs) { - if (stack instanceof GT_NEI_DefaultHandler.FixedPositionedStack && stack.item != null - && !(stack.item.getItem() instanceof GT_FluidDisplayItem)) { - int stackSize = ((GT_NEI_DefaultHandler.FixedPositionedStack) stack).realStackSize; - String displayString; - if (stack.item.stackSize > 9999) { - displayString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize); - } else { - displayString = String.valueOf(stackSize); - } - drawNEIOverlayText(displayString, stack, 0xffffff, 0.5f, true, Alignment.BottomRight); - } - } - if (neiCachedRecipe.mRecipe instanceof GT_FakeSpaceProjectRecipe) { - ISpaceProject project = SpaceProjectManager - .getProject(((GT_FakeSpaceProjectRecipe) neiCachedRecipe.mRecipe).projectName); - if (project != null) { - projectTexture = project.getTexture(); - GuiDraw - .drawStringC(EnumChatFormatting.BOLD + project.getLocalizedName(), 85, 0, 0x404040, false); - } - } - } - - @Override - public void addProgressBarUI(ModularWindow.Builder builder, Supplier<Float> progressSupplier, - Pos2d windowOffset) { - int bar1Width = 17; - int bar2Width = 18; - builder.widget( - new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_1, 17) - .setDirection(ProgressBar.Direction.RIGHT) - .setProgress(() -> progressSupplier.get() * ((float) (bar1Width + bar2Width) / bar1Width)) - .setSynced(false, false) - .setPos(new Pos2d(70, 28).add(windowOffset)) - .setSize(bar1Width, 72)); - builder.widget( - new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_2, 18) - .setDirection(ProgressBar.Direction.RIGHT) - .setProgress( - () -> (progressSupplier.get() - ((float) bar1Width / (bar1Width + bar2Width))) - * ((float) (bar1Width + bar2Width) / bar2Width)) - .setSynced(false, false) - .setPos(new Pos2d(106, 28).add(windowOffset)) - .setSize(bar2Width, 72)); - } - }.useModularUI(true) - .setRenderRealStackSizes(false) - .setUsualFluidInputCount(4) - .setNEIBackgroundOffset(2, 23) - .setLogoPos(152, 83) - .setDisableOptimize(true); - - public static class TranscendentPlasmaMixerRecipeMap extends GT_Recipe_Map { - - public TranscendentPlasmaMixerRecipeMap(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, - String aLocalName, String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, - int aMinimalInputItems, int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, - int aNEISpecialValueMultiplier, String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, - boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - useModularUI(true); - setUsualFluidInputCount(20); - setUsualFluidOutputCount(1); - setProgressBarPos(86, 44); - setNEITransferRect( - new Rectangle( - progressBarPos.x - (16 / 2), - progressBarPos.y, - progressBarSize.width + 16, - progressBarSize.height)); - setLogoPos(87, 99); - setNEIBackgroundSize(172, 118); - } - - @Override - public List<Pos2d> getItemInputPositions(int itemInputCount) { - return UIHelper.getGridPositions(itemInputCount, 60, 8, 1); - } - - @Override - public List<Pos2d> getFluidInputPositions(int fluidInputCount) { - return UIHelper.getGridPositions(fluidInputCount, 6, 26, 4, 5); - } - - @Override - public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { - return UIHelper.getGridPositions(fluidOutputCount, 114, 44, 1); - } - - @Override - protected void drawNEIEnergyInfo(NEIRecipeInfo recipeInfo) { - // These look odd because recipeInfo.recipe.mEUt is actually the EU per litre of fluid processed, not - // the EU/t. - drawNEIText( - recipeInfo, - GT_Utility.trans("152", "Total: ") - + formatNumbers(1000L * recipeInfo.recipe.mDuration / 100L * recipeInfo.recipe.mEUt) - + " EU"); - // 1000 / (20 ticks * 5 seconds) = 10L/t. 10L/t * x EU/L = 10 * x EU/t. - long averageUsage = 10L * recipeInfo.recipe.mEUt; - drawNEIText( - recipeInfo, - "Average: " + formatNumbers(averageUsage) - + " EU/t" - + GT_Utility.getTierNameWithParentheses(averageUsage)); - } - } - - /** - * Uses {@link GT_RecipeConstants#ADDITIVE_AMOUNT} for coal/charcoal amount. - */ - public static final GT_Recipe_Map sPrimitiveBlastRecipes = new GT_Recipe_Map( - new HashSet<>(200), - "gt.recipe.primitiveblastfurnace", - "Primitive Blast Furnace", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 3, - 3, - 1, - 0, - 1, - E, - 1, - E, - false, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setRecipeEmitter(builder -> { - Optional<GT_Recipe> rr = builder.validateInputCount(1, 2) - .validateOutputCount(1, 2) - .validateNoInputFluid() - .validateNoOutputFluid() - .noOptimize() - .build(); - if (!rr.isPresent()) return Collections.emptyList(); - ItemStack aInput1 = builder.getItemInputBasic(0); - ItemStack aInput2 = builder.getItemInputBasic(1); - ItemStack aOutput1 = builder.getItemOutput(0); - ItemStack aOutput2 = builder.getItemOutput(1); - if ((aInput1 == null && aInput2 == null) || (aOutput1 == null && aOutput2 == null)) - return Collections.emptyList(); - int aCoalAmount = builder.getMetadata(ADDITIVE_AMOUNT); - if (aCoalAmount <= 0) return Collections.emptyList(); - GT_RecipeTemplate coll = asTemplate(rr.get()); - for (Materials coal : new Materials[] { Materials.Coal, Materials.Charcoal }) { - coll.derive() - .setInputs(aInput1, aInput2, coal.getGems(aCoalAmount)) - .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDustTiny(aCoalAmount)); - coll.derive() - .setInputs(aInput1, aInput2, coal.getDust(aCoalAmount)) - .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDustTiny(aCoalAmount)); - } - int aDuration = builder.duration; - if (Railcraft.isModLoaded()) { - coll.derive() - .setInputs(aInput1, aInput2, RailcraftToolItems.getCoalCoke(aCoalAmount / 2)) - .setOutputs(aOutput1, aOutput2, Materials.Ash.getDustTiny(aCoalAmount / 2)) - .setDuration(aDuration * 2 / 3); - } - if (GTPlusPlus.isModLoaded()) { - ItemStack cactusCoke = GT_ModHandler - .getModItem(GTPlusPlus.ID, "itemCactusCoke", aCoalAmount * 2L); - ItemStack sugarCoke = GT_ModHandler - .getModItem(GTPlusPlus.ID, "itemSugarCoke", aCoalAmount * 2L); - coll.derive() - .setInputs(aInput1, aInput2, cactusCoke) - .setOutputs(aOutput1, aOutput2, Materials.Ash.getDustTiny(aCoalAmount * 2)) - .setDuration(aDuration * 2 / 3); - coll.derive() - .setInputs(aInput1, aInput2, sugarCoke) - .setOutputs(aOutput1, aOutput2, Materials.Ash.getDustTiny(aCoalAmount * 2)) - .setDuration(aDuration * 2 / 3); - } - if ((aInput1 == null || aInput1.stackSize <= 6) && (aInput2 == null || aInput2.stackSize <= 6) - && (aOutput1 == null || aOutput1.stackSize <= 6) - && (aOutput2 == null || aOutput2.stackSize <= 6)) { - // we don't use GT_Utility.mul() here. It does not have the truncating we need here. - aInput1 = GT_Utility.multiplyStack(10, aInput1); - aInput2 = GT_Utility.multiplyStack(10, aInput2); - aOutput1 = GT_Utility.multiplyStack(10, aOutput1); - aOutput2 = GT_Utility.multiplyStack(10, aOutput2); - for (Materials coal : new Materials[] { Materials.Coal, Materials.Charcoal }) { - coll.derive() - .setInputs(aInput1, aInput2, coal.getBlocks(aCoalAmount)) - .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDust(aCoalAmount)) - .setDuration(aDuration * 10); - coll.derive() - .setInputs(aInput1, aInput2, coal.getBlocks(aCoalAmount)) - .setOutputs(aOutput1, aOutput2, Materials.DarkAsh.getDust(aCoalAmount)) - .setDuration(aDuration * 10); - } - if (Railcraft.isModLoaded()) { - coll.derive() - .setInputs(aInput1, aInput2, EnumCube.COKE_BLOCK.getItem(aCoalAmount / 2)) - .setOutputs(aOutput1, aOutput2, Materials.Ash.getDust(aCoalAmount / 2)) - .setDuration(aDuration * 20 / 3); - } - } - return coll.getAll(); - }) - .setRecipeConfigFile("primitiveblastfurnace", FIRST_ITEM_INPUT); - /** - * Uses {@link GT_RecipeConstants#ADDITIVE_AMOUNT} for TNT/ITNT/... amount. Value is truncated to [0, 64] - */ - public static final GT_Recipe_Map sImplosionRecipes = new GT_Recipe_Map( - new HashSet<>(900), - "gt.recipe.implosioncompressor", - "Implosion Compressor", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 2, - 2, - 2, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_IMPLOSION) - .setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_EXPLOSIVE) - .setRecipeConfigFile("implosion", FIRST_ITEM_INPUT) - .setRecipeEmitter(b -> { - switch (b.getItemInputsBasic().length) { - case 0: - return Collections.emptyList(); - case 1: - break; - default: - return b.build() - .map(Collections::singletonList) - .orElse(Collections.emptyList()); - } - Optional<GT_Recipe> t = b.noOptimize() - .duration(20) - .eut(30) - .validateInputCount(1, 1) - .validateOutputCount(1, 2) - .build(); - if (!t.isPresent()) return Collections.emptyList(); - ItemStack input = b.getItemInputBasic(0); - GT_RecipeTemplate coll = asTemplate(t.get()); - int tExplosives = Math.min(b.getMetadata(ADDITIVE_AMOUNT), 64); - int tGunpowder = tExplosives << 1; // Worst - int tDynamite = Math.max(1, tExplosives >> 1); // good - @SuppressWarnings("UnnecessaryLocalVariable") - int tTNT = tExplosives; // Slightly better - int tITNT = Math.max(1, tExplosives >> 2); // the best - if (tGunpowder < 65) coll.derive() - .setInputs(input, ItemList.Block_Powderbarrel.get(tGunpowder)); - if (tDynamite < 17) coll.derive() - .setInputs(input, GT_ModHandler.getIC2Item("dynamite", tDynamite, null)); - coll.derive() - .setInputs(input, new ItemStack(Blocks.tnt, tTNT)); - coll.derive() - .setInputs(input, GT_ModHandler.getIC2Item("industrialTnt", tITNT, null)); - return coll.getAll(); - }) - .setDisableOptimize(true) - .setProgressBar(GT_UITextures.PROGRESSBAR_COMPRESS, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sVacuumRecipes = new GT_Recipe_Map( - new HashSet<>(305), - "gt.recipe.vacuumfreezer", - "Vacuum Freezer", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - E, - 1, - E, - false, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setRecipeConfigFile("vacuumfreezer", FIRST_ITEM_INPUT) - .setRecipeEmitter(b -> { - b.noOptimize(); - FluidStack in, out; - if (isArrayOfLength(b.getItemInputsBasic(), 1) && isArrayOfLength(b.getItemOutputs(), 1) - && isArrayEmptyOrNull(b.getFluidInputs()) - && isArrayEmptyOrNull(b.getFluidOutputs()) - && (in = GT_Utility.getFluidForFilledItem(b.getItemInputBasic(0), true)) != null - && (out = GT_Utility.getFluidForFilledItem(b.getItemOutput(0), true)) != null) { - return Arrays.asList( - b.build() - .get(), - b.itemInputs() - .itemOutputs() - .fluidInputs(in) - .fluidOutputs(out) - .build() - .get()); - } - return buildOrEmpty(b); - }) - .setUsualFluidInputCount(2); - /** - * using {@code .addTo(sChemicalRecipes)} will cause the recipe to be added to single block recipe map ONLY! - * use {@link GT_RecipeConstants#UniversalChemical} to add to both. - */ - public static final GT_Recipe_Map sChemicalRecipes = new GT_Recipe_Map( - new HashSet<>(1170), - "gt.recipe.chemicalreactor", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "ChemicalReactor"), - 2, - 2, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_MOLECULAR_1) - .setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_MOLECULAR_2) - .setSlotOverlay(true, false, GT_UITextures.OVERLAY_SLOT_MOLECULAR_3) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_VIAL_1) - .setSlotOverlay(true, true, GT_UITextures.OVERLAY_SLOT_VIAL_2) - .setRecipeConfigFile("chemicalreactor", FIRST_ITEM_OR_FLUID_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT) - .setDisableOptimize(true); - /** - * using {@code .addTo(sMultiblockChemicalRecipes)} will cause the recipe to be added to multiblock recipe map - * ONLY! - * use {@link GT_RecipeConstants#UniversalChemical} to add to both. - */ - public static final GT_Recipe_Map sMultiblockChemicalRecipes = // - new GT_Recipe_Map_LargeChemicalReactor() - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT) - .setUsualFluidInputCount(6) - .setUsualFluidOutputCount(6) - .setDisableOptimize(true); - public static final GT_Recipe_Map sDistillationRecipes = // - new GT_Recipe_Map_DistillationTower().setRecipeConfigFile("distillation", FIRST_FLUIDSTACK_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT) - .setUsualFluidOutputCount(11) - .setDisableOptimize(true); - public static final GT_Recipe_Map_OilCracker sCrackingRecipes = (GT_Recipe_Map_OilCracker) // - new GT_Recipe_Map_OilCracker().setRecipeConfigFile("cracking", FIRST_FLUIDSTACK_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW_MULTIPLE, ProgressBar.Direction.RIGHT) - .setUsualFluidInputCount(2); - /** - * @deprecated Use sCrackingRecipes instead - */ - @Deprecated - public static final GT_Recipe_Map sCrakingRecipes = sCrackingRecipes; - - public static final GT_Recipe_Map sPyrolyseRecipes = new GT_Recipe_Map( - new HashSet<>(150), - "gt.recipe.pyro", - "Pyrolyse Oven", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 2, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setDisableOptimize(true) - .setRecipeConfigFile("pyrolyse", FIRST_ITEM_INPUT); - public static final GT_Recipe_Map sWiremillRecipes = new GT_Recipe_Map( - new HashSet<>(450), - "gt.recipe.wiremill", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Wiremill"), - 2, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_WIREMILL) - .setRecipeConfigFile("wiremill", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_WIREMILL, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sBenderRecipes = new GT_Recipe_Map( - new HashSet<>(5000), - "gt.recipe.metalbender", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Bender"), - 2, - 1, - 2, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_BENDER) - .setRecipeConfigFile("bender", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_BENDING, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sAlloySmelterRecipes = new GT_Recipe_Map( - new HashSet<>(12000), - "gt.recipe.alloysmelter", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "AlloySmelter"), - 2, - 1, - 2, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_FURNACE) - .setRecipeEmitter(b -> { - if (Materials.Graphite.contains(b.getItemInputBasic(0))) return Collections.emptyList(); - if (GT_Utility.isArrayOfLength(b.getItemInputsBasic(), 1)) { - ItemStack aInput1 = b.getItemInputBasic(0); - if (((OrePrefixes.ingot.contains(aInput1)) || (OrePrefixes.dust.contains(aInput1)) - || (OrePrefixes.gem.contains(aInput1)))) return Collections.emptyList(); - } - return buildOrEmpty( - b.validateNoInputFluid() - .validateNoOutputFluid() - .validateInputCount(1, 2) - .validateOutputCount(1, 1)); - }) - .setRecipeConfigFile( - "alloysmelting", - r -> GT_Config - .getStackConfigName(GT_Utility.isArrayOfLength(r.mInputs, 1) ? r.mInputs[0] : r.mOutputs[0])) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setSlotOverlaySteam(false, GT_UITextures.OVERLAY_SLOT_FURNACE_STEAM) - .setProgressBarSteam(GT_UITextures.PROGRESSBAR_ARROW_STEAM); - public static final GT_Recipe_Map sAssemblerRecipes = new GT_Recipe_Map_Assembler( - new HashSet<>(8200), - "gt.recipe.assembler", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Assembler2"), - 9, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CIRCUIT) - .setRecipeConfigFile("assembling", FIRST_ITEM_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_ASSEMBLE, ProgressBar.Direction.RIGHT) - .setDisableOptimize(true); - public static final GT_Recipe_Map sCircuitAssemblerRecipes = new GT_Recipe_Map_Assembler( - new HashSet<>(605), - "gt.recipe.circuitassembler", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "CircuitAssembler"), - 6, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setNEIUnificateOutput(!NEICustomDiagrams.isModLoaded()) - .setRecipeConfigFile("circuitassembler", FIRST_ITEM_OUTPUT) - .setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CIRCUIT) - .setProgressBar(GT_UITextures.PROGRESSBAR_CIRCUIT_ASSEMBLER, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sCannerRecipes = new GT_Recipe_Map( - new HashSet<>(900), - "gt.recipe.canner", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Canner"), - 2, - 2, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_CANNER) - .setRecipeConfigFile("canning", FIRST_ITEM_INPUT) - .setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_CANISTER) - .setProgressBar(GT_UITextures.PROGRESSBAR_CANNER, ProgressBar.Direction.RIGHT); - @Deprecated - public static final GT_Recipe_Map sCNCRecipes = new GT_Recipe_Map( - new HashSet<>(100), - "gt.recipe.cncmachine", - "CNC Machine", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 2, - 1, - 2, - 1, - 1, - E, - 1, - E, - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sLatheRecipes = new GT_Recipe_Map( - new HashSet<>(1150), - "gt.recipe.lathe", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Lathe"), - 1, - 2, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_ROD_1) - .setSlotOverlay(false, true, true, GT_UITextures.OVERLAY_SLOT_ROD_2) - .setSlotOverlay(false, true, false, GT_UITextures.OVERLAY_SLOT_DUST) - .setRecipeConfigFile("lathe", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_LATHE, ProgressBar.Direction.RIGHT) - .addSpecialTexture(5, 18, 98, 24, GT_UITextures.PROGRESSBAR_LATHE_BASE); - public static final GT_Recipe_Map sCutterRecipes = new GT_Recipe_Map( - new HashSet<>(5125), - "gt.recipe.cuttingsaw", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Cutter4"), - 2, - 4, - 1, - 1, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_BOX) - .setSlotOverlay(false, true, true, GT_UITextures.OVERLAY_SLOT_CUTTER_SLICED) - .setSlotOverlay(false, true, false, GT_UITextures.OVERLAY_SLOT_DUST) - .setRecipeEmitter(b -> { - b.validateInputCount(1, 2) - .validateOutputCount(1, 4) - .validateNoOutputFluid(); - if ((b.getFluidInputs() != null && b.getFluidInputs().length > 0) || !b.isValid()) - return buildOrEmpty(b.validateInputFluidCount(1, 1)); - int aDuration = b.getDuration(), aEUt = b.getEUt(); - Collection<GT_Recipe> ret = new ArrayList<>(); - b.copy() - .fluidInputs(Materials.Water.getFluid(GT_Utility.clamp(aDuration * aEUt / 320, 4, 1000))) - .duration(aDuration * 2) - .build() - .ifPresent(ret::add); - b.copy() - .fluidInputs(GT_ModHandler.getDistilledWater(GT_Utility.clamp(aDuration * aEUt / 426, 3, 750))) - .duration(aDuration * 2) - .build() - .ifPresent(ret::add); - b.fluidInputs(Materials.Lubricant.getFluid(GT_Utility.clamp(aDuration * aEUt / 1280, 1, 250))) - .duration(aDuration) - .build() - .ifPresent(ret::add); - return ret; - }) - .setRecipeConfigFile("cutting", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_CUT, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sSlicerRecipes = new GT_Recipe_Map( - new HashSet<>(20), - "gt.recipe.slicer", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Slicer"), - 2, - 1, - 2, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_SQUARE) - .setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_SLICE_SHAPE) - .setSlotOverlay(false, true, GT_UITextures.OVERLAY_SLOT_SLICER_SLICED) - .setRecipeConfigFile("slicer", FIRST_ITEM_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_SLICE, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sExtruderRecipes = new GT_Recipe_Map( - new HashSet<>(13000), - "gt.recipe.extruder", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Extruder"), - 2, - 1, - 2, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, false, GT_UITextures.OVERLAY_SLOT_EXTRUDER_SHAPE) - .setRecipeConfigFile("extruder", FIRST_ITEM_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_EXTRUDE, ProgressBar.Direction.RIGHT); - - public static final GT_Recipe_Map sHammerRecipes = new GT_Recipe_Map( - new HashSet<>(3800), - "gt.recipe.hammer", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Hammer"), - 2, - 2, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setUsualFluidInputCount(2) - .setUsualFluidOutputCount(2) - .setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_HAMMER) - .setRecipeConfigFile("forgehammer", FIRST_ITEM_OUTPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_HAMMER, ProgressBar.Direction.DOWN) - .addSpecialTexture(20, 6, 78, 42, GT_UITextures.PROGRESSBAR_HAMMER_BASE) - .setSlotOverlaySteam(false, GT_UITextures.OVERLAY_SLOT_HAMMER_STEAM) - .setProgressBarSteam(GT_UITextures.PROGRESSBAR_HAMMER_STEAM) - .addSpecialTextureSteam(20, 6, 78, 42, GT_UITextures.PROGRESSBAR_HAMMER_BASE_STEAM); - public static final GT_Recipe_Map sAmplifiers = new GT_Recipe_Map( - new HashSet<>(2), - "gt.recipe.uuamplifier", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Amplifabricator"), - 1, - 0, - 1, - 0, - 1, - E, - 1, - E, - true, - true).setSlotOverlay(false, false, GT_UITextures.OVERLAY_SLOT_CENTRIFUGE) - .setSlotOverlay(true, true, GT_UITextures.OVERLAY_SLOT_UUA) - .setRecipeConfigFile("amplifier", FIRST_ITEM_INPUT) - .setProgressBar(GT_UITextures.PROGRESSBAR_EXTRACT, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sMassFabFakeRecipes = new GT_Recipe_Map( - new HashSet<>(2), - "gt.recipe.massfab", - null, - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Massfabricator"), - 1, - 0, - 1, - 0, - 8, - E, - 1, - E, - true, - true).setSlotOverlay(true, false, GT_UITextures.OVERLAY_SLOT_UUA) - .setSlotOverlay(true, true, GT_UITextures.OVERLAY_SLOT_UUM) - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sDieselFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(20), - "gt.recipe.dieselgeneratorfuel", - "Combustion Generator Fuels", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sExtremeDieselFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(20), - "gt.recipe.extremedieselgeneratorfuel", - "Extreme Diesel Engine Fuel", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sTurbineFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(25), - "gt.recipe.gasturbinefuel", - "Gas Turbine Fuel", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sHotFuels = new GT_Recipe_Map_Fuel( - new HashSet<>(10), - "gt.recipe.thermalgeneratorfuel", - "Thermal Generator Fuels", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - false); - public static final GT_Recipe_Map_Fuel sDenseLiquidFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(15), - "gt.recipe.semifluidboilerfuels", - "Semifluid Boiler Fuels", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sPlasmaFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(100), - "gt.recipe.plasmageneratorfuels", - "Plasma Generator Fuels", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sMagicFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(100), - "gt.recipe.magicfuels", - "Magic Energy Absorber Fuels", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sSmallNaquadahReactorFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(1), - "gt.recipe.smallnaquadahreactor", - "Naquadah Reactor MkI", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sLargeNaquadahReactorFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(1), - "gt.recipe.largenaquadahreactor", - "Naquadah Reactor MkII", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sHugeNaquadahReactorFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(1), - "gt.recipe.fluidnaquadahreactor", - "Naquadah Reactor MkIII", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sExtremeNaquadahReactorFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(1), - "gt.recipe.hugenaquadahreactor", - "Naquadah Reactor MkIV", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sUltraHugeNaquadahReactorFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(1), - "gt.recipe.extrahugenaquadahreactor", - "Naquadah Reactor MkV", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map_Fuel sFluidNaquadahReactorFuels = (GT_Recipe_Map_Fuel) new GT_Recipe_Map_Fuel( - new HashSet<>(1), - "gt.recipe.fluidfuelnaquadahreactor", - "Fluid Naquadah Reactor", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 0, - 0, - 1, - "Fuel Value: ", - 1000, - " EU", - true, - true).setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - public static final GT_Recipe_Map sMultiblockElectrolyzerRecipes = new GT_Recipe_Map( - new HashSet<>(300), - "gt.recipe.largeelectrolyzer", - "Large(PA) Electrolyzer", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "LCRNEI"), - 1, - 9, - 0, - 0, - 1, - "", - 0, - "", - true, - false).setRecipeEmitter(GT_RecipeMapUtil::buildRecipeForMultiblock); - - public static final GT_Recipe_Map sMultiblockCentrifugeRecipes = new GT_Recipe_Map( - new HashSet<>(1200), - "gt.recipe.largecentrifuge", - "Large(PA) Centrifuge", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "LCRNEI"), - 1, - 9, - 0, - 0, - 1, - "", - 0, - "", - true, - false).setRecipeEmitter(GT_RecipeMapUtil::buildRecipeForMultiblock) - .setDisableOptimize(true); - public static final GT_Recipe_Map sMultiblockMixerRecipes = new GT_Recipe_Map( - new HashSet<>(900), - "gt.recipe.largemixer", - "Large(PA) Mixer", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "LCRNEI"), - 9, - 3, - 0, - 0, - 1, - "", - 0, - "", - true, - false).setRecipeEmitter(GT_RecipeMapUtil::buildRecipeForMultiblockNoCircuit) - .setDisableOptimize(true); - public static final GT_Recipe_Map_LargeBoilerFakeFuels sLargeBoilerFakeFuels = (GT_Recipe_Map_LargeBoilerFakeFuels) new GT_Recipe_Map_LargeBoilerFakeFuels() - .setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) - .setDisableOptimize(true); - - public static final GT_Recipe_Map sNanoForge = new GT_Recipe_Map( - new HashSet<>(10), - "gt.recipe.nanoforge", - "Nano Forge", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "LCRNEI"), - 6, - 2, - 2, - 1, - 1, - "Tier: ", - 1, - "", - false, - true).useModularUI(true) - .setUsualFluidInputCount(3) - .setDisableOptimize(true) - .setSlotOverlay(false, false, true, GT_UITextures.OVERLAY_SLOT_LENS) - .setProgressBar(GT_UITextures.PROGRESSBAR_ASSEMBLE, ProgressBar.Direction.RIGHT); - - public static final GT_Recipe_Map sPCBFactory = new GT_Recipe_Map( - new HashSet<>(10), - "gt.recipe.pcbfactory", - "PCB Factory", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "LCRNEI"), - 6, - 9, - 3, - 1, - 1, - E, - 0, - E, - true, - true).useModularUI(true) - .setUsualFluidInputCount(3) - .setUsualFluidOutputCount(0) - .setDisableOptimize(true) - .setProgressBar(GT_UITextures.PROGRESSBAR_ASSEMBLE, ProgressBar.Direction.RIGHT) - .setNEISpecialInfoFormatter((recipeInfo, applyPrefixAndSuffix) -> { - List<String> result = new ArrayList<>(); - int bitmap = recipeInfo.recipe.mSpecialValue; - if ((bitmap & 0b1) > 0) { - result.add(GT_Utility.trans("336", "PCB Factory Tier: ") + 1); - } else if ((bitmap & 0b10) > 0) { - result.add(GT_Utility.trans("336", "PCB Factory Tier: ") + 2); - } else if ((bitmap & 0b100) > 0) { - result.add(GT_Utility.trans("336", "PCB Factory Tier: ") + 3); - } - if ((bitmap & 0b1000) > 0) { - result.add(GT_Utility.trans("337", "Upgrade Required: ") + GT_Utility.trans("338", "Bio")); - } - return result; - }); - - public static final GT_Recipe_Map_IC2NuclearFake sIC2NuclearFakeRecipe = (GT_Recipe_Map_IC2NuclearFake) new GT_Recipe_Map_IC2NuclearFake() - .setDisableOptimize(true); - - static { - sCentrifugeRecipes.addDownstream(sMultiblockCentrifugeRecipes.deepCopyInput()); - sMixerRecipes.addDownstream(sMultiblockMixerRecipes.deepCopyInput()); - sElectrolyzerRecipes.addDownstream(sMultiblockElectrolyzerRecipes.deepCopyInput()); - sDieselFuels.addDownstream( - IGT_RecipeMap.newRecipeMap( - b -> b.build() - .map(sLargeBoilerFakeFuels::addDieselRecipe) - .map(Collections::singletonList) - .orElse(Collections.emptyList()))); - sDenseLiquidFuels.addDownstream( - IGT_RecipeMap.newRecipeMap( - b -> b.build() - .map(sLargeBoilerFakeFuels::addDenseLiquidRecipe) - .map(Collections::singletonList) - .orElse(Collections.emptyList()))); - } - - @Nullable - public static GT_Recipe_Map findRecipeMap(@Nonnull String unlocalizedName) { - return sMappings.stream() - .filter(m -> unlocalizedName.equals(m.mUnlocalizedName)) - .findFirst() - .orElse(null); - } - - /** - * HashMap of Recipes based on their Items - */ - public final Map<GT_ItemStack, Collection<GT_Recipe>> mRecipeItemMap = new /* Concurrent */ HashMap<>(); - /** - * HashMap of Recipes based on their Fluids - */ - public final Map<String, Collection<GT_Recipe>> mRecipeFluidMap = new HashMap<>(); - - public final HashSet<String> mRecipeFluidNameMap = new HashSet<>(); - /** - * The List of all Recipes - */ - public final Collection<GT_Recipe> mRecipeList; - /** - * String used as an unlocalised Name. - */ - public final String mUnlocalizedName; - /** - * String used in NEI for the Recipe Lists. If null it will use the unlocalised Name instead - */ - public final String mNEIName; - /** - * GUI used for NEI Display. Usually the GUI of the Machine itself - */ - public final String mNEIGUIPath; - - public final String mNEISpecialValuePre, mNEISpecialValuePost; - public final int mUsualInputCount, mUsualOutputCount, mNEISpecialValueMultiplier, mMinimalInputItems, - mMinimalInputFluids, mAmperage; - public final boolean mNEIAllowed, mShowVoltageAmperageInNEI; - - /** - * Whether to show oredict equivalent outputs when NEI is queried to show recipe - */ - public boolean mNEIUnificateOutput = true; - - /** - * Unique identifier for this recipe map. Generated from aUnlocalizedName and a few other parameters. See - * constructor for details. - */ - public final String mUniqueIdentifier; - - /** - * Whether this recipe map contains any fluid outputs. - */ - private boolean mHasFluidOutputs = false; - - /** - * Whether this recipe map contains special slot inputs. - */ - private boolean mUsesSpecialSlot = false; - - /** - * Whether this recipemap checks for equality of special slot when searching recipe. - */ - private boolean isSpecialSlotSensitive = false; - - /** - * How many fluid inputs does this recipemap has at most. Currently used only for NEI slot placements and does - * not actually restrict number of fluids used in the recipe. - */ - private int usualFluidInputCount; - - /** - * How many fluid outputs does this recipemap has at most. Currently used only for NEI slot placements and does - * not actually restrict number of fluids used in the recipe. - */ - private int usualFluidOutputCount; - - /** - * Whether to use ModularUI for slot placements. - */ - public boolean useModularUI = false; - - /** - * Overlays used for GUI. 1 = If it's fluid slot. 2 = If it's output slot. 4 = If it's first slot in the same - * section, e.g. first slot in the item output slots 8 = If it's special item slot. - */ - private final TByteObjectMap<IDrawable> slotOverlays = new TByteObjectHashMap<>(); - - /** - * Overlays used for GUI on steam machine. 1 = If it's fluid slot. 2 = If it's output slot. 4 = If it's first - * slot in the same section, e.g. first slot in the item output slots 8 = If it's special item slot. - */ - private final TByteObjectMap<SteamTexture> slotOverlaysSteam = new TByteObjectHashMap<>(); - - /** - * Progressbar used for BasicMachine GUI and/or NEI. Unless specified, size should be (20, 36), consisting of - * two parts; First is (20, 18) size of "empty" image at the top, Second is (20, 18) size of "filled" image at - * the bottom. - */ - private FallbackableUITexture progressBarTexture; - - /** - * Progressbar used for steam machine GUI and/or NEI. Unless specified, size should be (20, 36), consisting of - * two parts; First is (20, 18) size of "empty" image at the top, Second is (20, 18) size of "filled" image at - * the bottom. - */ - private FallbackableSteamTexture progressBarTextureSteam; - - public ProgressBar.Direction progressBarDirection = ProgressBar.Direction.RIGHT; - - public Size progressBarSize = new Size(20, 18); - - public Pos2d progressBarPos = new Pos2d(78, 24); - - public Rectangle neiTransferRect = new Rectangle( - progressBarPos.x - (16 / 2), - progressBarPos.y, - progressBarSize.width + 16, - progressBarSize.height); - - /** - * Image size in direction of progress. Used for non-smooth rendering. - */ - private int progressBarImageSize; - - /** - * Additional textures shown on GUI. - */ - public final List<Pair<IDrawable, Pair<Size, Pos2d>>> specialTextures = new ArrayList<>(); - - /** - * Additional textures shown on steam machine GUI. - */ - public final List<Pair<SteamTexture, Pair<Size, Pos2d>>> specialTexturesSteam = new ArrayList<>(); - - public IDrawable logo = GT_UITextures.PICTURE_GT_LOGO_17x17_TRANSPARENT; - - public Pos2d logoPos = new Pos2d(152, 63); - - public Size logoSize = new Size(17, 17); - - public Pos2d neiBackgroundOffset = new Pos2d(2, 3); - - public Size neiBackgroundSize = new Size(172, 82); - - protected final GT_GUIColorOverride colorOverride; - private int neiTextColorOverride = -1; - - private INEISpecialInfoFormatter neiSpecialInfoFormatter; - - private final boolean checkForCollision = true; - private boolean allowNoInput; - private boolean allowNoInputFluid; - private boolean allowNoOutput; - private boolean allowNoOutputFluid; - private boolean disableOptimize = false; - private Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> recipeEmitter = this::defaultBuildRecipe; - private Function<? super GT_Recipe, ? extends GT_Recipe> specialHandler; - private String recipeConfigCategory; - private Function<? super GT_Recipe, String> recipeConfigKeyConvertor; - private final List<IGT_RecipeMap> downstreams = new ArrayList<>(0); - - /** - * Flag if a comparator should be used to search the recipe in NEI (which is defined in {@link Power}). Else - * only the voltage will be used to find recipes - */ - public boolean useComparatorForNEI; - - /** - * Whether to render the actual size of stacks or a size of 1. - */ - public boolean renderRealStackSizes = true; - - /** - * Initialises a new type of Recipe Handler. - * - * @param aRecipeList a List you specify as Recipe List. Usually just an ArrayList with a - * pre-initialised Size. - * @param aUnlocalizedName the unlocalised Name of this Recipe Handler, used mainly for NEI. - * @param aLocalName @deprecated the displayed Name inside the NEI Recipe GUI for optionally - * registering aUnlocalizedName - * with the language manager - * @param aNEIGUIPath the displayed GUI Texture, usually just a Machine GUI. Auto-Attaches ".png" - * if forgotten. - * @param aUsualInputCount the usual amount of Input Slots this Recipe Class has. - * @param aUsualOutputCount the usual amount of Output Slots this Recipe Class has. - * @param aNEISpecialValuePre the String in front of the Special Value in NEI. - * @param aNEISpecialValueMultiplier the Value the Special Value is getting Multiplied with before displaying - * @param aNEISpecialValuePost the String after the Special Value. Usually for a Unit or something. - * @param aNEIAllowed if NEI is allowed to display this Recipe Handler in general. - */ - public GT_Recipe_Map(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - sMappings.add(this); - mNEIAllowed = aNEIAllowed; - mShowVoltageAmperageInNEI = aShowVoltageAmperageInNEI; - mRecipeList = aRecipeList; - mNEIName = aNEIName == null ? aUnlocalizedName : aNEIName; - mNEIGUIPath = aNEIGUIPath.endsWith(".png") ? aNEIGUIPath : aNEIGUIPath + ".png"; - mNEISpecialValuePre = aNEISpecialValuePre; - mNEISpecialValueMultiplier = aNEISpecialValueMultiplier; - mNEISpecialValuePost = aNEISpecialValuePost; - mAmperage = aAmperage; - mUsualInputCount = aUsualInputCount; - mUsualOutputCount = aUsualOutputCount; - mMinimalInputItems = aMinimalInputItems; - mMinimalInputFluids = aMinimalInputFluids; - GregTech_API.sItemStackMappings.add(mRecipeItemMap); - mUnlocalizedName = aUnlocalizedName; - if (aLocalName != null) { - GT_LanguageManager.addStringLocalization(mUnlocalizedName, aLocalName); - } - mUniqueIdentifier = String.format( - "%s_%d_%d_%d_%d_%d", - aUnlocalizedName, - aAmperage, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputFluids, - aMinimalInputItems); - progressBarTexture = new FallbackableUITexture( - UITexture.fullImage(GregTech.ID, "gui/progressbar/" + mUnlocalizedName), - GT_UITextures.PROGRESSBAR_ARROW); - colorOverride = GT_GUIColorOverride.get(ModularUITextures.VANILLA_BACKGROUND.location); - if (sIndexedMappings.put(mUniqueIdentifier, this) != null) - throw new IllegalArgumentException("Duplicate recipe map registered: " + mUniqueIdentifier); - } - - @Deprecated - public GT_Recipe_Map(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed, - boolean aNEIUnificateOutput) { - this( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - setNEIUnificateOutput(aNEIUnificateOutput); - } - - public GT_Recipe_Map setDisableOptimize(boolean disableOptimize) { - this.disableOptimize = disableOptimize; - return this; - } - - public GT_Recipe_Map setSpecialSlotSensitive(boolean isSpecialSlotSensitive) { - this.isSpecialSlotSensitive = isSpecialSlotSensitive; - return this; - } - - public GT_Recipe_Map setNEIUnificateOutput(boolean mNEIUnificateOutput) { - this.mNEIUnificateOutput = mNEIUnificateOutput; - return this; - } - - public GT_Recipe_Map useComparatorForNEI(boolean use) { - this.useComparatorForNEI = use; - return this; - } - - public GT_Recipe_Map setRenderRealStackSizes(boolean renderRealStackSizes) { - this.renderRealStackSizes = renderRealStackSizes; - return this; - } - - public GT_Recipe_Map useModularUI(boolean use) { - this.useModularUI = use; - return this; - } - - public GT_Recipe_Map setSlotOverlay(boolean isFluid, boolean isOutput, boolean isFirst, boolean isSpecial, - IDrawable slotOverlay) { - useModularUI(true); - this.slotOverlays.put( - (byte) ((isFluid ? 1 : 0) + (isOutput ? 2 : 0) + (isFirst ? 4 : 0) + (isSpecial ? 8 : 0)), - slotOverlay); - return this; - } - - public GT_Recipe_Map setSlotOverlay(boolean isFluid, boolean isOutput, boolean isFirst, IDrawable slotOverlay) { - return setSlotOverlay(isFluid, isOutput, isFirst, false, slotOverlay); - } - - public GT_Recipe_Map setSlotOverlay(boolean isFluid, boolean isOutput, IDrawable slotOverlay) { - return setSlotOverlay(isFluid, isOutput, true, slotOverlay) - .setSlotOverlay(isFluid, isOutput, false, slotOverlay); - } - - public GT_Recipe_Map setSlotOverlaySteam(boolean isFluid, boolean isOutput, boolean isFirst, boolean isSpecial, - SteamTexture slotOverlay) { - useModularUI(true); - this.slotOverlaysSteam.put( - (byte) ((isFluid ? 1 : 0) + (isOutput ? 2 : 0) + (isFirst ? 4 : 0) + (isSpecial ? 8 : 0)), - slotOverlay); - return this; - } - - public GT_Recipe_Map setSlotOverlaySteam(boolean isOutput, boolean isFirst, SteamTexture slotOverlay) { - return setSlotOverlaySteam(false, isOutput, isFirst, false, slotOverlay); - } - - public GT_Recipe_Map setSlotOverlaySteam(boolean isOutput, SteamTexture slotOverlay) { - return setSlotOverlaySteam(false, isOutput, true, false, slotOverlay) - .setSlotOverlaySteam(false, isOutput, false, false, slotOverlay); - } - - public GT_Recipe_Map setProgressBar(UITexture progressBarTexture, ProgressBar.Direction progressBarDirection) { - return setProgressBarWithFallback( - new FallbackableUITexture( - UITexture.fullImage(GregTech.ID, "gui/progressbar/" + mUnlocalizedName), - progressBarTexture), - progressBarDirection); - } - - public GT_Recipe_Map setProgressBar(UITexture progressBarTexture) { - return setProgressBar(progressBarTexture, ProgressBar.Direction.RIGHT); - } - - /** - * Some resource packs want to use custom progress bar textures even for plain arrow. This method allows them to - * add unique textures, yet other packs don't need to make textures for every recipemap. - */ - public GT_Recipe_Map setProgressBarWithFallback(FallbackableUITexture progressBarTexture, - ProgressBar.Direction progressBarDirection) { - useModularUI(true); - this.progressBarTexture = progressBarTexture; - this.progressBarDirection = progressBarDirection; - return this; - } - - public GT_Recipe_Map setProgressBarSteam(SteamTexture progressBarTexture) { - return setProgressBarSteamWithFallback( - new FallbackableSteamTexture( - SteamTexture.fullImage(GregTech.ID, "gui/progressbar/" + mUnlocalizedName + "_%s"), - progressBarTexture)); - } - - public GT_Recipe_Map setProgressBarSteamWithFallback(FallbackableSteamTexture progressBarTexture) { - this.progressBarTextureSteam = progressBarTexture; - return this; - } - - public GT_Recipe_Map setProgressBarSize(int x, int y) { - useModularUI(true); - this.progressBarSize = new Size(x, y); - return this; - } - - public GT_Recipe_Map setProgressBarPos(int x, int y) { - useModularUI(true); - this.progressBarPos = new Pos2d(x, y); - return this; - } - - public GT_Recipe_Map setProgressBarImageSize(int progressBarImageSize) { - useModularUI(true); - this.progressBarImageSize = progressBarImageSize; - return this; - } - - public GT_Recipe_Map setNEITransferRect(Rectangle neiTransferRect) { - useModularUI(true); - this.neiTransferRect = neiTransferRect; - return this; - } - - public GT_Recipe_Map addSpecialTexture(int width, int height, int x, int y, IDrawable texture) { - useModularUI(true); - specialTextures - .add(new ImmutablePair<>(texture, new ImmutablePair<>(new Size(width, height), new Pos2d(x, y)))); - return this; - } - - public GT_Recipe_Map addSpecialTextureSteam(int width, int height, int x, int y, SteamTexture texture) { - useModularUI(true); - specialTexturesSteam - .add(new ImmutablePair<>(texture, new ImmutablePair<>(new Size(width, height), new Pos2d(x, y)))); - return this; - } - - public GT_Recipe_Map setUsualFluidInputCount(int usualFluidInputCount) { - useModularUI(true); - this.usualFluidInputCount = usualFluidInputCount; - return this; - } - - public GT_Recipe_Map setUsualFluidOutputCount(int usualFluidOutputCount) { - useModularUI(true); - this.usualFluidOutputCount = usualFluidOutputCount; - return this; - } - - public GT_Recipe_Map setLogo(IDrawable logo) { - useModularUI(true); - this.logo = logo; - return this; - } - - public GT_Recipe_Map setLogoPos(int x, int y) { - useModularUI(true); - this.logoPos = new Pos2d(x, y); - return this; - } - - public GT_Recipe_Map setLogoSize(int width, int height) { - useModularUI(true); - this.logoSize = new Size(width, height); - return this; - } - - public GT_Recipe_Map setNEIBackgroundOffset(int x, int y) { - useModularUI(true); - this.neiBackgroundOffset = new Pos2d(x, y); - return this; - } - - public GT_Recipe_Map setNEIBackgroundSize(int width, int height) { - useModularUI(true); - this.neiBackgroundSize = new Size(width, height); - return this; - } - - public GT_Recipe_Map setNEISpecialInfoFormatter(INEISpecialInfoFormatter neiSpecialInfoFormatter) { - this.neiSpecialInfoFormatter = neiSpecialInfoFormatter; - return this; - } - - /** - * Change how recipes are emitted by a particular recipe builder. Can emit multiple recipe per builder. - */ - public GT_Recipe_Map setRecipeEmitter( - Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> func) { - this.recipeEmitter = func; - return this; - } - - /** - * Change how recipes are emitted by a particular recipe builder. Can emit multiple recipe per builder. - * <p> - * Unlike {@link #setRecipeEmitter(Function)}, this one does not clear the existing recipe being emitted, if any - */ - public GT_Recipe_Map combineRecipeEmitter( - Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> func) { - // move recipeEmitter to local variable, so lambda capture the function itself instead of this - Function<? super GT_RecipeBuilder, ? extends Iterable<? extends GT_Recipe>> cur = recipeEmitter; - this.recipeEmitter = b -> Iterables.concat(cur.apply(b), func.apply(b)); - return this; - } - - /** - * Change how recipes are emitted by a particular recipe builder. Should not return null. - */ - public GT_Recipe_Map setRecipeEmitterSingle(Function<? super GT_RecipeBuilder, ? extends GT_Recipe> func) { - return setRecipeEmitter(func.andThen(Collections::singletonList)); - } - - /** - * Change how recipes are emitted by a particular recipe builder. Effectively add a new recipe per recipe added. - * func must not return null. - * <p> - * Unlike {@link #setRecipeEmitter(Function)}, this one does not clear the existing recipe being emitted, if any - */ - public GT_Recipe_Map combineRecipeEmitterSingle(Function<? super GT_RecipeBuilder, ? extends GT_Recipe> func) { - return combineRecipeEmitter(func.andThen(Collections::singletonList)); - } - - private static <T> Function<? super T, ? extends T> withIdentityReturn(Consumer<T> func) { - return r -> { - func.accept(r); - return r; - }; - } - - /** - * Run a custom hook on all recipes added <b>via builder</b>. For more complicated behavior subclass this, then - * override {@link #doAdd(GT_RecipeBuilder)} - * - * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. - */ - public GT_Recipe_Map setRecipeSpecialHandler(Function<? super GT_Recipe, ? extends GT_Recipe> func) { - this.specialHandler = func; - return this; - } - - /** - * Run a custom hook on all recipes added <b>via builder</b>. For more complicated behavior, create a subclass - * and override {@link #doAdd(GT_RecipeBuilder)} - * - * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. - */ - public GT_Recipe_Map setRecipeSpecialHandler(Consumer<GT_Recipe> func) { - return setRecipeSpecialHandler(withIdentityReturn(func)); - } - - /** - * Run a custom hook on all recipes added <b>via builder</b>. For more complicated behavior subclass this, then - * override {@link #doAdd(GT_RecipeBuilder)}. - * <p> - * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. - * <p> - * Unlike {@link #setRecipeSpecialHandler(Function)}, this one will not replace the existing special handler. - * The supplied function will be given the output of existing handler when a recipe is added. - */ - public GT_Recipe_Map chainRecipeSpecialHandler(Function<? super GT_Recipe, ? extends GT_Recipe> func) { - this.specialHandler = specialHandler == null ? func : specialHandler.andThen(func); - return this; - } - - /** - * Run a custom hook on all recipes added <b>via builder</b>. For more complicated behavior subclass this, then - * override {@link #doAdd(GT_RecipeBuilder)}. - * <p> - * Recipes added via one of the overloads of addRecipe will NOT be affected by this function. - * <p> - * Unlike {@link #setRecipeSpecialHandler(Function)}, this one will not replace the existing special handler. - * The supplied function will be given the output of existing handler when a recipe is added. - */ - public GT_Recipe_Map chainRecipeSpecialHandler(Consumer<GT_Recipe> func) { - return chainRecipeSpecialHandler(withIdentityReturn(func)); - } - - public GT_Recipe_Map setRecipeConfigFile(String category, Function<? super GT_Recipe, String> keyConvertor) { - if (StringUtils.isBlank(category) || keyConvertor == null) throw new IllegalArgumentException(); - this.recipeConfigCategory = category; - this.recipeConfigKeyConvertor = keyConvertor; - return this; - } - - @Override - public void addDownstream(IGT_RecipeMap downstream) { - this.downstreams.add(downstream); - } - - public GT_Recipe addRecipe(boolean aOptimize, ItemStack[] aInputs, ItemStack[] aOutputs, Object aSpecial, - int[] aOutputChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue) { - return addRecipe( - new GT_Recipe( - aOptimize, - aInputs, - aOutputs, - aSpecial, - aOutputChances, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue)); - } - - public GT_Recipe addRecipe(int[] aOutputChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, - int aDuration, int aEUt, int aSpecialValue) { - return addRecipe( - new GT_Recipe( - false, - null, - null, - null, - aOutputChances, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue), - false, - false, - false); - } - - public GT_Recipe addRecipe(boolean aOptimize, ItemStack[] aInputs, ItemStack[] aOutputs, Object aSpecial, - FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue) { - return addRecipe( - new GT_Recipe( - aOptimize, - aInputs, - aOutputs, - aSpecial, - null, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue)); - } - - public GT_Recipe addRecipe(GT_Recipe aRecipe) { - return addRecipe(aRecipe, true, false, false); - } - - protected GT_Recipe addRecipe(GT_Recipe aRecipe, boolean aCheckForCollisions, boolean aFakeRecipe, - boolean aHidden) { - aRecipe.mHidden = aHidden; - aRecipe.mFakeRecipe = aFakeRecipe; - if (aRecipe.mFluidInputs.length < mMinimalInputFluids && aRecipe.mInputs.length < mMinimalInputItems) - return null; - if (aCheckForCollisions - && findRecipe(null, false, true, Long.MAX_VALUE, aRecipe.mFluidInputs, aRecipe.mInputs) != null) - return null; - return add(aRecipe); - } - - /** - * Only used for fake Recipe Handlers to show something in NEI, do not use this for adding actual Recipes! - * findRecipe wont find fake Recipes, containsInput WILL find fake Recipes - */ - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, int[] aOutputChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, - int aEUt, int aSpecialValue) { - return addFakeRecipe( - aCheckForCollisions, - new GT_Recipe( - false, - aInputs, - aOutputs, - aSpecial, - aOutputChances, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue)); - } - - /** - * Only used for fake Recipe Handlers to show something in NEI, do not use this for adding actual Recipes! - * findRecipe wont find fake Recipes, containsInput WILL find fake Recipes - */ - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue) { - return addFakeRecipe( - aCheckForCollisions, - new GT_Recipe( - false, - aInputs, - aOutputs, - aSpecial, - null, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue)); - } - - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue, boolean hidden) { - return addFakeRecipe( - aCheckForCollisions, - new GT_Recipe( - false, - aInputs, - aOutputs, - aSpecial, - null, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue), - hidden); - } - - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue, ItemStack[][] aAlt, boolean hidden) { - return addFakeRecipe( - aCheckForCollisions, - new GT_Recipe_WithAlt( - false, - aInputs, - aOutputs, - aSpecial, - null, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue, - aAlt), - hidden); - } - - /** - * Only used for fake Recipe Handlers to show something in NEI, do not use this for adding actual Recipes! - * findRecipe wont find fake Recipes, containsInput WILL find fake Recipes - */ - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, GT_Recipe aRecipe) { - return addRecipe(aRecipe, aCheckForCollisions, true, false); - } - - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, GT_Recipe aRecipe, boolean hidden) { - return addRecipe(aRecipe, aCheckForCollisions, true, hidden); - } - - @Nonnull - @Override - public Collection<GT_Recipe> doAdd(GT_RecipeBuilder builder) { - Iterable<? extends GT_Recipe> recipes = recipeEmitter.apply(builder); - Collection<GT_Recipe> ret = new ArrayList<>(); - for (GT_Recipe r : recipes) { - if (recipeConfigCategory != null) { - String configKey = recipeConfigKeyConvertor.apply(r); - if (configKey != null - && (r.mDuration = GregTech_API.sRecipeFile.get(recipeConfigCategory, configKey, r.mDuration)) - <= 0) { - continue; - } - } - if (r.mFluidInputs.length < mMinimalInputFluids && r.mInputs.length < mMinimalInputItems) return null; - if (r.mSpecialValue == 0) { - // new style cleanroom/lowgrav handling - int specialValue = 0; - if (builder.getMetadata(GT_RecipeConstants.LOW_GRAVITY, false)) specialValue -= 100; - if (builder.getMetadata(GT_RecipeConstants.CLEANROOM, false)) specialValue -= 200; - for (GT_RecipeBuilder.MetadataIdentifier<Integer> ident : SPECIAL_VALUE_ALIASES) { - Integer metadata = builder.getMetadata(ident, null); - if (metadata != null) { - specialValue = metadata; - break; - } - } - r.mSpecialValue = specialValue; - } - if (specialHandler != null) r = specialHandler.apply(r); - if (r == null) continue; - if (checkForCollision - && findRecipe(null, false, true, Long.MAX_VALUE, r.mFluidInputs, r.mInputs) != null) { - StringBuilder errorInfo = new StringBuilder(); - boolean hasAnEntry = false; - for (FluidStack fStack : r.mFluidInputs) { - if (fStack == null) { - continue; - } - String s = fStack.getLocalizedName(); - if (s == null) { - continue; - } - if (hasAnEntry) { - errorInfo.append("+") - .append(s); - } else { - errorInfo.append(s); - } - hasAnEntry = true; - } - for (ItemStack iStack : r.mInputs) { - if (iStack == null) { - continue; - } - String s = iStack.getDisplayName(); - if (hasAnEntry) { - errorInfo.append("+") - .append(s); - } else { - errorInfo.append(s); - } - hasAnEntry = true; - } - handleRecipeCollision(errorInfo.toString()); - continue; - } - ret.add(add(r)); - } - if (!ret.isEmpty()) { - builder.clearInvalid(); - for (IGT_RecipeMap downstream : downstreams) { - downstream.doAdd(builder); - } - } - return ret; - } - - public final Iterable<? extends GT_Recipe> defaultBuildRecipe(GT_RecipeBuilder builder) { - // TODO sensible validation - GT_RecipeBuilder b = builder; - if (disableOptimize && builder.optimize) { - b = copy(builder, b).noOptimize(); - } - return buildOrEmpty(b); - } - - private static GT_RecipeBuilder copy(GT_RecipeBuilder original, GT_RecipeBuilder b) { - return b == original ? b.copy() : b; - } - - public GT_Recipe add(GT_Recipe aRecipe) { - mRecipeList.add(aRecipe); - for (FluidStack aFluid : aRecipe.mFluidInputs) { - if (aFluid != null) { - Collection<GT_Recipe> tList = mRecipeFluidMap.computeIfAbsent( - aFluid.getFluid() - .getName(), - k -> new HashSet<>(1)); - tList.add(aRecipe); - mRecipeFluidNameMap.add( - aFluid.getFluid() - .getName()); - } - } - if (aRecipe.mFluidOutputs.length != 0) { - this.mHasFluidOutputs = true; - } - if (aRecipe.mSpecialItems != null) { - this.mUsesSpecialSlot = true; - } - return addToItemMap(aRecipe); - } - - public void reInit() { - mRecipeItemMap.clear(); - for (GT_Recipe tRecipe : mRecipeList) { - GT_OreDictUnificator.setStackArray(true, tRecipe.mInputs); - GT_OreDictUnificator.setStackArray(true, tRecipe.mOutputs); - addToItemMap(tRecipe); - } - } - - /** - * @return if this Item is a valid Input for any for the Recipes - */ - public boolean containsInput(ItemStack aStack) { - return aStack != null && (mRecipeItemMap.containsKey(new GT_ItemStack(aStack)) - || mRecipeItemMap.containsKey(new GT_ItemStack(aStack, true))); - } - - /** - * @return if this Fluid is a valid Input for any for the Recipes - */ - public boolean containsInput(FluidStack aFluid) { - return aFluid != null && containsInput(aFluid.getFluid()); - } - - /** - * @return if this Fluid is a valid Input for any for the Recipes - */ - public boolean containsInput(Fluid aFluid) { - return aFluid != null && mRecipeFluidNameMap.contains(aFluid.getName()); - } - - @Nullable - public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, long aVoltage, - FluidStack[] aFluids, ItemStack... aInputs) { - return findRecipe(aTileEntity, null, aNotUnificated, aVoltage, aFluids, null, aInputs); - } - - @Nullable - public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, - boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack... aInputs) { - return findRecipe( - aTileEntity, - null, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - null, - aInputs); - } - - @Nullable - public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, - boolean aNotUnificated, long aVoltage, FluidStack[] aFluids, ItemStack... aInputs) { - return findRecipe(aTileEntity, aRecipe, aNotUnificated, aVoltage, aFluids, null, aInputs); - } - - @Nullable - public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack... aInputs) { - return findRecipe( - aTileEntity, - aRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - null, - aInputs); - } - - @Nullable - public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, - boolean aNotUnificated, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - return findRecipe(aTileEntity, aRecipe, aNotUnificated, false, aVoltage, aFluids, aSpecialSlot, aInputs); - } - - // TODO: make this final after migrating BW - @SuppressWarnings("unused") - @Nullable - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, - ItemStack... aInputs) { - FindRecipeResult result = findRecipeWithResult( - aRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - return result.isSuccessful() ? result.getRecipe() : null; - } - - /** - * finds a Recipe matching the aFluid and ItemStack Inputs. - * - * @param aRecipe in case this is != null it will try to use this Recipe first when looking things - * up. - * @param aNotUnificated if this is T the Recipe searcher will unificate the ItemStack Inputs - * @param aDontCheckStackSizes if set to false will only return recipes that can be executed at least once with - * the provided input - * @param aVoltage Voltage of the Machine or Long.MAX_VALUE if it has no Voltage - * @param aFluids the Fluid Inputs - * @param aSpecialSlot the content of the Special Slot, the regular Manager doesn't do anything with - * this, but some custom ones do. - * @param aInputs the Item Inputs - * @return Result of the recipe search - */ - @Nonnull - public final FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, - boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, - ItemStack... aInputs) { - return findRecipeWithResult( - aRecipe, - recipe -> aVoltage * mAmperage >= recipe.mEUt, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - } - - /** - * finds a Recipe matching the aFluid and ItemStack Inputs. - * - * @param aRecipe in case this is != null it will try to use this Recipe first when looking things - * up. - * @param aIsValidRecipe predicate to help identify, if the recipe matches our machine - * @param aNotUnificated if this is T the Recipe searcher will unificate the ItemStack Inputs - * @param aDontCheckStackSizes if set to false will only return recipes that can be executed at least once with - * the provided input - * @param aVoltage Voltage of the Machine or Long.MAX_VALUE if it has no Voltage - * @param aFluids the Fluid Inputs - * @param aSpecialSlot the content of the Special Slot, the regular Manager doesn't do anything with - * this, but some custom ones do. - * @param aInputs the Item Inputs - * @return Result of the recipe search - */ - @Nonnull - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - // No Recipes? Well, nothing to be found then. - if (mRecipeList.isEmpty()) return NOT_FOUND; - - // Some Recipe Classes require a certain amount of Inputs of certain kinds. Like "at least 1 Fluid + 1 - // Stack" or "at least 2 Stacks" before they start searching for Recipes. - // This improves Performance massively, especially if people leave things like Circuits, Molds or Shapes in - // their Machines to select Sub Recipes. - if (GregTech_API.sPostloadFinished) { - if (mMinimalInputFluids > 0) { - if (aFluids == null) return NOT_FOUND; - int tAmount = 0; - for (FluidStack aFluid : aFluids) if (aFluid != null) tAmount++; - if (tAmount < mMinimalInputFluids) return NOT_FOUND; - } - if (mMinimalInputItems > 0) { - if (aInputs == null) return NOT_FOUND; - int tAmount = 0; - for (ItemStack aInput : aInputs) if (aInput != null) tAmount++; - if (tAmount < mMinimalInputItems) return NOT_FOUND; - } - } - - // Unification happens here in case the Input isn't already unificated. - if (aNotUnificated) aInputs = GT_OreDictUnificator.getStackArray(true, (Object[]) aInputs); - - // Check the Recipe which has been used last time in order to not have to search for it again, if possible. - if (aRecipe != null) if (!aRecipe.mFakeRecipe && aRecipe.mCanBeBuffered - && aRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { - if (!isSpecialSlotSensitive - || GT_Utility.areStacksEqualOrNull((ItemStack) aRecipe.mSpecialItems, aSpecialSlot)) { - if (aRecipe.mEnabled && aIsValidRecipe.test(aRecipe)) { - return ofSuccess(aRecipe); - } - } - } - - // Now look for the Recipes inside the Item HashMaps, but only when the Recipes usually have Items. - if (mUsualInputCount > 0 && aInputs != null) for (ItemStack tStack : aInputs) if (tStack != null) { - Collection<GT_Recipe> tRecipes = mRecipeItemMap.get(new GT_ItemStack(tStack)); - if (tRecipes != null) for (GT_Recipe tRecipe : tRecipes) if (!tRecipe.mFakeRecipe - && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { - if (!isSpecialSlotSensitive - || GT_Utility.areStacksEqualOrNull((ItemStack) tRecipe.mSpecialItems, aSpecialSlot)) { - if (tRecipe.mEnabled && aIsValidRecipe.test(tRecipe)) { - return ofSuccess(tRecipe); - } - } - } - tRecipes = mRecipeItemMap.get(new GT_ItemStack(tStack, true)); - if (tRecipes != null) for (GT_Recipe tRecipe : tRecipes) if (!tRecipe.mFakeRecipe - && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { - if (!isSpecialSlotSensitive - || GT_Utility.areStacksEqualOrNull((ItemStack) tRecipe.mSpecialItems, aSpecialSlot)) { - if (tRecipe.mEnabled && aIsValidRecipe.test(tRecipe)) { - return ofSuccess(tRecipe); - } - } - } - } - - // If the minimal Amount of Items for the Recipe is 0, then it could be a Fluid-Only Recipe, so check that - // Map too. - if (mMinimalInputItems == 0 && aFluids != null) for (FluidStack aFluid : aFluids) if (aFluid != null) { - Collection<GT_Recipe> tRecipes = mRecipeFluidMap.get( - aFluid.getFluid() - .getName()); - if (tRecipes != null) for (GT_Recipe tRecipe : tRecipes) if (!tRecipe.mFakeRecipe - && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { - if (!isSpecialSlotSensitive - || GT_Utility.areStacksEqualOrNull((ItemStack) tRecipe.mSpecialItems, aSpecialSlot)) { - if (tRecipe.mEnabled && aIsValidRecipe.test(tRecipe)) { - return ofSuccess(tRecipe); - } - } - } - } - - // And nothing has been found. - return NOT_FOUND; - } - - protected GT_Recipe addToItemMap(GT_Recipe aRecipe) { - for (ItemStack aStack : aRecipe.mInputs) if (aStack != null) { - GT_ItemStack tStack = new GT_ItemStack(aStack); - Collection<GT_Recipe> tList = mRecipeItemMap.computeIfAbsent(tStack, k -> new HashSet<>(1)); - tList.add(aRecipe); - } - return aRecipe; - } - - /** - * Whether this recipe map contains any fluid outputs. - */ - public boolean hasFluidOutputs() { - return mHasFluidOutputs; - } - - /** - * Whether this recipe map contains any fluid inputs. - */ - public boolean hasFluidInputs() { - return mRecipeFluidNameMap.size() != 0; - } - - /** - * Whether this recipe map contains special slot inputs. - */ - public boolean usesSpecialSlot() { - return mUsesSpecialSlot; - } - - public int getUsualFluidInputCount() { - return Math.max(usualFluidInputCount, hasFluidInputs() ? 1 : 0); - } - - public int getUsualFluidOutputCount() { - return Math.max(usualFluidOutputCount, hasFluidOutputs() ? 1 : 0); - } - - @Nullable - public IDrawable getOverlayForSlot(boolean isFluid, boolean isOutput, int index, boolean isSpecial) { - byte overlayKey = (byte) ((isFluid ? 1 : 0) + (isOutput ? 2 : 0) - + (index == 0 ? 4 : 0) - + (isSpecial ? 8 : 0)); - if (slotOverlays.containsKey(overlayKey)) { - return slotOverlays.get(overlayKey); - } - return null; - } - - @Nullable - public SteamTexture getOverlayForSlotSteam(boolean isFluid, boolean isOutput, int index, boolean isSpecial) { - byte overlayKey = (byte) ((isFluid ? 1 : 0) + (isOutput ? 2 : 0) - + (index == 0 ? 4 : 0) - + (isSpecial ? 8 : 0)); - if (slotOverlaysSteam.containsKey(overlayKey)) { - return slotOverlaysSteam.get(overlayKey); - } - return null; - } - - @Nullable - public SteamTexture getOverlayForSlotSteam(boolean isOutput, boolean isFirst) { - byte overlayKey = (byte) ((isOutput ? 2 : 0) + (isFirst ? 4 : 0)); - if (slotOverlaysSteam.containsKey(overlayKey)) { - return slotOverlaysSteam.get(overlayKey); - } - return null; - } - - public UITexture getProgressBarTexture() { - return progressBarTexture.get(); - } - - public FallbackableUITexture getProgressBarTextureRaw() { - return progressBarTexture; - } - - public UITexture getProgressBarTextureSteam(SteamVariant steamVariant) { - return progressBarTextureSteam.get(steamVariant); - } - - public int getProgressBarImageSize() { - if (progressBarImageSize != 0) { - return progressBarImageSize; - } - return switch (progressBarDirection) { - case UP, DOWN -> progressBarSize.height; - case CIRCULAR_CW -> Math.max(progressBarSize.width, progressBarSize.height); - default -> progressBarSize.width; - }; - } - - /** - * Adds slot backgrounds, progressBar, etc. - */ - public ModularWindow.Builder createNEITemplate(IItemHandlerModifiable itemInputsInventory, - IItemHandlerModifiable itemOutputsInventory, IItemHandlerModifiable specialSlotInventory, - IItemHandlerModifiable fluidInputsInventory, IItemHandlerModifiable fluidOutputsInventory, - Supplier<Float> progressSupplier, Pos2d windowOffset) { - ModularWindow.Builder builder = ModularWindow.builder(neiBackgroundSize) - .setBackground(ModularUITextures.VANILLA_BACKGROUND); - - UIHelper.forEachSlots( - (i, backgrounds, pos) -> builder.widget( - SlotWidget.phantom(itemInputsInventory, i) - .setBackground(backgrounds) - .setPos(pos) - .setSize(18, 18)), - (i, backgrounds, pos) -> builder.widget( - SlotWidget.phantom(itemOutputsInventory, i) - .setBackground(backgrounds) - .setPos(pos) - .setSize(18, 18)), - (i, backgrounds, pos) -> { - if (usesSpecialSlot()) builder.widget( - SlotWidget.phantom(specialSlotInventory, 0) - .setBackground(backgrounds) - .setPos(pos) - .setSize(18, 18)); - }, - (i, backgrounds, pos) -> builder.widget( - SlotWidget.phantom(fluidInputsInventory, i) - .setBackground(backgrounds) - .setPos(pos) - .setSize(18, 18)), - (i, backgrounds, pos) -> builder.widget( - SlotWidget.phantom(fluidOutputsInventory, i) - .setBackground(backgrounds) - .setPos(pos) - .setSize(18, 18)), - ModularUITextures.ITEM_SLOT, - ModularUITextures.FLUID_SLOT, - this, - mUsualInputCount, - mUsualOutputCount, - getUsualFluidInputCount(), - getUsualFluidOutputCount(), - SteamVariant.NONE, - windowOffset); - - addProgressBarUI(builder, progressSupplier, windowOffset); - addGregTechLogoUI(builder, windowOffset); - - for (Pair<IDrawable, Pair<Size, Pos2d>> specialTexture : specialTextures) { - builder.widget( - new DrawableWidget().setDrawable(specialTexture.getLeft()) - .setSize( - specialTexture.getRight() - .getLeft()) - .setPos( - specialTexture.getRight() - .getRight() - .add(windowOffset))); - } - - return builder; - } - - public void addProgressBarUI(ModularWindow.Builder builder, Supplier<Float> progressSupplier, - Pos2d windowOffset) { - builder.widget( - new ProgressBar().setTexture(getProgressBarTexture(), 20) - .setDirection(progressBarDirection) - .setProgress(progressSupplier) - .setSynced(false, false) - .setPos(progressBarPos.add(windowOffset)) - .setSize(progressBarSize)); - } - - public void addGregTechLogoUI(ModularWindow.Builder builder, Pos2d windowOffset) { - builder.widget( - new DrawableWidget().setDrawable(logo) - .setSize(logoSize) - .setPos(logoPos.add(windowOffset))); - } - - public void addRecipeSpecificDrawable(ModularWindow.Builder builder, Pos2d windowOffset, - Supplier<IDrawable> supplier, Pos2d pos, Size size) { - builder.widget( - new DrawableWidget().setDrawable(supplier) - .setSize(size) - .setPos(pos.add(windowOffset))); - } - - /** - * Overriding this method allows custom NEI stack placement - */ - public List<Pos2d> getItemInputPositions(int itemInputCount) { - return UIHelper.getItemInputPositions(itemInputCount); - } - - /** - * Overriding this method allows custom NEI stack placement - */ - public List<Pos2d> getItemOutputPositions(int itemOutputCount) { - return UIHelper.getItemOutputPositions(itemOutputCount); - } - - /** - * Overriding this method allows custom NEI stack placement - */ - public Pos2d getSpecialItemPosition() { - return UIHelper.getSpecialItemPosition(); - } - - /** - * Overriding this method allows custom NEI stack placement - */ - public List<Pos2d> getFluidInputPositions(int fluidInputCount) { - return UIHelper.getFluidInputPositions(fluidInputCount); - } - - /** - * Overriding this method allows custom NEI stack placement - */ - public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { - return UIHelper.getFluidOutputPositions(fluidOutputCount); - } - - public void drawNEIDescription(NEIRecipeInfo recipeInfo) { - drawNEIEnergyInfo(recipeInfo); - drawNEIDurationInfo(recipeInfo); - drawNEISpecialInfo(recipeInfo); - drawNEIRecipeOwnerInfo(recipeInfo); - } - - protected void drawNEIEnergyInfo(NEIRecipeInfo recipeInfo) { - GT_Recipe recipe = recipeInfo.recipe; - Power power = recipeInfo.power; - if (power.getEuPerTick() > 0) { - drawNEIText(recipeInfo, GT_Utility.trans("152", "Total: ") + power.getTotalPowerString()); - - String amperage = power.getAmperageString(); - String powerUsage = power.getPowerUsageString(); - if (amperage == null || amperage.equals("unspecified") || powerUsage.contains("(OC)")) { - drawNEIText(recipeInfo, GT_Utility.trans("153", "Usage: ") + powerUsage); - if (GT_Mod.gregtechproxy.mNEIOriginalVoltage) { - Power originalPower = getPowerFromRecipeMap(); - if (!(originalPower instanceof UnspecifiedEUPower)) { - originalPower.computePowerUsageAndDuration(recipe.mEUt, recipe.mDuration); - drawNEIText( - recipeInfo, - GT_Utility.trans("275", "Original voltage: ") + originalPower.getVoltageString()); - } - } - if (amperage != null && !amperage.equals("unspecified") && !amperage.equals("1")) { - drawNEIText(recipeInfo, GT_Utility.trans("155", "Amperage: ") + amperage); - } - } else if (amperage.equals("1")) { - drawNEIText(recipeInfo, GT_Utility.trans("154", "Voltage: ") + power.getVoltageString()); - } else { - drawNEIText(recipeInfo, GT_Utility.trans("153", "Usage: ") + powerUsage); - drawNEIText(recipeInfo, GT_Utility.trans("154", "Voltage: ") + power.getVoltageString()); - drawNEIText(recipeInfo, GT_Utility.trans("155", "Amperage: ") + amperage); - } - } - } - - protected void drawNEIDurationInfo(NEIRecipeInfo recipeInfo) { - Power power = recipeInfo.power; - if (power.getDurationTicks() > 0) { - String textToDraw = GT_Utility.trans("158", "Time: "); - if (GT_Mod.gregtechproxy.mNEIRecipeSecondMode) { - textToDraw += power.getDurationStringSeconds(); - if (power.getDurationSeconds() <= 1.0d) { - textToDraw += String.format(" (%s)", power.getDurationStringTicks()); - } - } else { - textToDraw += power.getDurationStringTicks(); - } - drawNEIText(recipeInfo, textToDraw); - } - } - - protected void drawNEISpecialInfo(NEIRecipeInfo recipeInfo) { - String[] recipeDesc = recipeInfo.recipe.getNeiDesc(); - if (recipeDesc != null) { - for (String s : recipeDesc) { - drawOptionalNEIText(recipeInfo, s); - } - } else if (neiSpecialInfoFormatter != null) { - drawNEITextMultipleLines( - recipeInfo, - neiSpecialInfoFormatter.format(recipeInfo, this::formatSpecialValue)); - } else { - drawOptionalNEIText(recipeInfo, getNEISpecialInfo(recipeInfo.recipe.mSpecialValue)); - } - } - - protected String getNEISpecialInfo(int specialValue) { - if (specialValue == -100 && GT_Mod.gregtechproxy.mLowGravProcessing) { - return GT_Utility.trans("159", "Needs Low Gravity"); - } else if (specialValue == -200 && GT_Mod.gregtechproxy.mEnableCleanroom) { - return GT_Utility.trans("160", "Needs Cleanroom"); - } else if (specialValue == -201) { - return GT_Utility.trans("206", "Scan for Assembly Line"); - } else if (specialValue == -300 && GT_Mod.gregtechproxy.mEnableCleanroom) { - return GT_Utility.trans("160.1", "Needs Cleanroom & LowGrav"); - } else if (specialValue == -400) { - return GT_Utility.trans("216", "Deprecated Recipe"); - } else if (hasSpecialValueFormat()) { - return formatSpecialValue(specialValue); - } - return null; - } - - private boolean hasSpecialValueFormat() { - return (GT_Utility.isStringValid(mNEISpecialValuePre)) || (GT_Utility.isStringValid(mNEISpecialValuePost)); - } - - protected String formatSpecialValue(int specialValue) { - return mNEISpecialValuePre + formatNumbers((long) specialValue * mNEISpecialValueMultiplier) - + mNEISpecialValuePost; - } - - protected void drawNEIRecipeOwnerInfo(NEIRecipeInfo recipeInfo) { - GT_Recipe recipe = recipeInfo.recipe; - if (GT_Mod.gregtechproxy.mNEIRecipeOwner) { - if (recipe.owners.size() > 1) { - drawNEIText( - recipeInfo, - EnumChatFormatting.ITALIC + GT_Utility.trans("273", "Original Recipe by: ") - + recipe.owners.get(0) - .getName()); - for (int i = 1; i < recipe.owners.size(); i++) { - drawNEIText( - recipeInfo, - EnumChatFormatting.ITALIC + GT_Utility.trans("274", "Modified by: ") - + recipe.owners.get(i) - .getName()); - } - } else if (recipe.owners.size() > 0) { - drawNEIText( - recipeInfo, - EnumChatFormatting.ITALIC + GT_Utility.trans("272", "Recipe by: ") - + recipe.owners.get(0) - .getName()); - } - } - if (GT_Mod.gregtechproxy.mNEIRecipeOwnerStackTrace && recipe.stackTraces != null - && !recipe.stackTraces.isEmpty()) { - drawNEIText(recipeInfo, "stackTrace:"); - // todo: good way to show all stacktraces - for (StackTraceElement stackTrace : recipe.stackTraces.get(0)) { - drawNEIText(recipeInfo, stackTrace.toString()); - } - } - } - - protected void drawNEIText(NEIRecipeInfo recipeInfo, String text) { - drawNEIText(recipeInfo, text, 10); - } - - /** - * Draws text on NEI recipe. - * - * @param yShift y position to shift after this text - */ - @SuppressWarnings("SameParameterValue") - protected void drawNEIText(NEIRecipeInfo recipeInfo, String text, int yShift) { - drawNEIText(recipeInfo, text, 10, yShift); - } - - /** - * Draws text on NEI recipe. - * - * @param xStart x position to start drawing - * @param yShift y position to shift after this text - */ - @SuppressWarnings("SameParameterValue") - protected void drawNEIText(NEIRecipeInfo recipeInfo, String text, int xStart, int yShift) { - Minecraft.getMinecraft().fontRenderer.drawString( - text, - xStart, - recipeInfo.yPos, - neiTextColorOverride != -1 ? neiTextColorOverride : 0x000000); - recipeInfo.yPos += yShift; - } - - protected void drawOptionalNEIText(NEIRecipeInfo recipeInfo, String text) { - if (GT_Utility.isStringValid(text) && !text.equals("unspecified")) { - drawNEIText(recipeInfo, text, 10); - } - } - - protected void drawNEITextMultipleLines(NEIRecipeInfo recipeInfo, List<String> texts) { - for (String text : texts) { - drawNEIText(recipeInfo, text, 10); - } - } - - public List<String> handleNEIItemTooltip(ItemStack stack, List<String> currentTip, - GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) { - for (PositionedStack pStack : neiCachedRecipe.mInputs) { - if (stack == pStack.item) { - if (pStack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { - currentTip = handleNEIItemInputTooltip( - currentTip, - (GT_NEI_DefaultHandler.FixedPositionedStack) pStack); - } - break; - } - } - for (PositionedStack pStack : neiCachedRecipe.mOutputs) { - if (stack == pStack.item) { - if (pStack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { - currentTip = handleNEIItemOutputTooltip( - currentTip, - (GT_NEI_DefaultHandler.FixedPositionedStack) pStack); - } - break; - } - } - return currentTip; - } - - protected List<String> handleNEIItemInputTooltip(List<String> currentTip, - GT_NEI_DefaultHandler.FixedPositionedStack pStack) { - if (pStack.isNotConsumed()) { - currentTip.add(GRAY + GT_Utility.trans("151", "Does not get consumed in the process")); - } - return currentTip; - } - - protected List<String> handleNEIItemOutputTooltip(List<String> currentTip, - GT_NEI_DefaultHandler.FixedPositionedStack pStack) { - if (pStack.isChanceBased()) { - currentTip.add(GRAY + GT_Utility.trans("150", "Chance: ") + pStack.getChanceText()); - } - return currentTip; - } - - public void drawNEIOverlays(GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) { - for (PositionedStack stack : neiCachedRecipe.mInputs) { - if (stack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { - drawNEIOverlayForInput((GT_NEI_DefaultHandler.FixedPositionedStack) stack); - } - } - for (PositionedStack stack : neiCachedRecipe.mOutputs) { - if (stack instanceof GT_NEI_DefaultHandler.FixedPositionedStack) { - drawNEIOverlayForOutput((GT_NEI_DefaultHandler.FixedPositionedStack) stack); - } - } - } - - protected void drawNEIOverlayForInput(GT_NEI_DefaultHandler.FixedPositionedStack stack) { - if (stack.isNotConsumed()) { - drawNEIOverlayText("NC", stack); - } - } - - protected void drawNEIOverlayForOutput(GT_NEI_DefaultHandler.FixedPositionedStack stack) { - if (stack.isChanceBased()) { - drawNEIOverlayText(stack.getChanceText(), stack); - } - } - - @SuppressWarnings("SameParameterValue") - protected void drawNEIOverlayText(String text, PositionedStack stack, int color, float scale, boolean shadow, - Alignment alignment) { - FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; - int width = fontRenderer.getStringWidth(text); - int x = (int) ((stack.relx + 8 + 8 * alignment.x) / scale) - (width / 2 * (alignment.x + 1)); - int y = (int) ((stack.rely + 8 + 8 * alignment.y) / scale) - - (fontRenderer.FONT_HEIGHT / 2 * (alignment.y + 1)) - - (alignment.y - 1) / 2; - - GlStateManager.pushMatrix(); - GlStateManager.scale(scale, scale, 1); - fontRenderer.drawString(text, x, y, color, shadow); - GlStateManager.popMatrix(); - } - - protected void drawNEIOverlayText(String text, PositionedStack stack) { - drawNEIOverlayText( - text, - stack, - colorOverride.getTextColorOrDefault("nei_overlay_yellow", 0xFDD835), - 0.5f, - false, - Alignment.TopLeft); - } - - public void updateNEITextColorOverride() { - neiTextColorOverride = colorOverride.getTextColorOrDefault("nei", -1); - } - - public Power getPowerFromRecipeMap() { - // By default, assume generic EU LV power with no overclocks - Power power; - if (mShowVoltageAmperageInNEI) { - power = new EUPower((byte) 1, mAmperage); - } else { - power = new UnspecifiedEUPower((byte) 1, mAmperage); - } - return power; - } - - /** - * Use {@link #getItemInputPositions} or {@link #getSpecialItemPosition} or {@link #getFluidInputPositions} - * instead - */ - @Deprecated - public ArrayList<PositionedStack> getInputPositionedStacks(GT_Recipe recipe) { - return null; - } - - /** - * Use {@link #getItemOutputPositions} or {@link #getFluidOutputPositions} instead - */ - @Deprecated - public ArrayList<PositionedStack> getOutputPositionedStacks(GT_Recipe recipe) { - return null; - } - - public void addRecipe(Object o, FluidStack[] fluidInputArray, FluidStack[] fluidOutputArray) {} - } - - // ----------------------------------------------------------------------------------------------------------------- - // Here are a few Classes I use for Special Cases in some Machines without having to write a separate Machine Class. - // ----------------------------------------------------------------------------------------------------------------- - - /** - * Nicely display NEI with many items and fluids. Remember to call {@link GT_Recipe_Map#setUsualFluidInputCount} and - * {@link GT_Recipe_Map#setUsualFluidOutputCount}. If row count >= 6, it doesn't fit in 2 recipes per page, so - * change it via IMC. - */ - public static class GT_Recipe_Map_LargeNEI extends GT_Recipe_Map { - - private static final int xDirMaxCount = 3; - private static final int yOrigin = 8; - - public GT_Recipe_Map_LargeNEI(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - useModularUI(true); - setLogoPos(80, 62); - } - - @Override - public List<Pos2d> getItemInputPositions(int itemInputCount) { - return UIHelper.getGridPositions(itemInputCount, 16, yOrigin, xDirMaxCount); - } - - @Override - public List<Pos2d> getItemOutputPositions(int itemOutputCount) { - return UIHelper.getGridPositions(itemOutputCount, 106, yOrigin, xDirMaxCount); - } - - @Override - public List<Pos2d> getFluidInputPositions(int fluidInputCount) { - return UIHelper.getGridPositions(fluidInputCount, 16, yOrigin + getItemRowCount() * 18, xDirMaxCount); - } - - @Override - public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { - return UIHelper.getGridPositions(fluidOutputCount, 106, yOrigin + getItemRowCount() * 18, xDirMaxCount); - } - - @Override - public ModularWindow.Builder createNEITemplate(IItemHandlerModifiable itemInputsInventory, - IItemHandlerModifiable itemOutputsInventory, IItemHandlerModifiable specialSlotInventory, - IItemHandlerModifiable fluidInputsInventory, IItemHandlerModifiable fluidOutputsInventory, - Supplier<Float> progressSupplier, Pos2d windowOffset) { - // Delay setter so that calls to #setUsualFluidInputCount and #setUsualFluidOutputCount are considered - setNEIBackgroundSize(172, 82 + (Math.max(getItemRowCount() + getFluidRowCount() - 4, 0)) * 18); - return super.createNEITemplate( - itemInputsInventory, - itemOutputsInventory, - specialSlotInventory, - fluidInputsInventory, - fluidOutputsInventory, - progressSupplier, - windowOffset); - } - - private int getItemRowCount() { - return (Math.max(mUsualInputCount, mUsualOutputCount) - 1) / xDirMaxCount + 1; - } - - private int getFluidRowCount() { - return (Math.max(getUsualFluidInputCount(), getUsualFluidOutputCount()) - 1) / xDirMaxCount + 1; - } - } - - /** - * Display fluids where normally items are placed on NEI. - */ - public static class GT_Recipe_Map_FluidOnly extends GT_Recipe_Map { - - public GT_Recipe_Map_FluidOnly(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - useModularUI(true); - } - - @Override - public List<Pos2d> getFluidInputPositions(int fluidInputCount) { - return UIHelper.getItemInputPositions(fluidInputCount); - } - - @Override - public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { - return UIHelper.getItemOutputPositions(fluidOutputCount); - } - } - - /** - * Abstract Class for general Recipe Handling of non GT Recipes - */ - public abstract static class GT_Recipe_Map_NonGTRecipes extends GT_Recipe_Map { - - public GT_Recipe_Map_NonGTRecipes(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Override - public boolean containsInput(ItemStack aStack) { - return false; - } - - @Override - public boolean containsInput(FluidStack aFluid) { - return false; - } - - @Override - public boolean containsInput(Fluid aFluid) { - return false; - } - - @Override - public GT_Recipe addRecipe(boolean aOptimize, ItemStack[] aInputs, ItemStack[] aOutputs, Object aSpecial, - int[] aOutputChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue) { - return null; - } - - @Override - public GT_Recipe addRecipe(boolean aOptimize, ItemStack[] aInputs, ItemStack[] aOutputs, Object aSpecial, - FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, int aSpecialValue) { - return null; - } - - @Override - public GT_Recipe addRecipe(GT_Recipe aRecipe) { - return null; - } - - @Override - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, int[] aOutputChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, - int aEUt, int aSpecialValue) { - return null; - } - - @Override - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue) { - return null; - } - - @Override - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue, boolean hidden) { - return null; - } - - @Override - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, GT_Recipe aRecipe) { - return null; - } - - @Override - public GT_Recipe add(GT_Recipe aRecipe) { - return null; - } - - @Override - public void reInit() { - /**/ - } - - @Override - protected GT_Recipe addToItemMap(GT_Recipe aRecipe) { - return null; - } - } - - /** - * Just a Recipe Map with Utility specifically for Fuels. - */ - public static class GT_Recipe_Map_Fuel extends GT_Recipe_Map { - - private final Map<String, GT_Recipe> mRecipesByFluidInput = new HashMap<>(); - - public GT_Recipe_Map_Fuel(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - setDisableOptimize(true); - } - - public GT_Recipe addFuel(ItemStack aInput, ItemStack aOutput, int aFuelValueInEU) { - return addFuel(aInput, aOutput, null, null, 10000, aFuelValueInEU); - } - - public GT_Recipe addFuel(ItemStack aInput, ItemStack aOutput, int aChance, int aFuelValueInEU) { - return addFuel(aInput, aOutput, null, null, aChance, aFuelValueInEU); - } - - public GT_Recipe addFuel(FluidStack aFluidInput, FluidStack aFluidOutput, int aFuelValueInEU) { - return addFuel(null, null, aFluidInput, aFluidOutput, 10000, aFuelValueInEU); - } - - public GT_Recipe addFuel(ItemStack aInput, ItemStack aOutput, FluidStack aFluidInput, FluidStack aFluidOutput, - int aFuelValueInEU) { - return addFuel(aInput, aOutput, aFluidInput, aFluidOutput, 10000, aFuelValueInEU); - } - - public GT_Recipe addFuel(ItemStack aInput, ItemStack aOutput, FluidStack aFluidInput, FluidStack aFluidOutput, - int aChance, int aFuelValueInEU) { - return addRecipe( - true, - new ItemStack[] { aInput }, - new ItemStack[] { aOutput }, - null, - new int[] { aChance }, - new FluidStack[] { aFluidInput }, - new FluidStack[] { aFluidOutput }, - 0, - 0, - aFuelValueInEU); - } - - @Override - public GT_Recipe add(GT_Recipe aRecipe) { - aRecipe = super.add(aRecipe); - if (aRecipe.mInputs != null && GT_Utility.getNonnullElementCount(aRecipe.mInputs) == 1 - && (aRecipe.mFluidInputs == null || GT_Utility.getNonnullElementCount(aRecipe.mFluidInputs) == 0)) { - FluidStack tFluid = GT_Utility.getFluidForFilledItem(aRecipe.mInputs[0], true); - if (tFluid != null) { - tFluid.amount = 0; - mRecipesByFluidInput.put(tFluid.getUnlocalizedName(), aRecipe); - } - } else if ((aRecipe.mInputs == null || GT_Utility.getNonnullElementCount(aRecipe.mInputs) == 0) - && aRecipe.mFluidInputs != null - && GT_Utility.getNonnullElementCount(aRecipe.mFluidInputs) == 1 - && aRecipe.mFluidInputs[0] != null) { - mRecipesByFluidInput.put(aRecipe.mFluidInputs[0].getUnlocalizedName(), aRecipe); - } - return aRecipe; - } - - public GT_Recipe findFuel(FluidStack aFluidInput) { - return mRecipesByFluidInput.get(aFluidInput.getUnlocalizedName()); - } - } - - /** - * Special Class for Furnace Recipe handling. - */ - public static class GT_Recipe_Map_Furnace extends GT_Recipe_Map_NonGTRecipes { - - public GT_Recipe_Map_Furnace(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return NOT_FOUND; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) - return FindRecipeResult.ofSuccess(aRecipe); - ItemStack tOutput = GT_ModHandler.getSmeltingOutput(aInputs[0], false, null); - return tOutput == null ? NOT_FOUND - : FindRecipeResult.ofSuccess( - new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - null, - null, - 128, - 4, - 0)); - } - - @Override - public boolean containsInput(ItemStack aStack) { - return GT_ModHandler.getSmeltingOutput(aStack, false, null) != null; - } - } - - /** - * Special Class for Microwave Recipe handling. - */ - public static class GT_Recipe_Map_Microwave extends GT_Recipe_Map_NonGTRecipes { - - public GT_Recipe_Map_Microwave(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return NOT_FOUND; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) - return FindRecipeResult.ofSuccess(aRecipe); - ItemStack tOutput = GT_ModHandler.getSmeltingOutput(aInputs[0], false, null); - - if (GT_Utility.areStacksEqual(aInputs[0], new ItemStack(Items.book, 1, W))) { - return FindRecipeResult.ofSuccess( - new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { - GT_Utility.getWrittenBook("Manual_Microwave", ItemList.Book_Written_03.get(1)) }, - null, - null, - null, - null, - 32, - 4, - 0)); - } - - // Check Container Item of Input since it is around the Input, then the Input itself, then Container Item of - // Output and last check the Output itself - for (ItemStack tStack : new ItemStack[] { GT_Utility.getContainerItem(aInputs[0], true), aInputs[0], - GT_Utility.getContainerItem(tOutput, true), tOutput }) if (tStack != null) { - if (GT_Utility.areStacksEqual(tStack, new ItemStack(Blocks.netherrack, 1, W), true) - || GT_Utility.areStacksEqual(tStack, new ItemStack(Blocks.tnt, 1, W), true) - || GT_Utility.areStacksEqual(tStack, new ItemStack(Items.egg, 1, W), true) - || GT_Utility.areStacksEqual(tStack, new ItemStack(Items.firework_charge, 1, W), true) - || GT_Utility.areStacksEqual(tStack, new ItemStack(Items.fireworks, 1, W), true) - || GT_Utility.areStacksEqual(tStack, new ItemStack(Items.fire_charge, 1, W), true)) { - GT_Log.exp.println( - "Microwave Explosion due to TNT || EGG || FIREWORKCHARGE || FIREWORK || FIRE CHARGE"); - return EXPLODE; - } - ItemData tData = GT_OreDictUnificator.getItemData(tStack); - - if (tData != null) { - if (tData.mMaterial != null && tData.mMaterial.mMaterial != null) { - if (tData.mMaterial.mMaterial.contains(SubTag.METAL) - || tData.mMaterial.mMaterial.contains(SubTag.EXPLOSIVE)) { - GT_Log.exp.println("Microwave Explosion due to METAL insertion"); - return EXPLODE; - } - if (tData.mMaterial.mMaterial.contains(SubTag.FLAMMABLE)) { - GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); - return ON_FIRE; - } - } - for (MaterialStack tMaterial : tData.mByProducts) if (tMaterial != null) { - if (tMaterial.mMaterial.contains(SubTag.METAL) - || tMaterial.mMaterial.contains(SubTag.EXPLOSIVE)) { - GT_Log.exp.println("Microwave Explosion due to METAL insertion"); - return EXPLODE; - } - if (tMaterial.mMaterial.contains(SubTag.FLAMMABLE)) { - GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); - return ON_FIRE; - } - } - } - if (TileEntityFurnace.getItemBurnTime(tStack) > 0) { - GT_Log.exp.println("Microwave INFLAMMATION due to BURNABLE insertion"); - return ON_FIRE; - } - } - - return tOutput == null ? NOT_FOUND - : FindRecipeResult.ofSuccess( - new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - null, - null, - 32, - 4, - 0)); - } - - @Override - public boolean containsInput(ItemStack aStack) { - return GT_ModHandler.getSmeltingOutput(aStack, false, null) != null; - } - } - - /** - * Special Class for Unboxinator handling. - */ - public static class GT_Recipe_Map_Unboxinator extends GT_Recipe_Map { - - public GT_Recipe_Map_Unboxinator(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || !ItemList.IC2_Scrapbox.isStackEqual(aInputs[0], false, true)) - return super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - ItemStack tOutput = GT_ModHandler.getRandomScrapboxDrop(); - if (tOutput == null) return super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - GT_Recipe rRecipe = new GT_Recipe( - false, - new ItemStack[] { ItemList.IC2_Scrapbox.get(1) }, - new ItemStack[] { tOutput }, - null, - null, - null, - null, - 16, - 1, - 0); - // It is not allowed to be buffered due to the random Output - rRecipe.mCanBeBuffered = false; - // Due to its randomness it is not good if there are Items in the Output Slot, because those Items could - // manipulate the outcome. - rRecipe.mNeedsEmptyOutput = true; - return FindRecipeResult.ofSuccess(rRecipe); - } - - @Override - public boolean containsInput(ItemStack aStack) { - return ItemList.IC2_Scrapbox.isStackEqual(aStack, false, true) || super.containsInput(aStack); - } - } - - /** - * Special Class for Fluid Canner handling. - */ - public static class GT_Recipe_Map_FluidCanner extends GT_Recipe_Map { - - public GT_Recipe_Map_FluidCanner(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - FindRecipeResult result = super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - if (aInputs == null || aInputs.length == 0 - || aInputs[0] == null - || result.isSuccessful() - || !GregTech_API.sPostloadFinished) return result; - - if (aFluids != null && aFluids.length > 0 && aFluids[0] != null) { - ItemStack tOutput = GT_Utility.fillFluidContainer(aFluids[0], aInputs[0], false, true); - FluidStack tFluid = GT_Utility.getFluidForFilledItem(tOutput, true); - if (tFluid != null) { - GT_Recipe recipe = new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - new FluidStack[] { tFluid }, - null, - Math.max(tFluid.amount / 64, 16), - 1, - 0); - recipe.mCanBeBuffered = false; - return FindRecipeResult.ofSuccess(recipe); - } - } - FluidStack tFluid = GT_Utility.getFluidForFilledItem(aInputs[0], true); - if (tFluid != null) { - GT_Recipe recipe = new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { GT_Utility.getContainerItem(aInputs[0], true) }, - null, - null, - null, - new FluidStack[] { tFluid }, - Math.max(tFluid.amount / 64, 16), - 1, - 0); - recipe.mCanBeBuffered = false; - return FindRecipeResult.ofSuccess(recipe); - } - return NOT_FOUND; - } - - @Override - public boolean containsInput(ItemStack aStack) { - return aStack != null && (super.containsInput(aStack) || (aStack.getItem() instanceof IFluidContainerItem - && ((IFluidContainerItem) aStack.getItem()).getCapacity(aStack) > 0)); - } - - @Override - public boolean containsInput(FluidStack aFluid) { - return true; - } - - @Override - public boolean containsInput(Fluid aFluid) { - return true; - } - } - - /** - * Special Class for Recycler Recipe handling. - */ - public static class GT_Recipe_Map_Recycler extends GT_Recipe_Map_NonGTRecipes { - - public GT_Recipe_Map_Recycler(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return NOT_FOUND; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) - return FindRecipeResult.ofSuccess(aRecipe); - return FindRecipeResult.ofSuccess( - new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { GT_ModHandler.getRecyclerOutput(aInputs[0], 0) }, - null, - new int[] { 1250 }, - null, - null, - 45, - 1, - 0)); - } - - @Override - public boolean containsInput(ItemStack aStack) { - return GT_ModHandler.getRecyclerOutput(aStack, 0) != null; - } - } - - /** - * Special Class for Macerator/RockCrusher Recipe handling. - */ - public static class GT_Recipe_Map_Macerator extends GT_Recipe_Map { - - public GT_Recipe_Map_Macerator(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null || !GregTech_API.sPostloadFinished) - return super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - FindRecipeResult result = super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - if (result.isSuccessful()) return result; - - try { - List<ItemStack> tRecipeOutputs = mods.railcraft.api.crafting.RailcraftCraftingManager.rockCrusher - .getRecipe(GT_Utility.copyAmount(1, aInputs[0])) - .getRandomizedOuputs(); - if (tRecipeOutputs != null) { - GT_Recipe recipe = new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - tRecipeOutputs.toArray(new ItemStack[0]), - null, - null, - null, - null, - 800, - 2, - 0); - recipe.mCanBeBuffered = false; - recipe.mNeedsEmptyOutput = true; - return FindRecipeResult.ofSuccess(recipe); - } - } catch (NoClassDefFoundError e) { - if (D1) GT_Log.err.println("Railcraft Not loaded"); - } catch (NullPointerException e) { - /**/ - } - - ItemStack tComparedInput = GT_Utility.copyOrNull(aInputs[0]); - ItemStack[] tOutputItems = GT_ModHandler.getMachineOutput( - tComparedInput, - ic2.api.recipe.Recipes.macerator.getRecipes(), - true, - new NBTTagCompound(), - null, - null, - null); - if (tComparedInput != null && GT_Utility.arrayContainsNonNull(tOutputItems)) { - return FindRecipeResult.ofSuccess( - new GT_Recipe( - false, - new ItemStack[] { - GT_Utility.copyAmount(aInputs[0].stackSize - tComparedInput.stackSize, aInputs[0]) }, - tOutputItems, - null, - null, - null, - null, - 400, - 2, - 0)); - } - return NOT_FOUND; - } - - @Override - public boolean containsInput(ItemStack aStack) { - return super.containsInput(aStack) || GT_Utility.arrayContainsNonNull( - GT_ModHandler.getMachineOutput( - GT_Utility.copyAmount(64, aStack), - ic2.api.recipe.Recipes.macerator.getRecipes(), - false, - new NBTTagCompound(), - null, - null, - null)); - } - } - - /** - * Special Class for Assembler handling. - */ - public static class GT_Recipe_Map_Assembler extends GT_Recipe_Map { - - public GT_Recipe_Map_Assembler(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - - FindRecipeResult result = super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - true, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - /* - * Doesnt work, keep it as a reminder tho if (rRecipe == null){ Set<ItemStack> aInputs2 = new - * TreeSet<ItemStack>(); for (ItemStack aInput : aInputs) { aInputs2.add(aInput); } for (ItemStack aInput : - * aInputs) { aInputs2.remove(aInput); int[] oredictIDs = OreDictionary.getOreIDs(aInput); if ( - * oredictIDs.length > 1){ for (final int i : oredictIDs){ final ItemStack[] oredictIS = (ItemStack[]) - * OreDictionary.getOres(OreDictionary.getOreName(i)).toArray(); if (oredictIS != null && oredictIS.length > - * 1){ for (final ItemStack IS : oredictIS){ aInputs2.add(IS); ItemStack[] temp = (ItemStack[]) - * aInputs2.toArray(); rRecipe = super.findRecipe(aTileEntity, aRecipe, aNotUnificated, aVoltage, aFluids, - * aSpecialSlot,temp); if(rRecipe!= null){ break; } else { aInputs2.remove(IS); } } if(rRecipe!= null) - * break; } } if(rRecipe!= null) break; }else aInputs2.add(aInput); if(rRecipe!= null) break; } } - */ - if (aInputs == null || aInputs.length == 0 - || aInputs[0] == null - || !result.isSuccessful() - || !GregTech_API.sPostloadFinished) return result; - - GT_Recipe rRecipe = result.getRecipeNonNull(); - for (ItemStack aInput : aInputs) { - if (ItemList.Paper_Printed_Pages.isStackEqual(aInput, false, true)) { - rRecipe = rRecipe.copy(); - rRecipe.mCanBeBuffered = false; - rRecipe.mOutputs[0].setTagCompound(aInput.getTagCompound()); - } - } - return FindRecipeResult.ofSuccess(rRecipe); - } - } - - /** - * Special Class for Forming Press handling. - */ - public static class GT_Recipe_Map_FormingPress extends GT_Recipe_Map { - - public GT_Recipe_Map_FormingPress(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - FindRecipeResult result = super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - if (aInputs == null || aInputs.length < 2 || !GregTech_API.sPostloadFinished) return result; - if (!result.isSuccessful()) { - return findRenamingRecipe(aInputs); - } - for (ItemStack aMold : aInputs) { - if (ItemList.Shape_Mold_Credit.isStackEqual(aMold, false, true)) { - NBTTagCompound tNBT = aMold.getTagCompound(); - if (tNBT == null) tNBT = new NBTTagCompound(); - if (!tNBT.hasKey("credit_security_id")) tNBT.setLong("credit_security_id", System.nanoTime()); - aMold.setTagCompound(tNBT); - - GT_Recipe rRecipe = result.getRecipeNonNull(); - rRecipe = rRecipe.copy(); - rRecipe.mCanBeBuffered = false; - rRecipe.mOutputs[0].setTagCompound(tNBT); - return FindRecipeResult.ofSuccess(rRecipe); - } - } - return result; - } - - private ItemStack findNameMoldIndex(ItemStack[] inputs) { - for (ItemStack stack : inputs) { - if (ItemList.Shape_Mold_Name.isStackEqual(stack, false, true)) return stack; - } - return null; - } - - private ItemStack findStackToRename(ItemStack[] inputs, ItemStack mold) { - for (ItemStack stack : inputs) { - if (stack == mold || stack == null) continue; - return stack; - } - return null; - } - - @Nonnull - private FindRecipeResult findRenamingRecipe(ItemStack[] inputs) { - ItemStack mold = findNameMoldIndex(inputs); - if (mold == null) return NOT_FOUND; - ItemStack input = findStackToRename(inputs, mold); - if (input == null) return NOT_FOUND; - ItemStack output = GT_Utility.copyAmount(1, input); - if (output == null) return NOT_FOUND; - output.setStackDisplayName(mold.getDisplayName()); - GT_Recipe recipe = new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(0, mold), GT_Utility.copyAmount(1, input) }, - new ItemStack[] { output }, - null, - null, - null, - null, - 128, - 8, - 0); - recipe.mCanBeBuffered = false; - recipe.isNBTSensitive = true; - return FindRecipeResult.ofSuccess(recipe); - } - } - - /** - * Special Class for Printer handling. - */ - public static class GT_Recipe_Map_Printer extends GT_Recipe_Map { - - public GT_Recipe_Map_Printer(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Nonnull - @Override - public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, Predicate<GT_Recipe> aIsValidRecipe, - boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, - ItemStack aSpecialSlot, ItemStack... aInputs) { - FindRecipeResult result = super.findRecipeWithResult( - aRecipe, - aIsValidRecipe, - aNotUnificated, - aDontCheckStackSizes, - aVoltage, - aFluids, - aSpecialSlot, - aInputs); - if (aInputs == null || aInputs.length == 0 - || aInputs[0] == null - || aFluids == null - || aFluids.length == 0 - || aFluids[0] == null - || !GregTech_API.sPostloadFinished) return result; - - Dyes aDye = null; - for (Dyes tDye : Dyes.VALUES) if (tDye.isFluidDye(aFluids[0])) { - aDye = tDye; - break; - } - - if (aDye == null) return result; - - if (!result.isSuccessful()) { - ItemStack tOutput = GT_ModHandler.getAllRecipeOutput( - null, - aInputs[0], - aInputs[0], - aInputs[0], - aInputs[0], - ItemList.DYE_ONLY_ITEMS[aDye.mIndex].get(1), - aInputs[0], - aInputs[0], - aInputs[0], - aInputs[0]); - if (tOutput != null) { - GT_Recipe recipe = addRecipe( - new GT_Recipe( - true, - new ItemStack[] { GT_Utility.copyAmount(8, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - new FluidStack[] { new FluidStack(aFluids[0].getFluid(), (int) L) }, - null, - 256, - 2, - 0), - false, - false, - true); - return recipe != null ? FindRecipeResult.ofSuccess(recipe) : NOT_FOUND; - } - - tOutput = GT_ModHandler - .getAllRecipeOutput(null, aInputs[0], ItemList.DYE_ONLY_ITEMS[aDye.mIndex].get(1)); - if (tOutput != null) { - GT_Recipe recipe = addRecipe( - new GT_Recipe( - true, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - new FluidStack[] { new FluidStack(aFluids[0].getFluid(), (int) L) }, - null, - 32, - 2, - 0), - false, - false, - true); - return recipe != null ? FindRecipeResult.ofSuccess(recipe) : NOT_FOUND; - } - } else { - GT_Recipe rRecipe = result.getRecipeNonNull(); - if (aInputs[0].getItem() == Items.paper) { - if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return NOT_FOUND; - NBTTagCompound tNBT = aSpecialSlot.getTagCompound(); - if (tNBT == null || GT_Utility.isStringInvalid(tNBT.getString("title")) - || GT_Utility.isStringInvalid(tNBT.getString("author"))) return NOT_FOUND; - - rRecipe = rRecipe.copy(); - rRecipe.mCanBeBuffered = false; - rRecipe.mOutputs[0].setTagCompound(tNBT); - return FindRecipeResult.ofSuccess(rRecipe); - } - if (aInputs[0].getItem() == Items.map) { - if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return NOT_FOUND; - NBTTagCompound tNBT = aSpecialSlot.getTagCompound(); - if (tNBT == null || !tNBT.hasKey("map_id")) return NOT_FOUND; - - rRecipe = rRecipe.copy(); - rRecipe.mCanBeBuffered = false; - rRecipe.mOutputs[0].setItemDamage(tNBT.getShort("map_id")); - return FindRecipeResult.ofSuccess(rRecipe); - } - if (ItemList.Paper_Punch_Card_Empty.isStackEqual(aInputs[0], false, true)) { - if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return NOT_FOUND; - NBTTagCompound tNBT = aSpecialSlot.getTagCompound(); - if (tNBT == null || !tNBT.hasKey("GT.PunchCardData")) return NOT_FOUND; - - rRecipe = rRecipe.copy(); - rRecipe.mCanBeBuffered = false; - rRecipe.mOutputs[0].setTagCompound( - GT_Utility.getNBTContainingString( - new NBTTagCompound(), - "GT.PunchCardData", - tNBT.getString("GT.PunchCardData"))); - return FindRecipeResult.ofSuccess(rRecipe); - } - } - return result; - } - - @Override - public boolean containsInput(ItemStack aStack) { - return true; - } - - @Override - public boolean containsInput(FluidStack aFluid) { - return super.containsInput(aFluid) || Dyes.isAnyFluidDye(aFluid); - } - - @Override - public boolean containsInput(Fluid aFluid) { - return super.containsInput(aFluid) || Dyes.isAnyFluidDye(aFluid); - } - } - - public static class GT_Recipe_Map_LargeBoilerFakeFuels extends GT_Recipe_Map { - - private static final List<String> ALLOWED_SOLID_FUELS = Arrays.asList( - GregTech_API.sMachineFile.mConfig.getStringList( - "LargeBoiler.allowedFuels", - ConfigCategories.machineconfig.toString(), - new String[] { "gregtech:gt.blockreinforced:6", "gregtech:gt.blockreinforced:7" }, - "Allowed fuels for the Large Titanium Boiler and Large Tungstensteel Boiler")); - - public GT_Recipe_Map_LargeBoilerFakeFuels() { - super( - new HashSet<>(55), - "gt.recipe.largeboilerfakefuels", - "Large Boiler", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true); - GT_Recipe explanatoryRecipe = new GT_Recipe( - true, - new ItemStack[] {}, - new ItemStack[] {}, - null, - null, - null, - null, - 1, - 1, - 1); - explanatoryRecipe.setNeiDesc( - "Not all solid fuels are listed.", - "Any item that burns in a", - "vanilla furnace will burn in", - "a Large Bronze or Steel Boiler."); - addRecipe(explanatoryRecipe); - } - - public static boolean isAllowedSolidFuel(ItemStack stack) { - return isAllowedSolidFuel(Item.itemRegistry.getNameForObject(stack.getItem()), stack.getItemDamage()); - } - - public static boolean isAllowedSolidFuel(String itemRegistryName, int meta) { - return ALLOWED_SOLID_FUELS.contains(itemRegistryName + ":" + meta); - } - - public static boolean addAllowedSolidFuel(ItemStack stack) { - return addAllowedSolidFuel(Item.itemRegistry.getNameForObject(stack.getItem()), stack.getItemDamage()); - } - - public static boolean addAllowedSolidFuel(String itemregistryName, int meta) { - return ALLOWED_SOLID_FUELS.add(itemregistryName + ":" + meta); - } - - public GT_Recipe addDenseLiquidRecipe(GT_Recipe recipe) { - return addRecipe(recipe, ((double) recipe.mSpecialValue) / 10); - } - - public GT_Recipe addDieselRecipe(GT_Recipe recipe) { - return addRecipe(recipe, ((double) recipe.mSpecialValue) / 40); - } - - public void addSolidRecipes(ItemStack... itemStacks) { - for (ItemStack itemStack : itemStacks) { - addSolidRecipe(itemStack); - } - } - - public GT_Recipe addSolidRecipe(ItemStack fuelItemStack) { - boolean allowedFuel = false; - if (fuelItemStack != null) { - String registryName = Item.itemRegistry.getNameForObject(fuelItemStack.getItem()); - allowedFuel = ALLOWED_SOLID_FUELS.contains(registryName + ":" + fuelItemStack.getItemDamage()); - } - return addRecipe( - new GT_Recipe( - true, - new ItemStack[] { fuelItemStack }, - new ItemStack[] {}, - null, - null, - null, - null, - 1, - 0, - GT_ModHandler.getFuelValue(fuelItemStack) / 1600), - ((double) GT_ModHandler.getFuelValue(fuelItemStack)) / 1600, - allowedFuel); - } - - private GT_Recipe addRecipe(GT_Recipe recipe, double baseBurnTime, boolean isAllowedFuel) { - recipe = new GT_Recipe(recipe, true); - // Some recipes will have a burn time like 15.9999999 and % always rounds down - double floatErrorCorrection = 0.0001; - - double bronzeBurnTime = baseBurnTime * 2 + floatErrorCorrection; - bronzeBurnTime -= bronzeBurnTime % 0.05; - double steelBurnTime = baseBurnTime + floatErrorCorrection; - steelBurnTime -= steelBurnTime % 0.05; - double titaniumBurnTime = baseBurnTime * 0.3 + floatErrorCorrection; - titaniumBurnTime -= titaniumBurnTime % 0.05; - double tungstensteelBurnTime = baseBurnTime * 0.15 + floatErrorCorrection; - tungstensteelBurnTime -= tungstensteelBurnTime % 0.05; - - if (isAllowedFuel) { - recipe.setNeiDesc( - "Burn time in seconds:", - String.format("Bronze Boiler: %.4f", bronzeBurnTime), - String.format("Steel Boiler: %.4f", steelBurnTime), - String.format("Titanium Boiler: %.4f", titaniumBurnTime), - String.format("Tungstensteel Boiler: %.4f", tungstensteelBurnTime)); - } else { - recipe.setNeiDesc( - "Burn time in seconds:", - String.format("Bronze Boiler: %.4f", bronzeBurnTime), - String.format("Steel Boiler: %.4f", steelBurnTime), - "Titanium Boiler: Not allowed", - "Tungstenst. Boiler: Not allowed"); - } - - return super.addRecipe(recipe); - } - - private GT_Recipe addRecipe(GT_Recipe recipe, double baseBurnTime) { - recipe = new GT_Recipe(recipe, true); - // Some recipes will have a burn time like 15.9999999 and % always rounds down - double floatErrorCorrection = 0.0001; - - double bronzeBurnTime = baseBurnTime * 2 + floatErrorCorrection; - bronzeBurnTime -= bronzeBurnTime % 0.05; - double steelBurnTime = baseBurnTime + floatErrorCorrection; - steelBurnTime -= steelBurnTime % 0.05; - - recipe.setNeiDesc( - "Burn time in seconds:", - String.format("Bronze Boiler: %.4f", bronzeBurnTime), - String.format("Steel Boiler: %.4f", steelBurnTime), - "Titanium Boiler: Not allowed", - "Tungstenst. Boiler: Not allowed"); - - return super.addRecipe(recipe); - } - } - - public static class GT_Recipe_Map_IC2NuclearFake extends GT_Recipe_Map { - - public GT_Recipe_Map_IC2NuclearFake() { - super( - new HashSet<>(10), - "gt.recipe.ic2nuke", - "Fission", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "Default"), - 1, - 1, - 1, - 0, - 1, - E, - 1, - E, - true, - true); - setLogo(GT_UITextures.PICTURE_RADIATION_WARNING); - setLogoPos(152, 24); - setNEIBackgroundSize(172, 60); - setProgressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT); - } - - /** - * Add a breeder cell. - * - * @param input raw stack. should be undamaged. - * @param output breed output - * @param heatMultiplier bonus progress per neutron pulse per heat step - * @param heatStep divisor for hull heat - * @param reflector true if also acts as a neutron reflector, false otherwise. - * @param requiredPulses progress required to complete breeding - * @return added fake recipe - */ - public GT_Recipe addBreederCell(ItemStack input, ItemStack output, boolean reflector, int heatStep, - int heatMultiplier, int requiredPulses) { - return addFakeRecipe( - input, - output, - reflector ? "Neutron reflecting breeder cell" : "Heat neutral Breeder Cell", - String.format("Every %d reactor hull heat", heatStep), - String.format("increase speed by %d00%%", heatMultiplier), - String.format("Required pulses: %d", requiredPulses)); - } - - public GT_Recipe addFakeRecipe(ItemStack input, ItemStack output, String... neiDesc) { - GT_Recipe r = new GT_Recipe( - new ItemStack[] { input }, - new ItemStack[] { output }, - null, - new int[] { 10000 }, - null, - null, - 0, - 0, - 0); - r.setNeiDesc(neiDesc); - return addRecipe(r, true, true, false); - } - } - - public static class GT_Recipe_Map_LargeChemicalReactor extends GT_Recipe_Map_LargeNEI { - - private static final int TOTAL_INPUT_COUNT = 6; - private static final int OUTPUT_COUNT = 6; - - public GT_Recipe_Map_LargeChemicalReactor() { - super( - new HashSet<>(1000), - "gt.recipe.largechemicalreactor", - "Large Chemical Reactor", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "LCRNEI"), - TOTAL_INPUT_COUNT, - OUTPUT_COUNT, - 0, - 0, - 1, - E, - 1, - E, - true, - true); - } - - @Override - public GT_Recipe addRecipe(boolean aOptimize, ItemStack[] aInputs, ItemStack[] aOutputs, Object aSpecial, - int[] aOutputChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue) { - aOptimize = false; - ArrayList<ItemStack> adjustedInputs = new ArrayList<>(); - ArrayList<ItemStack> adjustedOutputs = new ArrayList<>(); - ArrayList<FluidStack> adjustedFluidInputs = new ArrayList<>(); - ArrayList<FluidStack> adjustedFluidOutputs = new ArrayList<>(); - - if (aInputs == null) { - aInputs = new ItemStack[0]; - } else { - aInputs = ArrayExt.withoutTrailingNulls(aInputs, ItemStack[]::new); - } - - for (ItemStack input : aInputs) { - FluidStack inputFluidContent = FluidContainerRegistry.getFluidForFilledItem(input); - if (inputFluidContent != null) { - inputFluidContent.amount *= input.stackSize; - if (inputFluidContent.getFluid() - .getName() - .equals("ic2steam")) { - inputFluidContent = GT_ModHandler.getSteam(inputFluidContent.amount); - } - adjustedFluidInputs.add(inputFluidContent); - } else { - ItemData itemData = GT_OreDictUnificator.getItemData(input); - if (itemData != null && itemData.hasValidPrefixMaterialData() - && itemData.mMaterial.mMaterial == Materials.Empty) { - continue; - } else { - if (itemData != null && itemData.hasValidPrefixMaterialData() - && itemData.mPrefix == OrePrefixes.cell) { - ItemStack dustStack = itemData.mMaterial.mMaterial.getDust(input.stackSize); - if (dustStack != null) { - adjustedInputs.add(dustStack); - } else { - adjustedInputs.add(input); - } - } else { - adjustedInputs.add(input); - } - } - } - - if (aFluidInputs == null) { - aFluidInputs = new FluidStack[0]; - } - } - Collections.addAll(adjustedFluidInputs, aFluidInputs); - aInputs = adjustedInputs.toArray(new ItemStack[0]); - aFluidInputs = adjustedFluidInputs.toArray(new FluidStack[0]); - - if (aOutputs == null) { - aOutputs = new ItemStack[0]; - } else { - aOutputs = ArrayExt.withoutTrailingNulls(aOutputs, ItemStack[]::new); - } - - for (ItemStack output : aOutputs) { - FluidStack outputFluidContent = FluidContainerRegistry.getFluidForFilledItem(output); - if (outputFluidContent != null) { - outputFluidContent.amount *= output.stackSize; - if (outputFluidContent.getFluid() - .getName() - .equals("ic2steam")) { - outputFluidContent = GT_ModHandler.getSteam(outputFluidContent.amount); - } - adjustedFluidOutputs.add(outputFluidContent); - } else { - ItemData itemData = GT_OreDictUnificator.getItemData(output); - if (!(itemData != null && itemData.hasValidPrefixMaterialData() - && itemData.mMaterial.mMaterial == Materials.Empty)) { - adjustedOutputs.add(output); - } - } - } - if (aFluidOutputs == null) { - aFluidOutputs = new FluidStack[0]; - } - Collections.addAll(adjustedFluidOutputs, aFluidOutputs); - aOutputs = adjustedOutputs.toArray(new ItemStack[0]); - aFluidOutputs = adjustedFluidOutputs.toArray(new FluidStack[0]); - - return super.addRecipe( - aOptimize, - aInputs, - aOutputs, - aSpecial, - aOutputChances, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue); - } - } - - public static class GT_Recipe_Map_DistillationTower extends GT_Recipe_Map { - - public GT_Recipe_Map_DistillationTower() { - super( - new HashSet<>(110), - "gt.recipe.distillationtower", - "Distillation Tower", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "DistillationTower"), - 2, - 1, - 0, - 0, - 1, - E, - 1, - E, - true, - true); - setLogoPos(80, 62); - } - - @Override - public IDrawable getOverlayForSlot(boolean isFluid, boolean isOutput, int index, boolean isSpecial) { - if (isOutput) { - if (isFluid) { - return GT_UITextures.OVERLAY_SLOTS_NUMBER[index + 1]; - } else { - return GT_UITextures.OVERLAY_SLOTS_NUMBER[0]; - } - } - return super.getOverlayForSlot(isFluid, false, index, isSpecial); - } - - @Override - public List<Pos2d> getItemOutputPositions(int itemOutputCount) { - return Collections.singletonList(new Pos2d(106, 62)); - } - - @Override - public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { - List<Pos2d> results = new ArrayList<>(); - for (int i = 1; i < fluidOutputCount + 1; i++) { - results.add(new Pos2d(106 + (i % 3) * 18, 62 - (i / 3) * 18)); - } - return results; - } - } - - public static class GT_Recipe_Map_OilCracker extends GT_Recipe_Map { - - private final Set<String> mValidCatalystFluidNames = new HashSet<>(); - - public GT_Recipe_Map_OilCracker() { - super( - new HashSet<>(70), - "gt.recipe.craker", - "Oil Cracker", - null, - GregTech.getResourcePath(TEXTURES_GUI_BASICMACHINES, "OilCracker"), - 1, - 1, - 1, - 2, - 1, - E, - 1, - E, - true, - true); - } - - @Override - public GT_Recipe add(GT_Recipe aRecipe) { - GT_Recipe ret = super.add(aRecipe); - if (ret != null && ret.mFluidInputs != null && ret.mFluidInputs.length > 1 && ret.mFluidInputs[1] != null) { - mValidCatalystFluidNames.add( - ret.mFluidInputs[1].getFluid() - .getName()); - } - return ret; - } - - public boolean isValidCatalystFluid(FluidStack aFluidStack) { - return mValidCatalystFluidNames.contains( - aFluidStack.getFluid() - .getName()); - } - } - public static class GT_Recipe_WithAlt extends GT_Recipe { ItemStack[][] mOreDictAlt; + /** + * Only for {@link GT_RecipeBuilder}. + */ GT_Recipe_WithAlt(ItemStack[] mInputs, ItemStack[] mOutputs, FluidStack[] mFluidInputs, FluidStack[] mFluidOutputs, int[] mChances, Object mSpecialItems, int mDuration, int mEUt, int mSpecialValue, boolean mEnabled, boolean mHidden, boolean mFakeRecipe, boolean mCanBeBuffered, - boolean mNeedsEmptyOutput, String[] neiDesc, ItemStack[][] mOreDictAlt) { + boolean mNeedsEmptyOutput, boolean nbtSensitive, String[] neiDesc, + @Nullable IRecipeMetadataStorage metadataStorage, RecipeCategory recipeCategory, + ItemStack[][] mOreDictAlt) { super( mInputs, mOutputs, @@ -6299,7 +938,10 @@ public class GT_Recipe implements Comparable<GT_Recipe> { mFakeRecipe, mCanBeBuffered, mNeedsEmptyOutput, - neiDesc); + nbtSensitive, + neiDesc, + metadataStorage, + recipeCategory); this.mOreDictAlt = mOreDictAlt; } @@ -6335,191 +977,4 @@ public class GT_Recipe implements Comparable<GT_Recipe> { return GT_Utility.copyOrNull(mInputs[aIndex]); } } - - private static class ReplicatorFakeMap extends GT_Recipe_Map { - - public ReplicatorFakeMap(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Override - public GT_Recipe addFakeRecipe(boolean aCheckForCollisions, ItemStack[] aInputs, ItemStack[] aOutputs, - Object aSpecial, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, int aDuration, int aEUt, - int aSpecialValue) { - AtomicInteger ai = new AtomicInteger(); - Optional.ofNullable(GT_OreDictUnificator.getAssociation(aOutputs[0])) - .map(itemData -> itemData.mMaterial) - .map(materialsStack -> materialsStack.mMaterial) - .map(materials -> materials.mElement) - .map(Element::getMass) - .ifPresent(e -> { - aFluidInputs[0].amount = (int) GT_MetaTileEntity_Replicator.cubicFluidMultiplier(e); - ai.set(GT_Utility.safeInt(aFluidInputs[0].amount * 512L, 1)); - }); - return addFakeRecipe( - aCheckForCollisions, - new GT_Recipe( - false, - aInputs, - aOutputs, - aSpecial, - null, - aFluidInputs, - aFluidOutputs, - ai.get(), - aEUt, - aSpecialValue)); - } - } - - public static class GT_Recipe_Map_ComplexFusion extends GT_Recipe_Map { - - public GT_Recipe_Map_ComplexFusion(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, - String aLocalName, String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, - int aMinimalInputItems, int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, - int aNEISpecialValueMultiplier, String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, - boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Override - public GT_Recipe addRecipe(int[] aOutputChances, FluidStack[] aFluidInputs, FluidStack[] aFluidOutputs, - int aDuration, int aEUt, int aSpecialValue) { - return addRecipe( - new GT_Recipe( - false, - null, - null, - null, - aOutputChances, - aFluidInputs, - aFluidOutputs, - aDuration, - aEUt, - aSpecialValue), - false, - false, - false); - } - - @Override - public List<Pos2d> getFluidInputPositions(int fluidInputCount) { - return UIHelper.getGridPositions(fluidInputCount, 7, 9, 4); - } - - @Override - public List<Pos2d> getFluidOutputPositions(int fluidOutputCount) { - return UIHelper.getGridPositions(fluidOutputCount, 97, 9, 4); - } - } - - public static class GT_Recipe_Map_AssemblyLineFake extends GT_Recipe_Map { - - public GT_Recipe_Map_AssemblyLineFake(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, - String aLocalName, String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, - int aMinimalInputItems, int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, - int aNEISpecialValueMultiplier, String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, - boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - setNEITransferRect(new Rectangle(146, 26, 10, 18)); - } - - @Override - public List<Pos2d> getItemInputPositions(int itemInputCount) { - return UIHelper.getGridPositions(itemInputCount, 16, 8, 4); - } - - @Override - public List<Pos2d> getItemOutputPositions(int itemOutputCount) { - return Collections.singletonList(new Pos2d(142, 8)); - } - - @Override - public Pos2d getSpecialItemPosition() { - return new Pos2d(142, 44); - } - - @Override - public List<Pos2d> getFluidInputPositions(int fluidInputCount) { - return UIHelper.getGridPositions(fluidInputCount, 106, 8, 1); - } - - @Override - public void addProgressBarUI(ModularWindow.Builder builder, Supplier<Float> progressSupplier, - Pos2d windowOffset) { - int bar1Width = 17; - int bar2Width = 18; - builder.widget( - new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_1, 17) - .setDirection(ProgressBar.Direction.RIGHT) - .setProgress(() -> progressSupplier.get() * ((float) (bar1Width + bar2Width) / bar1Width)) - .setSynced(false, false) - .setPos(new Pos2d(88, 8).add(windowOffset)) - .setSize(bar1Width, 72)); - builder.widget( - new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_2, 18) - .setDirection(ProgressBar.Direction.RIGHT) - .setProgress( - () -> (progressSupplier.get() - ((float) bar1Width / (bar1Width + bar2Width))) - * ((float) (bar1Width + bar2Width) / bar2Width)) - .setSynced(false, false) - .setPos(new Pos2d(124, 8).add(windowOffset)) - .setSize(bar2Width, 72)); - builder.widget( - new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_3, 18) - .setDirection(ProgressBar.Direction.UP) - .setProgress(progressSupplier) - .setSynced(false, false) - .setPos(new Pos2d(146, 26).add(windowOffset)) - .setSize(10, 18)); - } - } } diff --git a/src/main/java/gregtech/api/util/GT_RecipeBuilder.java b/src/main/java/gregtech/api/util/GT_RecipeBuilder.java index 3fa8d91da0..271ea28d87 100644 --- a/src/main/java/gregtech/api/util/GT_RecipeBuilder.java +++ b/src/main/java/gregtech/api/util/GT_RecipeBuilder.java @@ -1,30 +1,34 @@ package gregtech.api.util; +import static gregtech.api.util.GT_RecipeMapUtil.SPECIAL_VALUE_ALIASES; import static gregtech.api.util.GT_Utility.copyFluidArray; import static gregtech.api.util.GT_Utility.copyItemArray; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.minecraft.item.ItemStack; import net.minecraft.launchwrapper.Launch; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.Contract; + import gregtech.GT_Mod; -import gregtech.api.interfaces.IGT_RecipeMap; +import gregtech.api.interfaces.IRecipeMap; +import gregtech.api.recipe.RecipeCategory; +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.recipe.metadata.IRecipeMetadataStorage; +import gregtech.api.recipe.metadata.RecipeMetadataStorage; import gregtech.api.util.extensions.ArrayExt; -@SuppressWarnings("unused") +@SuppressWarnings({ "unused", "UnusedReturnValue" }) public class GT_RecipeBuilder { // debug mode expose problems. panic mode help you check nothing is wrong-ish without you actively monitoring @@ -86,9 +90,13 @@ public class GT_RecipeBuilder { protected boolean fakeRecipe = false; protected boolean mCanBeBuffered = true; protected boolean mNeedsEmptyOutput = false; + protected boolean nbtSensitive = false; protected String[] neiDesc; + protected RecipeCategory recipeCategory; protected boolean optimize = true; - protected Map<MetadataIdentifier<?>, Object> additionalData = new HashMap<>(); + @Nullable + protected IRecipeMetadataStorage metadataStorage; + protected boolean checkForCollision = true; protected boolean valid = true; GT_RecipeBuilder() {} @@ -96,8 +104,8 @@ public class GT_RecipeBuilder { private GT_RecipeBuilder(ItemStack[] inputsBasic, Object[] inputsOreDict, ItemStack[] outputs, ItemStack[][] alts, FluidStack[] fluidInputs, FluidStack[] fluidOutputs, int[] chances, Object special, int duration, int eut, int specialValue, boolean enabled, boolean hidden, boolean fakeRecipe, boolean mCanBeBuffered, - boolean mNeedsEmptyOutput, String[] neiDesc, boolean optimize, - Map<MetadataIdentifier<?>, Object> additionalData, boolean valid) { + boolean mNeedsEmptyOutput, boolean nbtSensitive, String[] neiDesc, RecipeCategory recipeCategory, + boolean optimize, @Nullable IRecipeMetadataStorage metadataStorage, boolean checkForCollision, boolean valid) { this.inputsBasic = inputsBasic; this.inputsOreDict = inputsOreDict; this.outputs = outputs; @@ -114,9 +122,15 @@ public class GT_RecipeBuilder { this.fakeRecipe = fakeRecipe; this.mCanBeBuffered = mCanBeBuffered; this.mNeedsEmptyOutput = mNeedsEmptyOutput; + this.nbtSensitive = nbtSensitive; this.neiDesc = neiDesc; + this.recipeCategory = recipeCategory; this.optimize = optimize; - this.additionalData.putAll(additionalData); + this.metadataStorage = metadataStorage; + if (this.metadataStorage != null) { + this.metadataStorage = this.metadataStorage.copy(); + } + this.checkForCollision = checkForCollision; this.valid = valid; } @@ -137,6 +151,14 @@ public class GT_RecipeBuilder { return new GT_RecipeBuilder(); } + /** + * Creates empty builder where only duration and EU/t are set to 0. + */ + public static GT_RecipeBuilder empty() { + return new GT_RecipeBuilder().duration(0) + .eut(0); + } + private static boolean containsNull(Object[] arr) { return arr == null || Arrays.stream(arr) .anyMatch(Objects::isNull); @@ -156,7 +178,7 @@ public class GT_RecipeBuilder { return DEBUG_MODE_NULL || PANIC_MODE_NULL; } - private static void handleInvalidRecipe() { + public static void handleInvalidRecipe() { if (!DEBUG_MODE_INVALID && !PANIC_MODE_INVALID) { return; } @@ -247,14 +269,6 @@ public class GT_RecipeBuilder { return noOptimize(); } - /** - * @deprecated You don't need to call this method, RecipeBuilder now takes empty item input array by default. - */ - @Deprecated - public GT_RecipeBuilder noItemInputs() { - return this; - } - public GT_RecipeBuilder itemOutputs(ItemStack... outputs) { if (debugNull() && containsNull(outputs)) handleNullRecipeComponents("itemOutputs"); this.outputs = outputs; @@ -278,50 +292,18 @@ public class GT_RecipeBuilder { return this; } - /** - * @deprecated You don't need to call this method, RecipeBuilder now takes empty item output array by default. - */ - @Deprecated - public GT_RecipeBuilder noItemOutputs() { - return this; - } - public GT_RecipeBuilder fluidInputs(FluidStack... fluidInputs) { if (debugNull() && containsNull(fluidInputs)) handleNullRecipeComponents("fluidInputs"); this.fluidInputs = fix(fluidInputs); return this; } - /** - * @deprecated You don't need to call this method, RecipeBuilder now takes empty fluid input array by default. - */ - @Deprecated - public GT_RecipeBuilder noFluidInputs() { - return this; - } - public GT_RecipeBuilder fluidOutputs(FluidStack... fluidOutputs) { if (debugNull() && containsNull(fluidOutputs)) handleNullRecipeComponents("fluidOutputs"); this.fluidOutputs = fix(fluidOutputs); return this; } - /** - * @deprecated You don't need to call this method, RecipeBuilder now takes empty fluid output array by default. - */ - @Deprecated - public GT_RecipeBuilder noFluidOutputs() { - return this; - } - - /** - * @deprecated You don't need to call this method, RecipeBuilder now takes empty arrays by default. - */ - @Deprecated - public GT_RecipeBuilder noOutputs() { - return this; - } - public GT_RecipeBuilder outputChances(int... chances) { if (outputs != null && chances.length != outputs.length) { throw new IllegalArgumentException("Output chances array and items array length differs"); @@ -398,11 +380,21 @@ public class GT_RecipeBuilder { return this; } + public GT_RecipeBuilder nbtSensitive() { + this.nbtSensitive = true; + return this; + } + public GT_RecipeBuilder setNEIDesc(String... neiDesc) { this.neiDesc = neiDesc; return this; } + public GT_RecipeBuilder recipeCategory(RecipeCategory recipeCategory) { + this.recipeCategory = recipeCategory; + return this; + } + /** * Prevent the resulting recipe from optimizing recipe, which is a process that reduce recipe batch size. */ @@ -411,17 +403,51 @@ public class GT_RecipeBuilder { return this; } - public <T> GT_RecipeBuilder metadata(MetadataIdentifier<T> key, T value) { - additionalData.put(key, value); + /** + * Prevents checking collision with existing recipes when adding the built recipe. + */ + public GT_RecipeBuilder ignoreCollision() { + this.checkForCollision = false; return this; } - public <T> T getMetadata(MetadataIdentifier<T> key) { - return key.cast(additionalData.get(key)); + /** + * Sets metadata of the recipe. It can be used for recipe emitter to do special things, or for being stored in the + * built recipe and used for actual recipe processing. + * <p> + * {@link GT_RecipeConstants} has a series of metadata keys. Or you can create one by yourself. + */ + public <T> GT_RecipeBuilder metadata(RecipeMetadataKey<T> key, T value) { + if (metadataStorage == null) { + metadataStorage = new RecipeMetadataStorage(); + } + metadataStorage.store(key, value); + return this; + } + + /** + * Gets metadata already set for this builder. Can return null. Use + * {@link #getMetadataOrDefault(RecipeMetadataKey, Object)} + * if you want to specify default value. + */ + @Nullable + public <T> T getMetadata(RecipeMetadataKey<T> key) { + if (metadataStorage == null) { + return null; + } + return key.cast(metadataStorage.getMetadata(key)); } - public <T> T getMetadata(MetadataIdentifier<T> key, T defaultValue) { - return key.cast(additionalData.getOrDefault(key, defaultValue)); + /** + * Gets metadata already set for this builder with default value. Does not return null unless default value is null. + */ + @Contract("_, !null -> !null") + @Nullable + public <T> T getMetadataOrDefault(RecipeMetadataKey<T> key, T defaultValue) { + if (metadataStorage == null) { + return defaultValue; + } + return key.cast(metadataStorage.getMetadataOrDefault(key, defaultValue)); } public GT_RecipeBuilder requiresCleanRoom() { @@ -466,9 +492,12 @@ public class GT_RecipeBuilder { fakeRecipe, mCanBeBuffered, mNeedsEmptyOutput, + nbtSensitive, copy(neiDesc), + recipeCategory, optimize, - additionalData, + metadataStorage, + checkForCollision, valid); } @@ -493,9 +522,12 @@ public class GT_RecipeBuilder { fakeRecipe, mCanBeBuffered, mNeedsEmptyOutput, + nbtSensitive, copy(neiDesc), + recipeCategory, optimize, - Collections.emptyMap(), + null, + checkForCollision, valid); } @@ -553,6 +585,18 @@ public class GT_RecipeBuilder { return eut; } + public RecipeCategory getRecipeCategory() { + return recipeCategory; + } + + public boolean isOptimize() { + return optimize; + } + + public boolean isCheckForCollision() { + return checkForCollision; + } + // endregion // region validator @@ -581,7 +625,7 @@ public class GT_RecipeBuilder { /** * Validate if input item match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateNoInput() { return GT_Utility.isArrayEmptyOrNull(inputsBasic) ? this : invalidate(); @@ -589,7 +633,7 @@ public class GT_RecipeBuilder { /** * Validate if input fluid match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateNoInputFluid() { return GT_Utility.isArrayEmptyOrNull(fluidInputs) ? this : invalidate(); @@ -597,7 +641,7 @@ public class GT_RecipeBuilder { /** * Validate if output item match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateNoOutput() { return GT_Utility.isArrayEmptyOrNull(outputs) ? this : invalidate(); @@ -605,7 +649,7 @@ public class GT_RecipeBuilder { /** * Validate if output fluid match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateNoOutputFluid() { return GT_Utility.isArrayEmptyOrNull(fluidOutputs) ? this : invalidate(); @@ -613,7 +657,7 @@ public class GT_RecipeBuilder { /** * Validate if input item match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateInputCount(int min, int max) { if (inputsBasic == null) return min < 0 ? this : invalidate(); @@ -622,7 +666,7 @@ public class GT_RecipeBuilder { /** * Validate if input fluid match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateInputFluidCount(int min, int max) { if (fluidInputs == null) return min < 0 ? this : invalidate(); @@ -631,7 +675,7 @@ public class GT_RecipeBuilder { /** * Validate if output item match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateOutputCount(int min, int max) { if (outputs == null) return min < 0 ? this : invalidate(); @@ -640,7 +684,7 @@ public class GT_RecipeBuilder { /** * Validate if output fluid match requirement. Return as invalidated if fails prereq. Specify -1 as min to allow - * unset. Both bound inclusive. Only supposed to be called by IGT_RecipeMap and not client code. + * unset. Both bound inclusive. Only supposed to be called by IRecipeMap and not client code. */ public GT_RecipeBuilder validateOutputFluidCount(int min, int max) { if (fluidOutputs == null) return min < 0 ? this : invalidate(); @@ -669,6 +713,12 @@ public class GT_RecipeBuilder { // endregion + /** + * Builds new recipe, without custom behavior of recipemaps. For adding recipe to recipemap, + * use {@link #addTo} instead. + * + * @return Built recipe. Returns empty if failed to build. + */ public Optional<GT_Recipe> build() { if (!valid) { handleInvalidRecipe(); @@ -693,7 +743,10 @@ public class GT_RecipeBuilder { fakeRecipe, mCanBeBuffered, mNeedsEmptyOutput, - neiDesc))); + nbtSensitive, + neiDesc, + metadataStorage, + recipeCategory))); } public GT_RecipeBuilder forceOreDictInput() { @@ -728,7 +781,10 @@ public class GT_RecipeBuilder { fakeRecipe, mCanBeBuffered, mNeedsEmptyOutput, + nbtSensitive, neiDesc, + metadataStorage, + recipeCategory, alts))); } @@ -769,18 +825,36 @@ public class GT_RecipeBuilder { r.mHidden = hidden; r.mCanBeBuffered = mCanBeBuffered; r.mNeedsEmptyOutput = mNeedsEmptyOutput; + r.isNBTSensitive = nbtSensitive; r.mFakeRecipe = fakeRecipe; r.mEnabled = enabled; if (neiDesc != null) r.setNeiDesc(neiDesc); + applyDefaultSpecialValues(r); return r; } - public Collection<GT_Recipe> addTo(IGT_RecipeMap recipeMap) { + private void applyDefaultSpecialValues(GT_Recipe recipe) { + if (recipe.mSpecialValue != 0) return; + + int specialValue = 0; + if (getMetadataOrDefault(GT_RecipeConstants.LOW_GRAVITY, false)) specialValue -= 100; + if (getMetadataOrDefault(GT_RecipeConstants.CLEANROOM, false)) specialValue -= 200; + for (RecipeMetadataKey<Integer> ident : SPECIAL_VALUE_ALIASES) { + Integer metadata = getMetadataOrDefault(ident, null); + if (metadata != null) { + specialValue = metadata; + break; + } + } + recipe.mSpecialValue = specialValue; + } + + public Collection<GT_Recipe> addTo(IRecipeMap recipeMap) { return recipeMap.doAdd(this); } public GT_RecipeBuilder reset() { - additionalData.clear(); + metadataStorage = null; alts = null; chances = null; duration = -1; @@ -794,7 +868,9 @@ public class GT_RecipeBuilder { inputsOreDict = null; mCanBeBuffered = true; mNeedsEmptyOutput = false; + nbtSensitive = false; neiDesc = null; + recipeCategory = null; optimize = true; outputs = null; special = null; @@ -802,45 +878,4 @@ public class GT_RecipeBuilder { valid = true; return this; } - - public final static class MetadataIdentifier<T> { - - private static final Map<MetadataIdentifier<?>, MetadataIdentifier<?>> allIdentifiers = Collections - .synchronizedMap(new HashMap<>()); - private final Class<T> clazz; - private final String identifier; - - private MetadataIdentifier(Class<T> clazz, String identifier) { - this.clazz = clazz; - this.identifier = identifier; - } - - public static <T> MetadataIdentifier<T> create(Class<T> clazz, String identifier) { - MetadataIdentifier<T> key = new MetadataIdentifier<>(clazz, identifier); - // noinspection unchecked // The class uses type T to fill allIdentifiers - return (MetadataIdentifier<T>) allIdentifiers.computeIfAbsent(key, Function.identity()); - } - - public T cast(Object o) { - return clazz.cast(o); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - MetadataIdentifier<?> that = (MetadataIdentifier<?>) o; - - if (!clazz.equals(that.clazz)) return false; - return identifier.equals(that.identifier); - } - - @Override - public int hashCode() { - int result = clazz.hashCode(); - result = 31 * result + identifier.hashCode(); - return result; - } - } } diff --git a/src/main/java/gregtech/api/util/GT_RecipeConstants.java b/src/main/java/gregtech/api/util/GT_RecipeConstants.java index 2b92615c5f..8e728030f2 100644 --- a/src/main/java/gregtech/api/util/GT_RecipeConstants.java +++ b/src/main/java/gregtech/api/util/GT_RecipeConstants.java @@ -17,8 +17,11 @@ import cpw.mods.fml.common.registry.GameRegistry; import gregtech.api.GregTech_API; import gregtech.api.enums.ItemList; import gregtech.api.enums.Materials; -import gregtech.api.interfaces.IGT_RecipeMap; -import gregtech.api.util.GT_Recipe.GT_Recipe_Map; +import gregtech.api.interfaces.IRecipeMap; +import gregtech.api.recipe.RecipeCategories; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.recipe.metadata.SimpleRecipeMetadataKey; // this class is intended to be import-static-ed on every recipe script // so take care to not put unrelated stuff here! @@ -28,72 +31,77 @@ public class GT_RecipeConstants { * 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 GT_RecipeBuilder.MetadataIdentifier<Boolean> LOW_GRAVITY = GT_RecipeBuilder.MetadataIdentifier + 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 GT_RecipeBuilder.MetadataIdentifier<Boolean> CLEANROOM = GT_RecipeBuilder.MetadataIdentifier + 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 GT_RecipeBuilder.MetadataIdentifier<Integer> ADDITIVE_AMOUNT = GT_RecipeBuilder.MetadataIdentifier + public static final RecipeMetadataKey<Integer> ADDITIVE_AMOUNT = SimpleRecipeMetadataKey .create(Integer.class, "additives"); /** * Used for fusion reactor. Denotes ignition threshold. */ - public static final GT_RecipeBuilder.MetadataIdentifier<Integer> FUSION_THRESHOLD = GT_RecipeBuilder.MetadataIdentifier + public static final RecipeMetadataKey<Integer> FUSION_THRESHOLD = SimpleRecipeMetadataKey .create(Integer.class, "fusion_threshold"); /** * Research time in a scanner used in ticks. */ - public static final GT_RecipeBuilder.MetadataIdentifier<Integer> RESEARCH_TIME = GT_RecipeBuilder.MetadataIdentifier + public static final RecipeMetadataKey<Integer> RESEARCH_TIME = SimpleRecipeMetadataKey .create(Integer.class, "research_time"); /** * Fuel type. TODO should we use enum directly? */ - public static final GT_RecipeBuilder.MetadataIdentifier<Integer> FUEL_TYPE = GT_RecipeBuilder.MetadataIdentifier + public static final RecipeMetadataKey<Integer> FUEL_TYPE = SimpleRecipeMetadataKey .create(Integer.class, "fuel_type"); /** * Fuel value. */ - public static final GT_RecipeBuilder.MetadataIdentifier<Integer> FUEL_VALUE = GT_RecipeBuilder.MetadataIdentifier + public static final RecipeMetadataKey<Integer> FUEL_VALUE = SimpleRecipeMetadataKey .create(Integer.class, "fuel_value"); /** - * Fuel value. + * Required heat for heating coil (Kelvin). */ - public static final GT_RecipeBuilder.MetadataIdentifier<Integer> COIL_HEAT = GT_RecipeBuilder.MetadataIdentifier + public static final RecipeMetadataKey<Integer> COIL_HEAT = SimpleRecipeMetadataKey .create(Integer.class, "coil_heat"); /** * Research item used by assline recipes. */ - public static final GT_RecipeBuilder.MetadataIdentifier<ItemStack> RESEARCH_ITEM = GT_RecipeBuilder.MetadataIdentifier + 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 GT_RecipeBuilder.MetadataIdentifier<Object> OREDICT_INPUT = GT_RecipeBuilder.MetadataIdentifier + public static final RecipeMetadataKey<Object> OREDICT_INPUT = SimpleRecipeMetadataKey .create(Object.class, "oredict_input"); - /** - * Add fusion recipes. Dispatcher between complex fusion (which accepts arbitrarily many input/outputs) and classic - * fusion (2 in 1 out). + * Replicator output material. */ - public static final IGT_RecipeMap Fusion = IGT_RecipeMap.newRecipeMap(builder -> { - if (GT_Utility.isArrayEmptyOrNull(builder.getFluidInputs()) - || GT_Utility.isArrayEmptyOrNull(builder.getFluidOutputs())) return Collections.emptyList(); - if (builder.getFluidInputs().length > 2 || builder.getFluidOutputs().length > 2) - return GT_Recipe_Map.sComplexFusionRecipes.doAdd(builder); - return GT_Recipe_Map.sFusionRecipes.doAdd(builder); - }); + 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"); /** * 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 IGT_RecipeMap UniversalArcFurnace = IGT_RecipeMap.newRecipeMap(builder -> { + public static final IRecipeMap UniversalArcFurnace = IRecipeMap.newRecipeMap(builder -> { if (!GT_Utility.isArrayOfLength(builder.getItemInputsBasic(), 1) || GT_Utility.isArrayEmptyOrNull(builder.getItemOutputs())) return Collections.emptyList(); int aDuration = builder.getDuration(); @@ -101,39 +109,45 @@ public class GT_RecipeConstants { return Collections.emptyList(); } builder.duration(aDuration); + boolean recycle = builder.getMetadataOrDefault(RECYCLE, false); Collection<GT_Recipe> ret = new ArrayList<>(); for (Materials mat : new Materials[] { Materials.Argon, Materials.Nitrogen }) { int tPlasmaAmount = (int) Math.max(1L, aDuration / (mat.getMass() * 16L)); - GT_RecipeBuilder b2 = builder.copy(); - b2.fluidInputs(mat.getPlasma(tPlasmaAmount)) + GT_RecipeBuilder plasmaBuilder = builder.copy() + .fluidInputs(mat.getPlasma(tPlasmaAmount)) .fluidOutputs(mat.getGas(tPlasmaAmount)); - ret.addAll(GT_Recipe_Map.sPlasmaArcFurnaceRecipes.doAdd(b2)); + if (recycle) { + plasmaBuilder.recipeCategory(RecipeCategories.plasmaArcFurnaceRecycling); + } + ret.addAll(RecipeMaps.plasmaArcFurnaceRecipes.doAdd(plasmaBuilder)); } - ret.addAll( - GT_Recipe_Map.sArcFurnaceRecipes.doAdd( - builder.copy() - .fluidInputs(Materials.Oxygen.getGas(aDuration)))); + GT_RecipeBuilder 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 IGT_RecipeMap UniversalChemical = IGT_RecipeMap.newRecipeMap(builder -> { + 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 (GT_Utility.isAnyIntegratedCircuit(input) && input.getItemDamage() >= 10) { - return builder.addTo(GT_Recipe_Map.sChemicalRecipes); + return builder.addTo(RecipeMaps.chemicalReactorRecipes); } } return GT_Utility.concat( builder.copy() - .addTo(GT_Recipe_Map.sChemicalRecipes), + .addTo(RecipeMaps.chemicalReactorRecipes), convertCellToFluid(builder, false) // LCR does not need cleanroom. .metadata(CLEANROOM, false) - .addTo(GT_Recipe_Map.sMultiblockChemicalRecipes)); + .addTo(RecipeMaps.multiblockChemicalReactorRecipes)); }); /** @@ -141,18 +155,22 @@ public class GT_RecipeConstants { * Uses {@link #RESEARCH_ITEM} metadata as research item, and {@link #RESEARCH_TIME} metadata as research time, unit * in ticks. */ - public static final IGT_RecipeMap AssemblyLine = IGT_RecipeMap.newRecipeMap(builder -> { + public static final IRecipeMap AssemblyLine = IRecipeMap.newRecipeMap(builder -> { Optional<GT_Recipe.GT_Recipe_WithAlt> rr = builder.forceOreDictInput() .validateInputCount(4, 16) .validateOutputCount(1, 1) .validateOutputFluidCount(-1, 0) .validateInputFluidCount(0, 4) .buildWithAlt(); + // noinspection SimplifyOptionalCallChains if (!rr.isPresent()) return Collections.emptyList(); GT_Recipe.GT_Recipe_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++) { @@ -198,13 +216,13 @@ public class GT_RecipeConstants { if (fluidInput == null) continue; tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(fluidInput, true, false); } - int aResearchTime = builder.getMetadata(RESEARCH_TIME); + int aResearchTime = builder.getMetadataOrDefault(RESEARCH_TIME, 0); tPersistentHash = tPersistentHash * 31 + aResearchTime; tPersistentHash = tPersistentHash * 31 + r.mDuration; tPersistentHash = tPersistentHash * 31 + r.mEUt; Collection<GT_Recipe> ret = new ArrayList<>(3); ret.add( - GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe( + RecipeMaps.scannerFakeRecipes.addFakeRecipe( false, new ItemStack[] { aResearchItem }, new ItemStack[] { aOutput }, @@ -216,7 +234,7 @@ public class GT_RecipeConstants { -201)); // means it's scanned ret.add( - GT_Recipe.GT_Recipe_Map.sAssemblylineVisualRecipes.addFakeRecipe( + RecipeMaps.assemblylineVisualRecipes.addFakeRecipe( false, r.mInputs, new ItemStack[] { aOutput }, @@ -248,13 +266,13 @@ public class GT_RecipeConstants { * 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 IGT_RecipeMap AssemblerOD = IGT_RecipeMap.newRecipeMap(builder -> { + public static IRecipeMap AssemblerOD = IRecipeMap.newRecipeMap(builder -> { Collection<GT_Recipe> ret = new ArrayList<>(); for (ItemStack input : GT_OreDictUnificator.getOresImmutable(builder.getMetadata(OREDICT_INPUT))) { ret.addAll( builder.copy() .itemInputs(GT_RecipeMapUtil.appendArray(builder.getItemInputsBasic(), input)) - .addTo(GT_Recipe_Map.sAssemblerRecipes)); + .addTo(RecipeMaps.assemblerRecipes)); } return ret; }); @@ -265,17 +283,18 @@ public class GT_RecipeConstants { * 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 IGT_RecipeMap Fuel = IGT_RecipeMap.newRecipeMap(builder -> { + public static IRecipeMap Fuel = IRecipeMap.newRecipeMap(builder -> { builder.validateInputCount(1, 1) .validateNoInputFluid() .validateOutputCount(-1, 1) .validateNoOutputFluid(); if (!builder.isValid()) return Collections.emptyList(); - int fuelType = builder.getMetadata(FUEL_TYPE); + Integer fuelType = builder.getMetadata(FUEL_TYPE); + if (fuelType == null) return Collections.emptyList(); builder.metadata( FUEL_VALUE, GregTech_API.sRecipeFile - .get("fuel_" + fuelType, builder.getItemInputBasic(0), builder.getMetadata(FUEL_VALUE))); + .get("fuel_" + fuelType, builder.getItemInputBasic(0), builder.getMetadataOrDefault(FUEL_VALUE, 0))); return FuelType.get(fuelType) .getTarget() .doAdd(builder); @@ -284,18 +303,18 @@ public class GT_RecipeConstants { public enum FuelType { // ORDER MATTERS. DO NOT INSERT ELEMENT BETWEEN EXISTING ONES - DieselFuel(GT_Recipe_Map.sDieselFuels), - GasTurbine(GT_Recipe_Map.sTurbineFuels), + DieselFuel(RecipeMaps.dieselFuels), + GasTurbine(RecipeMaps.gasTurbineFuels), // appears unused - HotFuel(GT_Recipe_Map.sHotFuels), - SemiFluid(GT_Recipe_Map.sDenseLiquidFuels), - PlasmaTurbine(GT_Recipe_Map.sPlasmaFuels), - Magic(GT_Recipe_Map.sMagicFuels),; + HotFuel(RecipeMaps.hotFuels), + SemiFluid(RecipeMaps.denseLiquidFuels), + PlasmaTurbine(RecipeMaps.plasmaFuels), + Magic(RecipeMaps.magicFuels),; private static final FuelType[] VALUES = values(); - private final IGT_RecipeMap target; + private final IRecipeMap target; - FuelType(IGT_RecipeMap target) { + FuelType(IRecipeMap target) { this.target = target; } @@ -304,7 +323,7 @@ public class GT_RecipeConstants { return VALUES[fuelType]; } - public IGT_RecipeMap getTarget() { + public IRecipeMap getTarget() { return target; } } diff --git a/src/main/java/gregtech/api/util/GT_RecipeMapUtil.java b/src/main/java/gregtech/api/util/GT_RecipeMapUtil.java index 577f91a170..3e97b56f84 100644 --- a/src/main/java/gregtech/api/util/GT_RecipeMapUtil.java +++ b/src/main/java/gregtech/api/util/GT_RecipeMapUtil.java @@ -26,12 +26,12 @@ import com.google.common.collect.Multimap; import cpw.mods.fml.common.Loader; import gnu.trove.list.TIntList; import gnu.trove.list.array.TIntArrayList; -import gregtech.api.interfaces.IGT_RecipeMap; +import gregtech.api.interfaces.IRecipeMap; +import gregtech.api.recipe.RecipeMetadataKey; /** * Define helpers useful in the creation of recipe maps. */ -// Do not place arbitrary stuff here! These are all statically imported in GT_Recipe.java file. public class GT_RecipeMapUtil { public static final Function<GT_Recipe, GT_Recipe> ALL_FAKE_RECIPE = r -> { @@ -65,10 +65,13 @@ public class GT_RecipeMapUtil { : r.mFluidOutputs[0].getFluid() .getName() : getStackConfigName(r.mOutputs[0]); - private static final Map<String, IGT_RecipeMap> addonRecipeMaps = new HashMap<>(); - private static final Multimap<String, Consumer<IGT_RecipeMap>> delayedActions = ArrayListMultimap.create(); + private static final Map<String, IRecipeMap> addonRecipeMaps = new HashMap<>(); + private static final Multimap<String, Consumer<IRecipeMap>> delayedActions = ArrayListMultimap.create(); - public static final Set<GT_RecipeBuilder.MetadataIdentifier<Integer>> SPECIAL_VALUE_ALIASES = new HashSet<>(); + /** + * Set of metadata that work as alias for special values. + */ + public static final Set<RecipeMetadataKey<Integer>> SPECIAL_VALUE_ALIASES = new HashSet<>(); public static <T> T[] appendArray(T[] arr, T val) { T[] newArr = Arrays.copyOf(arr, arr.length + 1); @@ -143,8 +146,7 @@ public class GT_RecipeMapUtil { * Currently unused, but you are advised to fill them, so that when The Day (tm) comes we don't * end up with a bunch of weird concurrency bugs. */ - public static void registerRecipeMap(String identifier, IGT_RecipeMap recipeMap, - RecipeMapDependency... dependencies) { + public static void registerRecipeMap(String identifier, IRecipeMap recipeMap, RecipeMapDependency... dependencies) { String modId = Loader.instance() .activeModContainer() .getModId(); @@ -152,7 +154,7 @@ public class GT_RecipeMapUtil { "do not register recipe map under the name of gregtech! do it in your own preinit!"); String id = modId + "@" + identifier; addonRecipeMaps.put(id, recipeMap); - for (Consumer<IGT_RecipeMap> action : delayedActions.get(id)) { + for (Consumer<IRecipeMap> action : delayedActions.get(id)) { action.accept(recipeMap); } } @@ -167,9 +169,9 @@ public class GT_RecipeMapUtil { * @param registerAction DO NOT ADD RECIPES TO MAPS OTHER THAN THE ONE PASSED TO YOU. DO NOT DO ANYTHING OTHER THAN * ADDING RECIPES TO THIS R */ - public static void registerRecipesFor(String modid, String identifier, Consumer<IGT_RecipeMap> registerAction) { + public static void registerRecipesFor(String modid, String identifier, Consumer<IRecipeMap> registerAction) { String id = modid + "@" + identifier; - IGT_RecipeMap map = addonRecipeMaps.get(id); + IRecipeMap map = addonRecipeMaps.get(id); if (map == null) delayedActions.put(id, registerAction); else registerAction.accept(map); } @@ -205,10 +207,10 @@ public class GT_RecipeMapUtil { public static final class RecipeMapDependency { - private final IGT_RecipeMap obj; + private final IRecipeMap obj; private final String id; - public RecipeMapDependency(IGT_RecipeMap obj, String id) { + public RecipeMapDependency(IRecipeMap obj, String id) { this.obj = obj; this.id = id; } @@ -217,7 +219,7 @@ public class GT_RecipeMapUtil { return new RecipeMapDependency(null, id); } - public static RecipeMapDependency create(IGT_RecipeMap obj) { + public static RecipeMapDependency create(IRecipeMap obj) { return new RecipeMapDependency(obj, null); } } diff --git a/src/main/java/gregtech/api/util/GT_RecipeRegistrator.java b/src/main/java/gregtech/api/util/GT_RecipeRegistrator.java index c057cf0b2f..560d26c41d 100644 --- a/src/main/java/gregtech/api/util/GT_RecipeRegistrator.java +++ b/src/main/java/gregtech/api/util/GT_RecipeRegistrator.java @@ -19,12 +19,13 @@ import static gregtech.api.enums.Materials.Steel; import static gregtech.api.enums.Materials.Steeleaf; import static gregtech.api.enums.Materials.Thaumium; import static gregtech.api.enums.Materials.Void; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sFluidExtractionRecipes; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sHammerRecipes; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sMaceratorRecipes; -import static gregtech.api.util.GT_Recipe.GT_Recipe_Map.sWiremillRecipes; +import static gregtech.api.recipe.RecipeMaps.fluidExtractionRecipes; +import static gregtech.api.recipe.RecipeMaps.hammerRecipes; +import static gregtech.api.recipe.RecipeMaps.maceratorRecipes; +import static gregtech.api.recipe.RecipeMaps.wiremillRecipes; import static gregtech.api.util.GT_RecipeBuilder.SECONDS; import static gregtech.api.util.GT_RecipeBuilder.TICKS; +import static gregtech.api.util.GT_RecipeConstants.RECYCLE; import static gregtech.api.util.GT_RecipeConstants.UniversalArcFurnace; import static gregtech.api.util.GT_Utility.calculateRecipeEU; @@ -61,6 +62,7 @@ import gregtech.api.enums.SubTag; import gregtech.api.enums.TierEU; import gregtech.api.objects.ItemData; import gregtech.api.objects.MaterialStack; +import gregtech.api.recipe.RecipeCategories; import ic2.api.reactor.IReactorComponent; /** @@ -205,15 +207,6 @@ public class GT_RecipeRegistrator { || aMaterial.mSmeltInto.mStandardMoltenFluid == null || !aMaterial.contains(SubTag.SMELTING_TO_FLUID) || (L * aMaterialAmount) / (M * aStack.stackSize) <= 0) return; - ItemData tData = GT_OreDictUnificator.getItemData(aStack); - boolean tHide = aStack.getUnlocalizedName() - .startsWith("gt.blockmachines") && (GT_Mod.gregtechproxy.mHideRecyclingRecipes); - if (GT_Mod.gregtechproxy.mHideRecyclingRecipes && tData != null - && tData.hasValidPrefixData() - && !(tData.mPrefix == OrePrefixes.dust || tData.mPrefix == OrePrefixes.ingot - || tData.mPrefix == OrePrefixes.block | tData.mPrefix == OrePrefixes.plate)) { - tHide = true; - } ItemStack recipeOutput = aByproduct == null ? null : aByproduct.mMaterial.contains(SubTag.NO_SMELTING) || !aByproduct.mMaterial.contains(SubTag.METAL) @@ -224,22 +217,16 @@ public class GT_RecipeRegistrator { : null : GT_OreDictUnificator.getIngotOrDust(aByproduct.mMaterial.mSmeltInto, aByproduct.mAmount); + GT_RecipeBuilder builder = RA.stdBuilder() + .itemInputs(GT_Utility.copyAmount(1, aStack)); if (recipeOutput != null) { - RA.stdBuilder() - .itemInputs(GT_Utility.copyAmount(1, aStack)) - .itemOutputs(recipeOutput) - .fluidOutputs(aMaterial.mSmeltInto.getMolten((L * aMaterialAmount) / (M * aStack.stackSize))) - .duration((int) Math.max(1, (24 * aMaterialAmount) / M)) - .eut(Math.max(8, (int) Math.sqrt(2 * aMaterial.mSmeltInto.mStandardMoltenFluid.getTemperature()))) - .addTo(sFluidExtractionRecipes); - } else { - RA.stdBuilder() - .itemInputs(GT_Utility.copyAmount(1, aStack)) - .fluidOutputs(aMaterial.mSmeltInto.getMolten((L * aMaterialAmount) / (M * aStack.stackSize))) - .duration((int) Math.max(1, (24 * aMaterialAmount) / M)) - .eut(Math.max(8, (int) Math.sqrt(2 * aMaterial.mSmeltInto.mStandardMoltenFluid.getTemperature()))) - .addTo(sFluidExtractionRecipes); + builder.itemOutputs(recipeOutput); } + builder.fluidOutputs(aMaterial.mSmeltInto.getMolten((L * aMaterialAmount) / (M * aStack.stackSize))) + .duration((int) Math.max(1, (24 * aMaterialAmount) / M)) + .eut(Math.max(8, (int) Math.sqrt(2 * aMaterial.mSmeltInto.mStandardMoltenFluid.getTemperature()))) + .recipeCategory(RecipeCategories.fluidExtractorRecycling) + .addTo(fluidExtractionRecipes); } /** @@ -259,11 +246,10 @@ public class GT_RecipeRegistrator { aMaterialAmount /= aStack.stackSize; - boolean tHide = (aMaterial != Materials.Iron) && (GT_Mod.gregtechproxy.mHideRecyclingRecipes); if (aAllowAlloySmelter) GT_ModHandler.addSmeltingAndAlloySmeltingRecipe( GT_Utility.copyAmount(1, aStack), GT_OreDictUnificator.getIngot(aMaterial.mSmeltInto, aMaterialAmount), - tHide); + false); else GT_ModHandler.addSmeltingRecipe( GT_Utility.copyAmount(1, aStack), GT_OreDictUnificator.getIngot(aMaterial.mSmeltInto, aMaterialAmount)); @@ -285,12 +271,19 @@ public class GT_RecipeRegistrator { aData = new ItemData(aData); if (!aData.hasValidMaterialData()) return; - boolean tIron = false; + boolean isRecycle = true; for (MaterialStack tMaterial : aData.getAllMaterialStacks()) { if (tMaterial.mMaterial == Materials.Iron || tMaterial.mMaterial == Materials.Copper || tMaterial.mMaterial == Materials.WroughtIron - || tMaterial.mMaterial == Materials.AnnealedCopper) tIron = true; + || tMaterial.mMaterial == Materials.AnnealedCopper) { + ItemData stackData = GT_OreDictUnificator.getItemData(aStack); + if (stackData != null + && (stackData.mPrefix == OrePrefixes.ingot || stackData.mPrefix == OrePrefixes.dust)) { + // iron ingot/dust -> wrought iron, copper ingot/dust -> annealed copper + isRecycle = false; + } + } if (tMaterial.mMaterial.contains(SubTag.UNBURNABLE)) { tMaterial.mMaterial = tMaterial.mMaterial.mSmeltInto.mArcSmeltInto; @@ -334,7 +327,6 @@ public class GT_RecipeRegistrator { for (MaterialStack tMaterial : aData.getAllMaterialStacks()) tAmount += tMaterial.mAmount * tMaterial.mMaterial.getMass(); - boolean tHide = !tIron && GT_Mod.gregtechproxy.mHideRecyclingRecipes; ArrayList<ItemStack> outputs = new ArrayList<>(); if (GT_OreDictUnificator.getIngotOrDust(aData.mMaterial) != null) { outputs.add(GT_OreDictUnificator.getIngotOrDust(aData.mMaterial)); @@ -344,18 +336,15 @@ public class GT_RecipeRegistrator { outputs.add(GT_OreDictUnificator.getIngotOrDust(aData.getByProduct(i))); } } - if (outputs.size() != 0) { - ItemStack[] outputsArray = outputs.toArray(new ItemStack[0]); + if (!outputs.isEmpty()) { GT_RecipeBuilder recipeBuilder = GT_Values.RA.stdBuilder(); recipeBuilder.itemInputs(aStack) - .itemOutputs(outputsArray) + .itemOutputs(outputs.toArray(new ItemStack[0])) .fluidInputs(Materials.Oxygen.getGas((int) Math.max(16, tAmount / M))) .duration(((int) Math.max(16, tAmount / M)) * TICKS) - .eut(90); - if (tHide) { - recipeBuilder.hidden(); - } - recipeBuilder.addTo(UniversalArcFurnace); + .eut(90) + .metadata(RECYCLE, isRecycle) + .addTo(UniversalArcFurnace); } } @@ -391,8 +380,6 @@ public class GT_RecipeRegistrator { } { - boolean tHide = (aData.mMaterial.mMaterial != Materials.Iron) - && (GT_Mod.gregtechproxy.mHideRecyclingRecipes); ArrayList<ItemStack> outputs = new ArrayList<>(); if (GT_OreDictUnificator.getDust(aData.mMaterial) != null) { outputs.add(GT_OreDictUnificator.getDust(aData.mMaterial)); @@ -402,18 +389,16 @@ public class GT_RecipeRegistrator { outputs.add(GT_OreDictUnificator.getDust(aData.getByProduct(i))); } } - if (outputs.size() != 0) { + if (!outputs.isEmpty()) { ItemStack[] outputsArray = outputs.toArray(new ItemStack[0]); GT_RecipeBuilder recipeBuilder = GT_Values.RA.stdBuilder(); recipeBuilder.itemInputs(aStack) .itemOutputs(outputsArray) .duration( (aData.mMaterial.mMaterial == Materials.Marble ? 1 : (int) Math.max(16, tAmount / M)) * TICKS) - .eut(4); - if (tHide) { - recipeBuilder.hidden(); - } - recipeBuilder.addTo(sMaceratorRecipes); + .eut(4) + .recipeCategory(RecipeCategories.maceratorRecycling) + .addTo(maceratorRecipes); } } @@ -430,8 +415,8 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.getDust(aData.mMaterial)) .duration(10 * SECONDS) .eut(TierEU.RECIPE_LV) - .addTo(sHammerRecipes); - + .recipeCategory(RecipeCategories.forgeHammerRecycling) + .addTo(hammerRecipes); break; } } @@ -687,7 +672,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt01, aMaterial, multiplier)) .duration(baseDuration * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix1, aMaterial, 2L / multiplier), @@ -695,7 +680,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt02, aMaterial, 1L)) .duration(((int) (baseDuration * 1.5f)) * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix1, aMaterial, 4L / multiplier), @@ -703,7 +688,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt04, aMaterial, 1L)) .duration(baseDuration * 2 * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix1, aMaterial, 8L / multiplier), @@ -711,7 +696,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt08, aMaterial, 1L)) .duration(((int) (baseDuration * 2.5f)) * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix1, aMaterial, 12L / multiplier), @@ -719,7 +704,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt12, aMaterial, 1L)) .duration(baseDuration * 3 * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix1, aMaterial, 16L / multiplier), @@ -727,7 +712,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt16, aMaterial, 1L)) .duration(((int) (baseDuration * 3.5f)) * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); } if (GT_OreDictUnificator.get(prefix2, aMaterial, 1L) != null @@ -737,7 +722,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt01, aMaterial, 2L / multiplier)) .duration(((int) (baseDuration * 0.5f)) * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix2, aMaterial, 4L / multiplier), @@ -745,7 +730,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt02, aMaterial, 1L)) .duration(baseDuration * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix2, aMaterial, 8L / multiplier), @@ -753,7 +738,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt04, aMaterial, 1L)) .duration(((int) (baseDuration * 1.5f)) * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix2, aMaterial, 16L / multiplier), @@ -761,7 +746,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt08, aMaterial, 1L)) .duration(baseDuration * 2 * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix2, aMaterial, 24L / multiplier), @@ -769,7 +754,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt12, aMaterial, 1L)) .duration(((int) (baseDuration * 2.5f)) * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); GT_Values.RA.stdBuilder() .itemInputs( GT_OreDictUnificator.get(prefix2, aMaterial, 32L / multiplier), @@ -777,7 +762,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireGt16, aMaterial, 1L)) .duration(baseDuration * 3 * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); } if (GT_OreDictUnificator.get(prefix1, aMaterial, 1L) != null && GT_OreDictUnificator.get(OrePrefixes.wireFine, aMaterial, 1L) != null) { @@ -786,7 +771,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireFine, aMaterial, 4L * multiplier)) .duration(baseDuration * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); } if (GT_OreDictUnificator.get(prefix2, aMaterial, 1L) != null && GT_OreDictUnificator.get(OrePrefixes.wireFine, aMaterial, 1L) != null) { @@ -795,7 +780,7 @@ public class GT_RecipeRegistrator { .itemOutputs(GT_OreDictUnificator.get(OrePrefixes.wireFine, aMaterial, 2L * multiplier)) .duration(((int) (baseDuration * 0.5f)) * TICKS) .eut(aEUt) - .addTo(sWiremillRecipes); + .addTo(wiremillRecipes); } } diff --git a/src/main/java/gregtech/api/util/GT_StreamUtil.java b/src/main/java/gregtech/api/util/GT_StreamUtil.java new file mode 100644 index 0000000000..c29e611c4e --- /dev/null +++ b/src/main/java/gregtech/api/util/GT_StreamUtil.java @@ -0,0 +1,44 @@ +package gregtech.api.util; + +import java.util.Arrays; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public final class GT_StreamUtil { + + /** + * Backport of {@link Stream#ofNullable}. + */ + public static <T> Stream<T> ofNullable(@Nullable T value) { + return value == null ? Stream.empty() : Stream.of(value); + } + + /** + * Returns a sequential ordered {@code Stream} whose elements are the specified values, + * if {@code condition} is true, otherwise returns an empty {@code Stream}. + * + * @param <T> the type of stream elements + * @param values the elements of the new stream + * @return the new stream + */ + public static <T> Stream<T> ofConditional(boolean condition, T[] values) { + return condition ? Arrays.stream(values) : Stream.empty(); + } + + /** + * Returns a sequential {@code Stream} containing a single element, which will be lazily evaluated from supplier. + * + * @param <T> the type of stream elements + * @param supplier the supplier for single stream element + * @return the new stream + */ + public static <T> Stream<T> ofSupplier(Supplier<T> supplier) { + return Stream.generate(supplier) + .limit(1); + } +} diff --git a/src/main/java/gregtech/api/util/GT_Utility.java b/src/main/java/gregtech/api/util/GT_Utility.java index 755dc0286e..13ce66ddbf 100644 --- a/src/main/java/gregtech/api/util/GT_Utility.java +++ b/src/main/java/gregtech/api/util/GT_Utility.java @@ -115,6 +115,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; +import com.google.common.collect.SetMultimap; import com.gtnewhorizon.structurelib.alignment.IAlignment; import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider; import com.mojang.authlib.GameProfile; @@ -158,6 +159,7 @@ import gregtech.api.objects.CollectorUtils; import gregtech.api.objects.GT_ItemStack; import gregtech.api.objects.GT_ItemStack2; import gregtech.api.objects.ItemData; +import gregtech.api.recipe.RecipeMaps; import gregtech.api.threads.GT_Runnable_Sound; import gregtech.api.util.extensions.ArrayExt; import gregtech.common.GT_Pollution; @@ -500,14 +502,6 @@ public class GT_Utility { } /** - * Do not use. It is rounding up voltage - */ - @Deprecated - public static long roundDownVoltage(long voltage) { - return roundUpVoltage(voltage); - } - - /** * Rounds up partial voltage that exceeds tiered voltage, e.g. 4,096 -> 8,192(IV) */ public static long roundUpVoltage(long voltage) { @@ -3133,6 +3127,20 @@ public class GT_Utility { return aMap; } + /** + * re-maps all Keys of a Map after the Keys were weakened. + */ + public static <X, Y> SetMultimap<X, Y> reMap(SetMultimap<X, Y> aMap) { + @SuppressWarnings("unchecked") + Map.Entry<X, Y>[] entries = aMap.entries() + .toArray(new Map.Entry[0]); + aMap.clear(); + for (Map.Entry<X, Y> entry : entries) { + aMap.put(entry.getKey(), entry.getValue()); + } + return aMap; + } + public static <X, Y extends Comparable<Y>> LinkedHashMap<X, Y> sortMapByValuesAcending(Map<X, Y> map) { return map.entrySet() .stream() @@ -4866,7 +4874,8 @@ public class GT_Utility { public static int getPlasmaFuelValueInEUPerLiterFromFluid(FluidStack aLiquid) { if (aLiquid == null) return 0; - GT_Recipe tFuel = GT_Recipe.GT_Recipe_Map.sPlasmaFuels.findFuel(aLiquid); + GT_Recipe tFuel = RecipeMaps.plasmaFuels.getBackend() + .findFuel(aLiquid); if (tFuel != null) return tFuel.mSpecialValue; return 0; } diff --git a/src/main/java/gregtech/api/util/MethodsReturnNonnullByDefault.java b/src/main/java/gregtech/api/util/MethodsReturnNonnullByDefault.java new file mode 100644 index 0000000000..2b2c310695 --- /dev/null +++ b/src/main/java/gregtech/api/util/MethodsReturnNonnullByDefault.java @@ -0,0 +1,22 @@ +package gregtech.api.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.annotation.Nonnull; +import javax.annotation.meta.TypeQualifierDefault; + +/** + * This annotation can be applied to a package or class to indicate that + * the methods in that element are nonnull by default unless there is: + * <ul> + * <li>An explicit nullness annotation + * <li>The method overrides a method in a superclass (in which case the + * annotation of the corresponding method in the superclass applies) + * </ul> + */ +@Nonnull +@TypeQualifierDefault({ ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface MethodsReturnNonnullByDefault {} diff --git a/src/main/java/gregtech/api/util/VoidProtectionHelper.java b/src/main/java/gregtech/api/util/VoidProtectionHelper.java index 67e412bc83..440d8e63ef 100644 --- a/src/main/java/gregtech/api/util/VoidProtectionHelper.java +++ b/src/main/java/gregtech/api/util/VoidProtectionHelper.java @@ -13,7 +13,6 @@ import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap; import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.interfaces.tileentity.IVoidable; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; /** * Helper class to calculate how many parallels of items / fluids can fit in the output buses / hatches. @@ -52,27 +51,6 @@ public class VoidProtectionHelper { public VoidProtectionHelper() {} /** - * Sets MetaTE controller, with current configuration for void protection mode. - * - * @deprecated Use {@link #setMachine(IVoidable)} - */ - @Deprecated - public VoidProtectionHelper setController(GT_MetaTileEntity_MultiBlockBase machineMeta) { - return setMachine(machineMeta, machineMeta.protectsExcessItem(), machineMeta.protectsExcessFluid()); - } - - /** - * Sets MetaTE controller, with void protection mode forcibly. - * - * @deprecated Use {@link #setMachine(IVoidable, boolean, boolean)} - */ - @Deprecated - public VoidProtectionHelper setController(GT_MetaTileEntity_MultiBlockBase machineMeta, boolean protectExcessItem, - boolean protectExcessFluid) { - return setMachine(machineMeta, protectExcessItem, protectExcessFluid); - } - - /** * Sets machine, with current configuration for void protection mode. */ public VoidProtectionHelper setMachine(IVoidable machine) { |