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 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.GTUITextures; import gregtech.api.gui.modularui.SteamTexture; import gregtech.api.objects.overclockdescriber.OverclockDescriber; import gregtech.api.util.GTRecipe; import gregtech.api.util.GTRecipeBuilder; 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: * *
* {@code * RecipeMap* * Note that {@link #maxIO} is required to build. */ // spotless:on @SuppressWarnings("unused") @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault public final class RecipeMapBuilder { private final String unlocalizedName; private final RecipeMapBackendPropertiesBuilder backendPropertiesBuilder = RecipeMapBackendProperties.builder(); private final RecipeMapBackend.BackendCreator 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 RecipeMapBuilder of(String unlocalizedName, RecipeMapBackend.BackendCreator 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 RecipeMapBuilderexampleRecipes = RecipeMapBuilder.of("example") * .maxIO(9, 4, 1, 1) * .build(); * } *
* Recipes added via one of the overloads of addRecipe will NOT be affected by this function. */ public RecipeMapBuilder recipeEmitterSingle( Function super GTRecipeBuilder, ? extends GTRecipe> recipeEmitter) { return recipeEmitter(recipeEmitter.andThen(Collections::singletonList)); } /** * Changes how recipes are emitted by a particular recipe builder. Can emit multiple recipe per builder. *
* Recipes added via one of the overloads of addRecipe will NOT be affected by this function. *
* Unlike {@link #recipeEmitter(Function)}, this one does not clear the existing recipe being emitted, if any */ public RecipeMapBuilder combineRecipeEmitter( Function super GTRecipeBuilder, ? extends Iterable extends GTRecipe>> 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. *
* Recipes added via one of the overloads of addRecipe will NOT be affected by this function. *
* Unlike {@link #recipeEmitter(Function)}, this one does not clear the existing recipe being emitted, if any */ public RecipeMapBuilder combineRecipeEmitterSingle( Function super GTRecipeBuilder, ? extends GTRecipe> recipeEmitter) { return combineRecipeEmitter(recipeEmitter.andThen(Collections::singletonList)); } /** * Runs a custom hook on all recipes added via builder. For more complicated behavior, * use {@link #recipeEmitter}. *
* Recipes added via one of the overloads of addRecipe will NOT be affected by this function. */ public RecipeMapBuilder recipeTransformer(Function super GTRecipe, ? extends GTRecipe> recipeTransformer) { backendPropertiesBuilder.recipeTransformer(recipeTransformer); return this; } /** * Runs a custom hook on all recipes added via builder. For more complicated behavior, * use {@link #recipeEmitter}. *
* Recipes added via one of the overloads of addRecipe will NOT be affected by this function.
*/
public RecipeMapBuilder recipeTransformer(Consumer
* Recipes added via one of the overloads of addRecipe will NOT be affected by this function.
*
* 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 chainRecipeTransformer(
Function super GTRecipe, ? extends GTRecipe> recipeTransformer) {
backendPropertiesBuilder.chainRecipeTransformer(recipeTransformer);
return this;
}
/**
* Runs a custom hook on all recipes added via builder. For more complicated behavior,
* use {@link #recipeEmitter}.
*
* Recipes added via one of the overloads of addRecipe will NOT be affected by this function.
*
* 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 chainRecipeTransformer(Consumer
* 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.
*
* By default, it's set to {@code GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT}.
*/
public RecipeMapBuilder progressBar(UITexture texture, ProgressBar.Direction direction) {
return progressBarWithFallback(GTUITextures.fallbackableProgressbar(unlocalizedName, texture), direction);
}
/**
* Sets progressbar texture with right direction.
*
* 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 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 progressBarWithFallback(FallbackableUITexture texture,
ProgressBar.Direction direction) {
uiPropertiesBuilder.progressBarTexture(texture)
.progressBarDirection(direction);
return this;
}
/**
* Sets progressbar texture for steam machines.
*
* 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 progressBarSteam(SteamTexture texture) {
return progressBarSteamWithFallback(
new FallbackableSteamTexture(
SteamTexture.fullImage(GregTech.ID, "gui/progressbar/" + unlocalizedName + "_%s"),
texture));
}
private RecipeMapBuilder progressBarSteamWithFallback(FallbackableSteamTexture texture) {
uiPropertiesBuilder.progressBarTextureSteam(texture);
return this;
}
/**
* Sets size of the progressbar. (20, 36) by default.
*/
public RecipeMapBuilder progressBarSize(int x, int y) {
uiPropertiesBuilder.progressBarSize(new Size(x, y));
return this;
}
/**
* Sets position of the progressbar. (78, 24) by default.
*/
public RecipeMapBuilder progressBarPos(int x, int y) {
uiPropertiesBuilder.progressBarPos(new Pos2d(x, y));
return this;
}
/**
* Stops adding progressbar to the UI.
*/
public RecipeMapBuilder 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 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 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 neiTransferRectId(String neiTransferRectId) {
uiPropertiesBuilder.neiTransferRectId(neiTransferRectId);
return this;
}
/**
* Adds additional textures shown on GUI.
*/
public RecipeMapBuilder 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 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 logo(IDrawable logo) {
uiPropertiesBuilder.logo(logo);
return this;
}
/**
* Sets size of logo. (17, 17) by default.
*/
public RecipeMapBuilder logoSize(int width, int height) {
uiPropertiesBuilder.logoSize(new Size(width, height));
return this;
}
/**
* Sets position of logo. (152, 63) by default.
*/
public RecipeMapBuilder logoPos(int x, int y) {
uiPropertiesBuilder.logoPos(new Pos2d(x, y));
return this;
}
/**
* Sets amperage for the recipemap.
*/
public RecipeMapBuilder 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 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.
*
* 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.
*
* If this method is not used, handler icon will be inferred from recipe catalysts associated with this recipemap.
*
* 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 neiHandlerInfo(UnaryOperator
* 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 useCustomFilterForNEI() {
neiPropertiesBuilder.useCustomFilter();
return this;
}
/**
* Stops rendering the actual stack size of items on NEI.
*/
public RecipeMapBuilder disableRenderRealStackSizes() {
neiPropertiesBuilder.disableRenderRealStackSizes();
return this;
}
/**
* Sets custom comparator for NEI recipe sort.
*/
public RecipeMapBuilder neiRecipeComparator(Comparator