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/RecipeMapFrontend.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/RecipeMapFrontend.java')
-rw-r--r-- | src/main/java/gregtech/api/recipe/RecipeMapFrontend.java | 395 |
1 files changed, 395 insertions, 0 deletions
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); + } +} |