diff options
author | miozune <miozune@gmail.com> | 2023-12-04 05:34:27 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-03 21:34:27 +0100 |
commit | f74c7cc297d1d19d38a19683cd277ad9ce605d3a (patch) | |
tree | b2a5d66ec5a959099240fb1db239ffc0f9531839 /src/main/java/gregtech/api/recipe/RecipeMap.java | |
parent | b08cde7de4ec93cba05fb070991ad1dffb800ce1 (diff) | |
download | GT5-Unofficial-f74c7cc297d1d19d38a19683cd277ad9ce605d3a.tar.gz GT5-Unofficial-f74c7cc297d1d19d38a19683cd277ad9ce605d3a.tar.bz2 GT5-Unofficial-f74c7cc297d1d19d38a19683cd277ad9ce605d3a.zip |
Refactor RecipeMap (#2345)
* Remove deprecated and unused things
* Move recipemap subclasses
* Move GT_Recipe_Map to outside and rename to RecipeMap
* Move recipemap instances to separated class & remove prepending s
* Remove useless GT_Recipe constructors
* Always use ModularUI
* Rename IGT_RecipeMap -> IRecipeMap
* Add RecipeMapBuilder
* Remove more deprecated and unused things
* Fix RecipeMap type parameters
* Use multimap for recipe index
* Fix bending recipe error in dev env
* Remove mUniqueIdentifier
* Update AE2FC
* Less edgy texture for NEI recipe background
* Add replicator fluid output slot for NEI and machine GUI
* Fix fluid fuels not having fuel value in large boilers
* Remove GT_RectHandler and NEI_TransferRectHost
* Remove RecipeMapHandler
* Move NEI energy description from RecipeMapFrontend to Power
* Refactor the way to filter fusion recipes
* Check restriction for some properties
* Remove showVoltageAmperage
* Make Power accept GT_Recipe
* Fix NPE
* Move NEI duration description to Power from Frontend
* Directly implement IRecipeProcessingAwareHatch for GT_MetaTileEntity_Hatch_InputBus_ME
* Make Power integrated with GT_OverclockCalculator
* Rename Power -> OverclockDescriber
* Don't modify recipe find logic until postload finishes
* Reformat reserved MTE ids
* Fix check for too few inputs on recipe addition
* Move replicator logic to backend
* Stop un-hiding assline recipes
* Allow setting custom recipe comparator & implement for fusion
* Update AE2FC
* Rename getRecipeList and getRecipes -> getRecipeMap
* Automatically register recipe catalysts
* Cleanup the way to detect recipe collision
* Make use of BasicUIProperties for basic machines
* Make use of BasicUIProperties for UIHelper
* Rename specialHandler -> recipeTransformer
* Add way to automatically register handler info
* Add recipe category
* Add some APIs for addons
* Rename blastRecipes ->
blastFurnaceRecipes
* Remove GT_MetaTileEntity_BasicMachine_GT_Recipe#mSharedTank and #mRequiresFluidForFiltering
* Don't require setting duration and EU/t for fuel recipes
* Don't require setting EU/t for primitive blast furnace recipes
* Revert change to addMultiblockChemicalRecipe
* Fix large boiler general desc recipe not being added
* Hide duration and EU/t from large boiler
* Cleanup recipe stacktrace draw
* Extend metadata usage of recipe builder to recipe itself
* Implement metadata handling & NEI comparator for PCB factory
* Some rename around NEIRecipeInfo
* Some toString implementations
* Add more APIs for addons & some rename
* Infer handler icon from recipe catalyst if one is not set
* Also shrink recipe title when OC is not used
* Remove rare earth centrifuge recipe
* Use metadata for replicator backend
* Adjust geothermal generator output slot
* Allow having multiple transferrects
* Store recipemap reference in backend
* Rename vacuumRecipes -> vacuumFreezerRecipes
* Add config to tweak visibility of recipe categories
* Remove mHideRecyclingRecipes in favor of recipe category config
* Fix typo fluidSolidfierRecipes -> fluidSolidifierRecipes
* Refactor findRecipe and ProcessingLogic to use Stream
* Fix BBF handler icon & remove bronze blast furnace
* Add fluent API for findRecipe
* Add way to stop adding progressbar
* Change arg order for special texture
* Avoid overwriting interesting failure with NO_RECIPE
* Some changes for FuelBackend
* Set space project icon
* Remove localization from TT
* Remove CNC recipe adder
* Move recipe extractor from AE2FC
* Minor internal change for ProcessingLogic#applyRecipe
* More javadoc on #getAvailableRecipeMaps
* Better implementation of #ofSupplier
* Move replicator exponent config to GT_Proxy
* Remove RC & IC2 macerator handling
* Rename StreamUtil -> GT_StreamUtil
* Refactor code around RecipeMetadataStorage
* Revise #compileRecipe javadoc
* Switch extreme diesel recipe loader to downstream recipe map
* Optimize #reMap
* Rename reload -> reloadNEICache
* Minor tweak for drawEnergyInfo
* a bit more doc
* Adjust recipe catalysts
* Add toString implementation for GT_Fluid for debug
* Minor revision for OilCrackerBackend
* Index replicator recipes by material
---------
Co-authored-by: Glease <4586901+Glease@users.noreply.github.com>
Diffstat (limited to 'src/main/java/gregtech/api/recipe/RecipeMap.java')
-rw-r--r-- | src/main/java/gregtech/api/recipe/RecipeMap.java | 395 |
1 files changed, 395 insertions, 0 deletions
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)); + } +} |