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/util/GT_RecipeBuilder.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/util/GT_RecipeBuilder.java')
-rw-r--r-- | src/main/java/gregtech/api/util/GT_RecipeBuilder.java | 257 |
1 files changed, 146 insertions, 111 deletions
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; - } - } } |