From d8bc10a6ba68f8740d851dc9b2804d82d1226cc1 Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:22:41 -0500 Subject: [PATCH 01/12] Reimplement the new progress text and recipe outputs --- .../capability/impl/AbstractRecipeLogic.java | 10 ++ .../MultiMapMultiblockController.java | 3 +- .../RecipeMapMultiblockController.java | 3 +- .../RecipeMapSteamMultiblockController.java | 3 +- .../multiblock/ui/MultiblockUIBuilder.java | 170 +++++++++++++++++- .../electric/MetaTileEntityCleanroom.java | 2 +- .../electric/MetaTileEntityCrackingUnit.java | 3 +- .../MetaTileEntityElectricBlastFurnace.java | 3 +- .../electric/MetaTileEntityFluidDrill.java | 2 +- .../electric/MetaTileEntityMultiSmelter.java | 3 +- .../MetaTileEntityProcessingArray.java | 3 +- .../electric/MetaTileEntityPyrolyseOven.java | 3 +- .../MetaTileEntityResearchStation.java | 2 +- .../resources/assets/gregtech/lang/en_us.lang | 1 + 14 files changed, 194 insertions(+), 17 deletions(-) diff --git a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java index 99132df53dd..ba791e30e2c 100644 --- a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java +++ b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java @@ -1172,6 +1172,16 @@ public void setOverclockTier(final int tier) { setMaximumOverclockVoltage(GTValues.V[tier]); } + @NotNull + public List getItemOutputs() { + return itemOutputs; + } + + @NotNull + public List getFluidOutputs() { + return fluidOutputs; + } + /** * Used to reset cached values in the Recipe Logic on events such as multiblock structure deformation */ diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/MultiMapMultiblockController.java b/src/main/java/gregtech/api/metatileentity/multiblock/MultiMapMultiblockController.java index 1fccce2d897..1e581113c0d 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/MultiMapMultiblockController.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/MultiMapMultiblockController.java @@ -166,7 +166,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { .addEnergyTierLine(GTUtility.getTierByVoltage(recipeMapWorkable.getMaxVoltage())) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } @Override diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapMultiblockController.java b/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapMultiblockController.java index 9ce6514702b..7d241836797 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapMultiblockController.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapMultiblockController.java @@ -151,7 +151,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { .addEnergyTierLine(GTUtility.getTierByVoltage(recipeMapWorkable.getMaxVoltage())) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } protected void configureWarningText(MultiblockUIBuilder builder) { diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapSteamMultiblockController.java b/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapSteamMultiblockController.java index 0ccda35523e..53cf2b3f0ac 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapSteamMultiblockController.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/RecipeMapSteamMultiblockController.java @@ -118,7 +118,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { }) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } @Override diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java index 08304c4db60..99c7ba66f44 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java @@ -2,17 +2,21 @@ import gregtech.api.GTValues; import gregtech.api.capability.IEnergyContainer; +import gregtech.api.capability.impl.AbstractRecipeLogic; import gregtech.api.recipes.RecipeMap; import gregtech.api.util.KeyUtil; import gregtech.api.util.TextFormattingUtil; import gregtech.common.ConfigHolder; +import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fluids.FluidStack; import com.cleanroommc.modularui.api.drawable.IDrawable; import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.drawable.IRichTextBuilder; +import com.cleanroommc.modularui.utils.serialization.ByteBufAdapters; import com.cleanroommc.modularui.utils.serialization.IByteBufDeserializer; import com.cleanroommc.modularui.utils.serialization.IByteBufSerializer; import com.cleanroommc.modularui.value.sync.PanelSyncManager; @@ -27,7 +31,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.BooleanSupplier; @@ -46,6 +52,8 @@ public class MultiblockUIBuilder { private final InternalSyncHandler syncHandler = new InternalSyncHandler(); private final KeyManager manager = new InternalKeyManager(); + private static final int DEFAULT_MAX_RECIPE_LINES = 25; + @Nullable private InternalSyncer syncer; @@ -313,17 +321,23 @@ public MultiblockUIBuilder addIdlingLine(boolean checkState) { } /** - * Adds a simple progress line that displays progress as a percentage. + * Adds a progress line that displays recipe progress as "time / total time (percentage)". *
* Added if structure is formed and the machine is active. * - * @param progressPercent Progress formatted as a range of [0,1] representing the progress of the recipe. + * @param progress current progress. + * @param maxProgress total progress to be made. */ - public MultiblockUIBuilder addProgressLine(double progressPercent) { + public MultiblockUIBuilder addProgressLine(int progress, int maxProgress) { if (!isStructureFormed || !isActive) return this; - addKey(KeyUtil.lang(TextFormatting.GRAY, - "gregtech.multiblock.progress", - (int) (getSyncer().syncDouble(progressPercent) * 100))); + + progress = getSyncer().syncInt(progress); + maxProgress = getSyncer().syncInt(maxProgress); + + addKey(KeyUtil.lang(TextFormatting.WHITE, "gregtech.multiblock.recipe_progress", + String.format("%,3.2f", (float) progress / 20), + String.format("%,3.2f", (float) maxProgress / 20), + String.format("%,3.1f", (float) progress / maxProgress * 100f))); return this; } @@ -484,6 +498,150 @@ public MultiblockUIBuilder addRecipeMapLine(RecipeMap map) { return this; } + /** + * Adds the current outputs of a recipe from recipe logic. Items then fluids. + * + * @param arl an instance of an {@link AbstractRecipeLogic} to gather the outputs from. + */ + public MultiblockUIBuilder addRecipeOutputLine(@NotNull AbstractRecipeLogic arl) { + return addRecipeOutputLine(arl, DEFAULT_MAX_RECIPE_LINES); + } + + /** + * Adds the current outputs of a recipe from recipe logic. Items then fluids. + * + * @param arl an instance of an {@link AbstractRecipeLogic} to gather the outputs from. + * @param maxLines the maximum number of lines to print until truncating with {@code ...} + */ + public MultiblockUIBuilder addRecipeOutputLine(@NotNull AbstractRecipeLogic arl, int maxLines) { + return addRecipeOutputLine(arl.getItemOutputs(), arl.getFluidOutputs(), arl.getMaxProgress(), maxLines); + } + + /** + * Adds the current outputs of a recipe. Items then fluids. + * + * @param itemOutputs a list of {@link ItemStack}s to display. + * @param fluidOutputs a list of {@link FluidStack}s to display. + * @param recipeLength the recipe length, in ticks. + */ + public MultiblockUIBuilder addRecipeOutputLine(@Nullable List itemOutputs, + @Nullable List fluidOutputs, + int recipeLength) { + return addRecipeOutputLine(itemOutputs, fluidOutputs, recipeLength, DEFAULT_MAX_RECIPE_LINES); + } + + /** + * Adds the current outputs of a recipe. Items then fluids. + * + * @param itemOutputs a list of {@link ItemStack}s to display. + * @param fluidOutputs a list of {@link FluidStack}s to display. + * @param recipeLength the recipe length, in ticks. + * @param maxLines the maximum number of lines to print until truncating with {@code ...} + */ + public MultiblockUIBuilder addRecipeOutputLine(@Nullable List itemOutputs, + @Nullable List fluidOutputs, + int recipeLength, int maxLines) { + recipeLength = getSyncer().syncInt(recipeLength); + maxLines = getSyncer().syncInt(maxLines); + + if (itemOutputs != null) { + maxLines -= addItemOutputLine(itemOutputs, recipeLength, maxLines); + } + + if (fluidOutputs != null) { + maxLines -= addFluidOutputLine(fluidOutputs, recipeLength, maxLines); + } + + if (maxLines == 0) { + addKey(KeyUtil.string(TextFormatting.WHITE, "...")); + } + + return this; + } + + /** + * Add the item outputs of a recipe to the display. + * + * @param itemOutputs a list of {@link ItemStack}s to display. + * @param recipeLength the recipe length, in ticks. + * @param maxLines number of lines to print. + * @return the number of lines printed. + */ + private int addItemOutputLine(@NotNull List itemOutputs, int recipeLength, int maxLines) { + itemOutputs = getSyncer().syncCollection(new ArrayList<>(itemOutputs), ByteBufAdapters.ITEM_STACK); + + Map itemMap = new LinkedHashMap<>(); + for (ItemStack itemStack : itemOutputs) { + if (itemStack.isEmpty()) continue; + itemMap.merge(itemStack.getDisplayName(), (long) itemStack.getCount(), Long::sum); + } + + int printedLines = 0; + for (Map.Entry entry : itemMap.entrySet()) { + if (printedLines >= maxLines) break; + + IKey itemName = KeyUtil.string(TextFormatting.AQUA, entry.getKey()); + IKey itemAmount = KeyUtil.number(TextFormatting.GOLD, entry.getValue()); + IKey itemRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getValue())); + + addKey(formatRecipeData(itemName, itemAmount, itemRate)); + + printedLines += 1; + } + + return printedLines; + } + + /** + * Add the fluid outputs of a recipe to the display. + * + * @param fluidOutputs a list of {@link FluidStack}s to display. + * @param recipeLength the recipe length, in ticks. + * @param maxLines number of lines to print. + * @return the number of lines printed. + */ + private int addFluidOutputLine(@NotNull List fluidOutputs, int recipeLength, int maxLines) { + fluidOutputs = getSyncer().syncCollection(new ArrayList<>(fluidOutputs), ByteBufAdapters.FLUID_STACK); + + Map fluidMap = new LinkedHashMap<>(); + for (FluidStack fluidStack : fluidOutputs) { + if (fluidStack.amount < 1) continue; + fluidMap.merge(fluidStack, (long) fluidStack.amount, Long::sum); + } + + int printedLines = 0; + for (Map.Entry entry : fluidMap.entrySet()) { + if (printedLines >= maxLines) break; + + IKey fluidName = KeyUtil.fluid(TextFormatting.AQUA, entry.getKey()); + IKey fluidAmount = KeyUtil.number(TextFormatting.GOLD, entry.getValue(), "L"); + IKey fluidRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getValue())); + + addKey(formatRecipeData(fluidName, fluidAmount, fluidRate)); + + printedLines += 1; + } + + return printedLines; + } + + private static String formatRecipeRate(int recipeLength, long amount) { + float perSecond = ((float) amount / recipeLength) * 20f; + + String rate; + if (perSecond > 1) { + rate = "(" + String.format("%,.2f", perSecond).replaceAll("\\.?0+$", "") + "/s)"; + } else { + rate = "(" + String.format("%,.2f", 1 / (perSecond)).replaceAll("\\.?0+$", "") + "s/ea)"; + } + + return rate; + } + + private static IKey formatRecipeData(IKey name, IKey amount, IKey rate) { + return IKey.comp(name, KeyUtil.string(TextFormatting.WHITE, " x "), amount, IKey.SPACE, rate); + } + /** Insert an empty line into the text list. */ public MultiblockUIBuilder addEmptyLine() { addKey(IKey.LINE_FEED); diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java index 0b1edad8de7..f4584488be9 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java @@ -504,7 +504,7 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { cleanState)); } }) - .addProgressLine(getProgressPercent() / 100.0) + .addProgressLine(getProgress(), getMaxProgress()) .addWorkingStatusLine(); } diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java index 62d05fd2aa2..a20c11176c1 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java @@ -102,7 +102,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { }) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } @Override diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java index d57007262aa..b70680943f2 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java @@ -78,7 +78,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { .addCustom(this::addHeatCapacity) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } private void addHeatCapacity(KeyManager keyManager, UISyncer syncer) { diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java index b0ac1aa59ec..d6ce9f408e1 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java @@ -195,7 +195,7 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { } } }) - .addProgressLine(minerLogic.getProgressPercent()) + .addProgressLine(minerLogic.getProgressTime(), FluidDrillLogic.MAX_PROGRESS) .addWorkingStatusLine(); } diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java index 41ebaeb15a6..382a54719b5 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java @@ -91,7 +91,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { } }) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } @Override diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java index 7355e0c91eb..fbb5d7faeab 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java @@ -170,7 +170,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { }) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } @SideOnly(Side.CLIENT) diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java index 8734ee35a67..6213867dd68 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java @@ -128,7 +128,8 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { }) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()) + .addRecipeOutputLine(recipeMapWorkable); } @Override diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityResearchStation.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityResearchStation.java index db325ef9524..5e2bed97a52 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityResearchStation.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityResearchStation.java @@ -233,7 +233,7 @@ protected void configureDisplayText(MultiblockUIBuilder builder) { .addComputationUsageExactLine(getRecipeMapWorkable().getCurrentDrawnCWUt()) .addParallelsLine(recipeMapWorkable.getParallelLimit()) .addWorkingStatusLine() - .addProgressLine(recipeMapWorkable.getProgressPercent()); + .addProgressLine(recipeMapWorkable.getProgress(), recipeMapWorkable.getMaxProgress()); } @Override diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index ff66c289421..4e5c8778bb3 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -5734,6 +5734,7 @@ gregtech.multiblock.idling=Idling. gregtech.multiblock.not_enough_energy=Machine needs more energy! gregtech.multiblock.not_enough_energy_output=Energy Dynamo Tier Too Low! gregtech.multiblock.progress=Progress: %s%% +gregtech.multiblock.recipe_progress=Progress: %ss / %ss (%s%%) gregtech.multiblock.invalid_structure=§cInvalid structure. gregtech.multiblock.invalid_structure.tooltip=This block is a controller of the multiblock structure. For building help, see structure template in JEI. gregtech.multiblock.validation_failed=Invalid amount of inputs/outputs. From 46f58ed0c45bad75773bdf6bf736bfe78a252448 Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:46:34 -0500 Subject: [PATCH 02/12] fastutils + FluidStackHashStrategy --- .../multiblock/ui/MultiblockUIBuilder.java | 16 +++-- .../api/util/FluidStackHashStrategy.java | 68 +++++++++++++++++++ 2 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 src/main/java/gregtech/api/util/FluidStackHashStrategy.java diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java index 99c7ba66f44..b6d4a12afaf 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java @@ -4,6 +4,8 @@ import gregtech.api.capability.IEnergyContainer; import gregtech.api.capability.impl.AbstractRecipeLogic; import gregtech.api.recipes.RecipeMap; +import gregtech.api.util.FluidStackHashStrategy; +import gregtech.api.util.ItemStackHashStrategy; import gregtech.api.util.KeyUtil; import gregtech.api.util.TextFormattingUtil; import gregtech.common.ConfigHolder; @@ -23,6 +25,7 @@ import com.cleanroommc.modularui.value.sync.SyncHandler; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.objects.Object2LongLinkedOpenCustomHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,7 +34,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -570,17 +572,18 @@ public MultiblockUIBuilder addRecipeOutputLine(@Nullable List itemOut private int addItemOutputLine(@NotNull List itemOutputs, int recipeLength, int maxLines) { itemOutputs = getSyncer().syncCollection(new ArrayList<>(itemOutputs), ByteBufAdapters.ITEM_STACK); - Map itemMap = new LinkedHashMap<>(); + Map itemMap = new Object2LongLinkedOpenCustomHashMap<>( + ItemStackHashStrategy.comparingAllButCount()); for (ItemStack itemStack : itemOutputs) { if (itemStack.isEmpty()) continue; - itemMap.merge(itemStack.getDisplayName(), (long) itemStack.getCount(), Long::sum); + itemMap.merge(itemStack, (long) itemStack.getCount(), Long::sum); } int printedLines = 0; - for (Map.Entry entry : itemMap.entrySet()) { + for (Map.Entry entry : itemMap.entrySet()) { if (printedLines >= maxLines) break; - IKey itemName = KeyUtil.string(TextFormatting.AQUA, entry.getKey()); + IKey itemName = KeyUtil.string(TextFormatting.AQUA, entry.getKey().getDisplayName()); IKey itemAmount = KeyUtil.number(TextFormatting.GOLD, entry.getValue()); IKey itemRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getValue())); @@ -603,7 +606,8 @@ private int addItemOutputLine(@NotNull List itemOutputs, int recipeLe private int addFluidOutputLine(@NotNull List fluidOutputs, int recipeLength, int maxLines) { fluidOutputs = getSyncer().syncCollection(new ArrayList<>(fluidOutputs), ByteBufAdapters.FLUID_STACK); - Map fluidMap = new LinkedHashMap<>(); + Map fluidMap = new Object2LongLinkedOpenCustomHashMap<>( + FluidStackHashStrategy.comparingAllButAmount); for (FluidStack fluidStack : fluidOutputs) { if (fluidStack.amount < 1) continue; fluidMap.merge(fluidStack, (long) fluidStack.amount, Long::sum); diff --git a/src/main/java/gregtech/api/util/FluidStackHashStrategy.java b/src/main/java/gregtech/api/util/FluidStackHashStrategy.java new file mode 100644 index 00000000000..8aacb2d39d5 --- /dev/null +++ b/src/main/java/gregtech/api/util/FluidStackHashStrategy.java @@ -0,0 +1,68 @@ +package gregtech.api.util; + +import net.minecraftforge.fluids.FluidStack; + +import it.unimi.dsi.fastutil.Hash; + +import java.util.Objects; + +public interface FluidStackHashStrategy extends Hash.Strategy { + + static FluidStackHashStrategyBuilder builder() { + return new FluidStackHashStrategyBuilder(); + } + + FluidStackHashStrategy comparingAll = builder() + .compareFluid() + .compareAmount() + .compareNBT() + .build(); + + FluidStackHashStrategy comparingAllButAmount = builder() + .compareFluid() + .compareNBT() + .build(); + + class FluidStackHashStrategyBuilder { + + private boolean fluid, amount, nbt = false; + + public FluidStackHashStrategyBuilder compareFluid() { + this.fluid = true; + return this; + } + + public FluidStackHashStrategyBuilder compareAmount() { + this.amount = true; + return this; + } + + public FluidStackHashStrategyBuilder compareNBT() { + this.nbt = true; + return this; + } + + public FluidStackHashStrategy build() { + return new FluidStackHashStrategy() { + + @Override + public int hashCode(FluidStack other) { + return other == null ? 0 : Objects.hash( + fluid ? other.getFluid() : null, + amount ? other.amount : null, + nbt ? other.tag : null); + } + + @Override + public boolean equals(FluidStack a, FluidStack b) { + if (a == null) return b == null; + if (b == null) return false; + + return (!fluid || a.getFluid() == b.getFluid()) && + (!amount || a.amount == b.amount) && + (!nbt || Objects.equals(a.tag, b.tag)); + } + }; + } + } +} From c237f3a324cb8f357814ec980d78430447f5e708 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:18:41 -0700 Subject: [PATCH 03/12] add drawable fluid/item stack instead move output data into tooltip mixin to fix RichTextCompiler --- .../multiblock/ui/MultiblockUIBuilder.java | 33 +++++++--- .../api/mui/drawable/GTFluidDrawable.java | 65 +++++++++++++++++++ .../api/mui/drawable/GTItemDrawable.java | 65 +++++++++++++++++++ .../mixins/mui2/RichTextCompilerMixin.java | 18 +++++ src/main/resources/mixins.gregtech.mui2.json | 3 +- 5 files changed, 175 insertions(+), 9 deletions(-) create mode 100644 src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java create mode 100644 src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java create mode 100644 src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java index b6d4a12afaf..11f44d1ba00 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java @@ -3,6 +3,8 @@ import gregtech.api.GTValues; import gregtech.api.capability.IEnergyContainer; import gregtech.api.capability.impl.AbstractRecipeLogic; +import gregtech.api.mui.drawable.GTFluidDrawable; +import gregtech.api.mui.drawable.GTItemDrawable; import gregtech.api.recipes.RecipeMap; import gregtech.api.util.FluidStackHashStrategy; import gregtech.api.util.ItemStackHashStrategy; @@ -540,24 +542,28 @@ public MultiblockUIBuilder addRecipeOutputLine(@Nullable List itemOut * @param recipeLength the recipe length, in ticks. * @param maxLines the maximum number of lines to print until truncating with {@code ...} */ - public MultiblockUIBuilder addRecipeOutputLine(@Nullable List itemOutputs, - @Nullable List fluidOutputs, + public MultiblockUIBuilder addRecipeOutputLine(@NotNull List itemOutputs, + @NotNull List fluidOutputs, int recipeLength, int maxLines) { recipeLength = getSyncer().syncInt(recipeLength); maxLines = getSyncer().syncInt(maxLines); - if (itemOutputs != null) { + if (recipeLength == 0) return this; + + addKey(KeyUtil.string(TextFormatting.GRAY, "Producing: "), Operation.ADD); + + if (!itemOutputs.isEmpty()) maxLines -= addItemOutputLine(itemOutputs, recipeLength, maxLines); - } - if (fluidOutputs != null) { + if (!fluidOutputs.isEmpty()) maxLines -= addFluidOutputLine(fluidOutputs, recipeLength, maxLines); - } if (maxLines == 0) { addKey(KeyUtil.string(TextFormatting.WHITE, "...")); } + addEmptyLine(); + return this; } @@ -587,8 +593,13 @@ private int addItemOutputLine(@NotNull List itemOutputs, int recipeLe IKey itemAmount = KeyUtil.number(TextFormatting.GOLD, entry.getValue()); IKey itemRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getValue())); - addKey(formatRecipeData(itemName, itemAmount, itemRate)); + IDrawable stack = new GTItemDrawable(entry.getKey(), entry.getValue()) + .asIcon() + .asHoverable() + .addTooltipLine(formatRecipeData(itemName, itemAmount, itemRate)); + addKey(stack, Operation.ADD); + addKey(IKey.SPACE, Operation.ADD); printedLines += 1; } @@ -621,7 +632,13 @@ private int addFluidOutputLine(@NotNull List fluidOutputs, int recip IKey fluidAmount = KeyUtil.number(TextFormatting.GOLD, entry.getValue(), "L"); IKey fluidRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getValue())); - addKey(formatRecipeData(fluidName, fluidAmount, fluidRate)); + IDrawable fluid = new GTFluidDrawable(entry.getKey(), entry.getValue()) + .asIcon() + .asHoverable() + .addTooltipLine(formatRecipeData(fluidName, fluidAmount, fluidRate)); + + addKey(fluid, Operation.ADD); + addKey(IKey.SPACE, Operation.ADD); printedLines += 1; } diff --git a/src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java new file mode 100644 index 00000000000..1884144f79d --- /dev/null +++ b/src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java @@ -0,0 +1,65 @@ +package gregtech.api.mui.drawable; + +import net.minecraftforge.fluids.FluidStack; + +import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.drawable.Icon; +import com.cleanroommc.modularui.drawable.text.TextRenderer; +import com.cleanroommc.modularui.screen.viewport.GuiContext; +import com.cleanroommc.modularui.theme.WidgetTheme; +import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.utils.Color; +import com.cleanroommc.modularui.utils.NumberFormat; +import com.cleanroommc.modularui.widget.Widget; + +public class GTFluidDrawable implements IDrawable { + + private FluidStack stack; + private long amount; + private final TextRenderer renderer = new TextRenderer(); + + public GTFluidDrawable(FluidStack stack, long amount) { + this.stack = stack; + this.amount = amount; + } + + public GTFluidDrawable(FluidStack stack) { + this.stack = stack; + } + + public GTFluidDrawable() {} + + { + renderer.setScale(0.5f); + renderer.setShadow(true); + renderer.setColor(Color.WHITE.main); + } + + @Override + public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { + GuiDraw.drawFluidTexture(this.stack, x, y, width, height, 0); + String amountText = NumberFormat.formatWithMaxDigits(amount, 3) + "L"; + renderer.setAlignment(Alignment.BottomRight, width - 1, height - 1); + renderer.setPos(x + 1, y + 1); + renderer.draw(amountText); + } + + public void setAmount(long amount) { + this.amount = amount; + } + + public void setStack(FluidStack stack) { + this.stack = stack; + } + + @Override + public Icon asIcon() { + return IDrawable.super.asIcon().size(16); + } + + @Override + public Widget asWidget() { + return IDrawable.super.asWidget().size(16); + } +} diff --git a/src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java new file mode 100644 index 00000000000..040f4892058 --- /dev/null +++ b/src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java @@ -0,0 +1,65 @@ +package gregtech.api.mui.drawable; + +import net.minecraft.item.ItemStack; + +import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.drawable.Icon; +import com.cleanroommc.modularui.drawable.text.TextRenderer; +import com.cleanroommc.modularui.screen.viewport.GuiContext; +import com.cleanroommc.modularui.theme.WidgetTheme; +import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.utils.Color; +import com.cleanroommc.modularui.utils.NumberFormat; +import com.cleanroommc.modularui.widget.Widget; + +public class GTItemDrawable implements IDrawable { + + private ItemStack stack; + private long amount; + private final TextRenderer renderer = new TextRenderer(); + + public GTItemDrawable(ItemStack stack, long amount) { + this.stack = stack; + this.amount = amount; + } + + public GTItemDrawable(ItemStack stack) { + this.stack = stack; + } + + public GTItemDrawable() {} + + { + renderer.setScale(0.5f); + renderer.setShadow(true); + renderer.setColor(Color.WHITE.main); + } + + @Override + public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { + GuiDraw.drawItem(this.stack, x, y, width, height); + String amountText = NumberFormat.formatWithMaxDigits(amount, 3); + renderer.setAlignment(Alignment.BottomRight, width - 1, height - 1); + renderer.setPos(x + 1, y + 1); + renderer.draw(amountText); + } + + public void setAmount(long amount) { + this.amount = amount; + } + + public void setStack(ItemStack stack) { + this.stack = stack; + } + + @Override + public Icon asIcon() { + return IDrawable.super.asIcon().size(16); + } + + @Override + public Widget asWidget() { + return IDrawable.super.asWidget().size(16); + } +} diff --git a/src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java b/src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java new file mode 100644 index 00000000000..fbb826a151c --- /dev/null +++ b/src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java @@ -0,0 +1,18 @@ +package gregtech.mixins.mui2; + +import com.cleanroommc.modularui.drawable.text.RichTextCompiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(value = RichTextCompiler.class, remap = false) +public class RichTextCompilerMixin { + + @ModifyArg(method = "trimRight", + at = @At(value = "INVOKE", + target = "Ljava/lang/String;substring(II)Ljava/lang/String;"), + index = 1) + private static int fixTrim(int beginIndex) { + return beginIndex + 1; + } +} diff --git a/src/main/resources/mixins.gregtech.mui2.json b/src/main/resources/mixins.gregtech.mui2.json index f313fa2b32d..a13b45e2493 100644 --- a/src/main/resources/mixins.gregtech.mui2.json +++ b/src/main/resources/mixins.gregtech.mui2.json @@ -8,7 +8,8 @@ "maxShiftBy": 10 }, "mixins": [ - "ModularPanelMixin" + "ModularPanelMixin", + "RichTextCompilerMixin" ], "client": [ "LangKeyMixin" From 847a5912eea49d95d2c3aadb180a8cc66b4e6482 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:11:31 -0700 Subject: [PATCH 04/12] remove is empty check use obj2long map interface --- .../multiblock/ui/MultiblockUIBuilder.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java index 11f44d1ba00..5ab14972e9d 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java @@ -28,6 +28,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.objects.Object2LongLinkedOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.Object2LongMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,7 +38,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.BooleanSupplier; @@ -552,11 +552,9 @@ public MultiblockUIBuilder addRecipeOutputLine(@NotNull List itemOutp addKey(KeyUtil.string(TextFormatting.GRAY, "Producing: "), Operation.ADD); - if (!itemOutputs.isEmpty()) - maxLines -= addItemOutputLine(itemOutputs, recipeLength, maxLines); + maxLines -= addItemOutputLine(itemOutputs, recipeLength, maxLines); - if (!fluidOutputs.isEmpty()) - maxLines -= addFluidOutputLine(fluidOutputs, recipeLength, maxLines); + maxLines -= addFluidOutputLine(fluidOutputs, recipeLength, maxLines); if (maxLines == 0) { addKey(KeyUtil.string(TextFormatting.WHITE, "...")); @@ -578,7 +576,7 @@ public MultiblockUIBuilder addRecipeOutputLine(@NotNull List itemOutp private int addItemOutputLine(@NotNull List itemOutputs, int recipeLength, int maxLines) { itemOutputs = getSyncer().syncCollection(new ArrayList<>(itemOutputs), ByteBufAdapters.ITEM_STACK); - Map itemMap = new Object2LongLinkedOpenCustomHashMap<>( + Object2LongMap itemMap = new Object2LongLinkedOpenCustomHashMap<>( ItemStackHashStrategy.comparingAllButCount()); for (ItemStack itemStack : itemOutputs) { if (itemStack.isEmpty()) continue; @@ -586,14 +584,14 @@ private int addItemOutputLine(@NotNull List itemOutputs, int recipeLe } int printedLines = 0; - for (Map.Entry entry : itemMap.entrySet()) { + for (var entry : itemMap.object2LongEntrySet()) { if (printedLines >= maxLines) break; IKey itemName = KeyUtil.string(TextFormatting.AQUA, entry.getKey().getDisplayName()); - IKey itemAmount = KeyUtil.number(TextFormatting.GOLD, entry.getValue()); - IKey itemRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getValue())); + IKey itemAmount = KeyUtil.number(TextFormatting.GOLD, entry.getLongValue()); + IKey itemRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getLongValue())); - IDrawable stack = new GTItemDrawable(entry.getKey(), entry.getValue()) + IDrawable stack = new GTItemDrawable(entry.getKey(), entry.getLongValue()) .asIcon() .asHoverable() .addTooltipLine(formatRecipeData(itemName, itemAmount, itemRate)); @@ -617,7 +615,7 @@ private int addItemOutputLine(@NotNull List itemOutputs, int recipeLe private int addFluidOutputLine(@NotNull List fluidOutputs, int recipeLength, int maxLines) { fluidOutputs = getSyncer().syncCollection(new ArrayList<>(fluidOutputs), ByteBufAdapters.FLUID_STACK); - Map fluidMap = new Object2LongLinkedOpenCustomHashMap<>( + Object2LongMap fluidMap = new Object2LongLinkedOpenCustomHashMap<>( FluidStackHashStrategy.comparingAllButAmount); for (FluidStack fluidStack : fluidOutputs) { if (fluidStack.amount < 1) continue; @@ -625,14 +623,14 @@ private int addFluidOutputLine(@NotNull List fluidOutputs, int recip } int printedLines = 0; - for (Map.Entry entry : fluidMap.entrySet()) { + for (var entry : fluidMap.object2LongEntrySet()) { if (printedLines >= maxLines) break; IKey fluidName = KeyUtil.fluid(TextFormatting.AQUA, entry.getKey()); - IKey fluidAmount = KeyUtil.number(TextFormatting.GOLD, entry.getValue(), "L"); - IKey fluidRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getValue())); + IKey fluidAmount = KeyUtil.number(TextFormatting.GOLD, entry.getLongValue(), "L"); + IKey fluidRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getLongValue())); - IDrawable fluid = new GTFluidDrawable(entry.getKey(), entry.getValue()) + IDrawable fluid = new GTFluidDrawable(entry.getKey(), entry.getLongValue()) .asIcon() .asHoverable() .addTooltipLine(formatRecipeData(fluidName, fluidAmount, fluidRate)); From 086fba58c1f40ccd409ee89ff3ec354c66ed8bba Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 1 Mar 2025 23:33:38 -0700 Subject: [PATCH 05/12] greatly rework adding outputs to the display (sorry zorb) chanced outputs are now added to the display replace item/fluid drawable with object drawable create GTByteBufAdapters add serialization for chanced item/fluid outputs add method to get parallel recipe directly from arl --- .../capability/impl/AbstractRecipeLogic.java | 6 + .../multiblock/ui/MultiblockUIBuilder.java | 236 ++++++++++-------- .../gregtech/api/mui/GTByteBufAdapters.java | 53 ++++ .../api/mui/drawable/GTFluidDrawable.java | 65 ----- .../api/mui/drawable/GTItemDrawable.java | 65 ----- .../api/mui/drawable/GTObjectDrawable.java | 81 ++++++ .../output/impl/ChancedFluidOutput.java | 15 ++ .../chance/output/impl/ChancedItemOutput.java | 12 + 8 files changed, 305 insertions(+), 228 deletions(-) create mode 100644 src/main/java/gregtech/api/mui/GTByteBufAdapters.java delete mode 100644 src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java delete mode 100644 src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java create mode 100644 src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java diff --git a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java index ba791e30e2c..5b587f33b20 100644 --- a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java +++ b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java @@ -187,6 +187,12 @@ protected IMultipleTankHandler getOutputTank() { return metaTileEntity.getExportFluids(); } + public Recipe getParallelRecipe() { + if (previousRecipe == null) return null; + return findParallelRecipe(previousRecipe, getInputInventory(), getInputTank(), + getOutputInventory(), getOutputTank(), getMaxParallelVoltage(), getParallelLimit()); + } + /** * @return true if energy is consumed by this Recipe Logic, otherwise false */ diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java index 5ab14972e9d..22c55f86b97 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java @@ -3,10 +3,15 @@ import gregtech.api.GTValues; import gregtech.api.capability.IEnergyContainer; import gregtech.api.capability.impl.AbstractRecipeLogic; -import gregtech.api.mui.drawable.GTFluidDrawable; -import gregtech.api.mui.drawable.GTItemDrawable; +import gregtech.api.mui.GTByteBufAdapters; +import gregtech.api.mui.drawable.GTObjectDrawable; +import gregtech.api.recipes.Recipe; import gregtech.api.recipes.RecipeMap; +import gregtech.api.recipes.chance.boost.ChanceBoostFunction; +import gregtech.api.recipes.chance.output.impl.ChancedFluidOutput; +import gregtech.api.recipes.chance.output.impl.ChancedItemOutput; import gregtech.api.util.FluidStackHashStrategy; +import gregtech.api.util.GTUtility; import gregtech.api.util.ItemStackHashStrategy; import gregtech.api.util.KeyUtil; import gregtech.api.util.TextFormattingUtil; @@ -517,131 +522,166 @@ public MultiblockUIBuilder addRecipeOutputLine(@NotNull AbstractRecipeLogic arl) * @param arl an instance of an {@link AbstractRecipeLogic} to gather the outputs from. * @param maxLines the maximum number of lines to print until truncating with {@code ...} */ - public MultiblockUIBuilder addRecipeOutputLine(@NotNull AbstractRecipeLogic arl, int maxLines) { - return addRecipeOutputLine(arl.getItemOutputs(), arl.getFluidOutputs(), arl.getMaxProgress(), maxLines); - } - - /** - * Adds the current outputs of a recipe. Items then fluids. - * - * @param itemOutputs a list of {@link ItemStack}s to display. - * @param fluidOutputs a list of {@link FluidStack}s to display. - * @param recipeLength the recipe length, in ticks. - */ - public MultiblockUIBuilder addRecipeOutputLine(@Nullable List itemOutputs, - @Nullable List fluidOutputs, - int recipeLength) { - return addRecipeOutputLine(itemOutputs, fluidOutputs, recipeLength, DEFAULT_MAX_RECIPE_LINES); - } - - /** - * Adds the current outputs of a recipe. Items then fluids. - * - * @param itemOutputs a list of {@link ItemStack}s to display. - * @param fluidOutputs a list of {@link FluidStack}s to display. - * @param recipeLength the recipe length, in ticks. - * @param maxLines the maximum number of lines to print until truncating with {@code ...} - */ - public MultiblockUIBuilder addRecipeOutputLine(@NotNull List itemOutputs, - @NotNull List fluidOutputs, - int recipeLength, int maxLines) { - recipeLength = getSyncer().syncInt(recipeLength); - maxLines = getSyncer().syncInt(maxLines); - - if (recipeLength == 0) return this; + public MultiblockUIBuilder addRecipeOutputLine(AbstractRecipeLogic arl, int maxLines) { + // todo doing this every tick on the server is probably not good + Recipe recipe = arl.getParallelRecipe(); - addKey(KeyUtil.string(TextFormatting.GRAY, "Producing: "), Operation.ADD); + if (getSyncer().syncBoolean(recipe == null)) return this; + if (getSyncer().syncBoolean(arl.getRecipeMap() == null)) return this; - maxLines -= addItemOutputLine(itemOutputs, recipeLength, maxLines); + long eut = getSyncer().syncLong(recipe == null ? 0 : recipe.getEUt()); + long maxVoltage = getSyncer().syncLong(arl.getMaximumOverclockVoltage()); - maxLines -= addFluidOutputLine(fluidOutputs, recipeLength, maxLines); + List itemOutputs = new ArrayList<>(); + List chancedItemOutputs = new ArrayList<>(); + List fluidOutputs = new ArrayList<>(); + List chancedFluidOutputs = new ArrayList<>(); - if (maxLines == 0) { - addKey(KeyUtil.string(TextFormatting.WHITE, "...")); + if (isServer()) { + // recipe is checked indirectly for null + // noinspection DataFlowIssue + itemOutputs.addAll(recipe.getOutputs()); + chancedItemOutputs.addAll(recipe.getChancedOutputs().getChancedEntries()); + fluidOutputs.addAll(recipe.getFluidOutputs()); + chancedFluidOutputs.addAll(recipe.getChancedFluidOutputs().getChancedEntries()); } - addEmptyLine(); + itemOutputs = getSyncer().syncCollection(itemOutputs, ByteBufAdapters.ITEM_STACK); + fluidOutputs = getSyncer().syncCollection(fluidOutputs, ByteBufAdapters.FLUID_STACK); + chancedItemOutputs = getSyncer().syncCollection(chancedItemOutputs, GTByteBufAdapters.CHANCED_ITEM_OUTPUT); + chancedFluidOutputs = getSyncer().syncCollection(chancedFluidOutputs, GTByteBufAdapters.CHANCED_FLUID_OUTPUT); - return this; - } + addKey(KeyUtil.string(TextFormatting.GRAY, "Producing: "), Operation.NEW_LINE); - /** - * Add the item outputs of a recipe to the display. - * - * @param itemOutputs a list of {@link ItemStack}s to display. - * @param recipeLength the recipe length, in ticks. - * @param maxLines number of lines to print. - * @return the number of lines printed. - */ - private int addItemOutputLine(@NotNull List itemOutputs, int recipeLength, int maxLines) { - itemOutputs = getSyncer().syncCollection(new ArrayList<>(itemOutputs), ByteBufAdapters.ITEM_STACK); + var chanceFunction = arl.getRecipeMap().getChanceFunction(); + int recipeTier = GTUtility.getTierByVoltage(eut); + int machineTier = GTUtility.getOCTierByVoltage(maxVoltage); + + // items Object2LongMap itemMap = new Object2LongLinkedOpenCustomHashMap<>( ItemStackHashStrategy.comparingAllButCount()); - for (ItemStack itemStack : itemOutputs) { - if (itemStack.isEmpty()) continue; - itemMap.merge(itemStack, (long) itemStack.getCount(), Long::sum); + + for (ItemStack stack : itemOutputs) { + itemMap.merge(stack, (long) stack.getCount(), Long::sum); } - int printedLines = 0; - for (var entry : itemMap.object2LongEntrySet()) { - if (printedLines >= maxLines) break; + for (var stack : itemMap.keySet()) { + addItemOutputLine(stack, itemMap.getLong(stack), arl.getMaxProgress()); + } - IKey itemName = KeyUtil.string(TextFormatting.AQUA, entry.getKey().getDisplayName()); - IKey itemAmount = KeyUtil.number(TextFormatting.GOLD, entry.getLongValue()); - IKey itemRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getLongValue())); + for (var chancedItemOutput : chancedItemOutputs) { + addChancedItemOutputLine(chancedItemOutput, chanceFunction, recipeTier, machineTier, arl.getMaxProgress()); + } - IDrawable stack = new GTItemDrawable(entry.getKey(), entry.getLongValue()) - .asIcon() - .asHoverable() - .addTooltipLine(formatRecipeData(itemName, itemAmount, itemRate)); + // fluids - addKey(stack, Operation.ADD); - addKey(IKey.SPACE, Operation.ADD); - printedLines += 1; + Object2LongMap fluidMap = new Object2LongLinkedOpenCustomHashMap<>( + FluidStackHashStrategy.comparingAllButAmount); + + for (FluidStack stack : fluidOutputs) { + fluidMap.merge(stack, (long) stack.amount, Long::sum); + } + + for (var stack : fluidMap.keySet()) { + addFluidOutputLine(stack, fluidMap.getLong(stack), arl.getMaxProgress()); } - return printedLines; + for (var chancedFluidOutput : chancedFluidOutputs) { + addChancedFluidOutputLine(chancedFluidOutput, chanceFunction, recipeTier, machineTier, + arl.getMaxProgress()); + } + return this; } /** - * Add the fluid outputs of a recipe to the display. + * Add an item output of a recipe to the display. * - * @param fluidOutputs a list of {@link FluidStack}s to display. + * @param stack the {@link ItemStack} to display. * @param recipeLength the recipe length, in ticks. - * @param maxLines number of lines to print. - * @return the number of lines printed. */ - private int addFluidOutputLine(@NotNull List fluidOutputs, int recipeLength, int maxLines) { - fluidOutputs = getSyncer().syncCollection(new ArrayList<>(fluidOutputs), ByteBufAdapters.FLUID_STACK); + private void addItemOutputLine(@NotNull ItemStack stack, long count, int recipeLength) { + IKey name = KeyUtil.string(TextFormatting.AQUA, stack.getDisplayName()); + IKey amount = KeyUtil.number(TextFormatting.GOLD, count); + IKey rate = KeyUtil.string(TextFormatting.WHITE, + formatRecipeRate(getSyncer().syncInt(recipeLength), count)); - Object2LongMap fluidMap = new Object2LongLinkedOpenCustomHashMap<>( - FluidStackHashStrategy.comparingAllButAmount); - for (FluidStack fluidStack : fluidOutputs) { - if (fluidStack.amount < 1) continue; - fluidMap.merge(fluidStack, (long) fluidStack.amount, Long::sum); - } - - int printedLines = 0; - for (var entry : fluidMap.object2LongEntrySet()) { - if (printedLines >= maxLines) break; - - IKey fluidName = KeyUtil.fluid(TextFormatting.AQUA, entry.getKey()); - IKey fluidAmount = KeyUtil.number(TextFormatting.GOLD, entry.getLongValue(), "L"); - IKey fluidRate = KeyUtil.string(TextFormatting.WHITE, formatRecipeRate(recipeLength, entry.getLongValue())); + addKey(new GTObjectDrawable(stack, count) + .asIcon() + .asHoverable() + .addTooltipLine(formatRecipeData(name, amount, rate)), Operation.ADD); + // addKey(IKey.SPACE, Operation.ADD); + } - IDrawable fluid = new GTFluidDrawable(entry.getKey(), entry.getLongValue()) - .asIcon() - .asHoverable() - .addTooltipLine(formatRecipeData(fluidName, fluidAmount, fluidRate)); + /** + * Add the fluid outputs of a recipe to the display. + * + * @param stack a {@link FluidStack}s to display. + * @param recipeLength the recipe length, in ticks. + */ + private void addFluidOutputLine(@NotNull FluidStack stack, long count, int recipeLength) { + IKey name = KeyUtil.fluid(TextFormatting.AQUA, stack); + IKey amount = KeyUtil.number(TextFormatting.GOLD, count); + IKey rate = KeyUtil.string(TextFormatting.WHITE, + formatRecipeRate(getSyncer().syncInt(recipeLength), count)); - addKey(fluid, Operation.ADD); - addKey(IKey.SPACE, Operation.ADD); + addKey(new GTObjectDrawable(stack, count) + .asIcon() + .asHoverable() + .addTooltipLine(formatRecipeData(name, amount, rate)), Operation.ADD); + // addKey(IKey.SPACE, Operation.ADD); + } - printedLines += 1; - } + /** + * Add a chanced item output of a recipe to the display. + * + * @param chancedItemOutput chanced item output + * @param boostFunction function to calculate boosted chance + * @param recipeTier voltage tier of the recipe + * @param machineTier machine tier + * @param recipeLength max duration of the recipe + */ + private void addChancedItemOutputLine(@NotNull ChancedItemOutput chancedItemOutput, + ChanceBoostFunction boostFunction, + int recipeTier, int machineTier, int recipeLength) { + var stack = chancedItemOutput.getIngredient(); + IKey name = KeyUtil.string(TextFormatting.AQUA, stack.getDisplayName()); + IKey amount = KeyUtil.number(TextFormatting.GOLD, stack.getCount()); + IKey rate = KeyUtil.string(TextFormatting.WHITE, + formatRecipeRate(getSyncer().syncInt(recipeLength), stack.getCount())); + + addKey(new GTObjectDrawable(chancedItemOutput, stack.getCount()) + .setBoostFunction(entry -> boostFunction.getBoostedChance(entry, recipeTier, machineTier)) + .asIcon() + .asHoverable() + .addTooltipLine(formatRecipeData(name, amount, rate)), Operation.ADD); + // addKey(IKey.SPACE, Operation.ADD); + } - return printedLines; + /** + * Add a chanced fluid output of a recipe to the display. + * + * @param chancedFluidOutput chanced fluid output + * @param boostFunction function to calculate boosted chance + * @param recipeTier voltage tier of the recipe + * @param machineTier machine tier + * @param recipeLength max duration of the recipe + */ + private void addChancedFluidOutputLine(@NotNull ChancedFluidOutput chancedFluidOutput, + ChanceBoostFunction boostFunction, + int recipeTier, int machineTier, int recipeLength) { + var stack = chancedFluidOutput.getIngredient(); + IKey name = KeyUtil.fluid(TextFormatting.AQUA, stack); + IKey amount = KeyUtil.number(TextFormatting.GOLD, stack.amount); + IKey rate = KeyUtil.string(TextFormatting.WHITE, + formatRecipeRate(getSyncer().syncInt(recipeLength), stack.amount)); + + addKey(new GTObjectDrawable(chancedFluidOutput, stack.amount) + .setBoostFunction(entry -> boostFunction.getBoostedChance(entry, recipeTier, machineTier)) + .asIcon() + .asHoverable() + .addTooltipLine(formatRecipeData(name, amount, rate)), Operation.ADD); + // addKey(IKey.SPACE, Operation.ADD); } private static String formatRecipeRate(int recipeLength, long amount) { diff --git a/src/main/java/gregtech/api/mui/GTByteBufAdapters.java b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java new file mode 100644 index 00000000000..661d4685618 --- /dev/null +++ b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java @@ -0,0 +1,53 @@ +package gregtech.api.mui; + +import gregtech.api.recipes.chance.output.impl.ChancedFluidOutput; +import gregtech.api.recipes.chance.output.impl.ChancedItemOutput; + +import net.minecraft.network.PacketBuffer; + +import com.cleanroommc.modularui.utils.serialization.IByteBufAdapter; +import com.cleanroommc.modularui.utils.serialization.IByteBufDeserializer; +import com.cleanroommc.modularui.utils.serialization.IByteBufSerializer; +import com.cleanroommc.modularui.utils.serialization.IEquals; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Objects; + +public class GTByteBufAdapters { + + public static final IByteBufAdapter CHANCED_ITEM_OUTPUT = makeAdapter( + ChancedItemOutput::fromBuffer, ChancedItemOutput::toBuffer); + + public static final IByteBufAdapter CHANCED_FLUID_OUTPUT = makeAdapter( + ChancedFluidOutput::fromBuffer, ChancedFluidOutput::toBuffer); + + public static IByteBufAdapter makeAdapter(@NotNull IByteBufDeserializer deserializer, + @NotNull IByteBufSerializer serializer) { + return makeAdapter(deserializer, serializer, Objects::equals); + } + + public static IByteBufAdapter makeAdapter(@NotNull IByteBufDeserializer deserializer, + @NotNull IByteBufSerializer serializer, + @Nullable IEquals equals) { + final IEquals tester = equals != null ? equals : IEquals.defaultTester(); + return new IByteBufAdapter() { + + @Override + public T deserialize(PacketBuffer buffer) throws IOException { + return deserializer.deserialize(buffer); + } + + @Override + public void serialize(PacketBuffer buffer, T u) throws IOException { + serializer.serialize(buffer, u); + } + + @Override + public boolean areEqual(@NotNull T t1, @NotNull T t2) { + return tester.areEqual(t1, t2); + } + }; + } +} diff --git a/src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java deleted file mode 100644 index 1884144f79d..00000000000 --- a/src/main/java/gregtech/api/mui/drawable/GTFluidDrawable.java +++ /dev/null @@ -1,65 +0,0 @@ -package gregtech.api.mui.drawable; - -import net.minecraftforge.fluids.FluidStack; - -import com.cleanroommc.modularui.api.drawable.IDrawable; -import com.cleanroommc.modularui.drawable.GuiDraw; -import com.cleanroommc.modularui.drawable.Icon; -import com.cleanroommc.modularui.drawable.text.TextRenderer; -import com.cleanroommc.modularui.screen.viewport.GuiContext; -import com.cleanroommc.modularui.theme.WidgetTheme; -import com.cleanroommc.modularui.utils.Alignment; -import com.cleanroommc.modularui.utils.Color; -import com.cleanroommc.modularui.utils.NumberFormat; -import com.cleanroommc.modularui.widget.Widget; - -public class GTFluidDrawable implements IDrawable { - - private FluidStack stack; - private long amount; - private final TextRenderer renderer = new TextRenderer(); - - public GTFluidDrawable(FluidStack stack, long amount) { - this.stack = stack; - this.amount = amount; - } - - public GTFluidDrawable(FluidStack stack) { - this.stack = stack; - } - - public GTFluidDrawable() {} - - { - renderer.setScale(0.5f); - renderer.setShadow(true); - renderer.setColor(Color.WHITE.main); - } - - @Override - public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { - GuiDraw.drawFluidTexture(this.stack, x, y, width, height, 0); - String amountText = NumberFormat.formatWithMaxDigits(amount, 3) + "L"; - renderer.setAlignment(Alignment.BottomRight, width - 1, height - 1); - renderer.setPos(x + 1, y + 1); - renderer.draw(amountText); - } - - public void setAmount(long amount) { - this.amount = amount; - } - - public void setStack(FluidStack stack) { - this.stack = stack; - } - - @Override - public Icon asIcon() { - return IDrawable.super.asIcon().size(16); - } - - @Override - public Widget asWidget() { - return IDrawable.super.asWidget().size(16); - } -} diff --git a/src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java deleted file mode 100644 index 040f4892058..00000000000 --- a/src/main/java/gregtech/api/mui/drawable/GTItemDrawable.java +++ /dev/null @@ -1,65 +0,0 @@ -package gregtech.api.mui.drawable; - -import net.minecraft.item.ItemStack; - -import com.cleanroommc.modularui.api.drawable.IDrawable; -import com.cleanroommc.modularui.drawable.GuiDraw; -import com.cleanroommc.modularui.drawable.Icon; -import com.cleanroommc.modularui.drawable.text.TextRenderer; -import com.cleanroommc.modularui.screen.viewport.GuiContext; -import com.cleanroommc.modularui.theme.WidgetTheme; -import com.cleanroommc.modularui.utils.Alignment; -import com.cleanroommc.modularui.utils.Color; -import com.cleanroommc.modularui.utils.NumberFormat; -import com.cleanroommc.modularui.widget.Widget; - -public class GTItemDrawable implements IDrawable { - - private ItemStack stack; - private long amount; - private final TextRenderer renderer = new TextRenderer(); - - public GTItemDrawable(ItemStack stack, long amount) { - this.stack = stack; - this.amount = amount; - } - - public GTItemDrawable(ItemStack stack) { - this.stack = stack; - } - - public GTItemDrawable() {} - - { - renderer.setScale(0.5f); - renderer.setShadow(true); - renderer.setColor(Color.WHITE.main); - } - - @Override - public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { - GuiDraw.drawItem(this.stack, x, y, width, height); - String amountText = NumberFormat.formatWithMaxDigits(amount, 3); - renderer.setAlignment(Alignment.BottomRight, width - 1, height - 1); - renderer.setPos(x + 1, y + 1); - renderer.draw(amountText); - } - - public void setAmount(long amount) { - this.amount = amount; - } - - public void setStack(ItemStack stack) { - this.stack = stack; - } - - @Override - public Icon asIcon() { - return IDrawable.super.asIcon().size(16); - } - - @Override - public Widget asWidget() { - return IDrawable.super.asWidget().size(16); - } -} diff --git a/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java new file mode 100644 index 00000000000..af176b14b1d --- /dev/null +++ b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java @@ -0,0 +1,81 @@ +package gregtech.api.mui.drawable; + +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.recipes.chance.boost.BoostableChanceEntry; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.drawable.Icon; +import com.cleanroommc.modularui.drawable.text.TextRenderer; +import com.cleanroommc.modularui.screen.viewport.GuiContext; +import com.cleanroommc.modularui.theme.WidgetTheme; +import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.utils.Color; +import com.cleanroommc.modularui.utils.NumberFormat; +import com.cleanroommc.modularui.widget.Widget; + +import java.util.function.Function; + +public class GTObjectDrawable implements IDrawable { + + private static final TextRenderer renderer = new TextRenderer(); + + private final Object object; + private final long amount; + private Function, Integer> boostFunction; + + public GTObjectDrawable(Object object, long amount) { + this.object = object; + this.amount = amount; + } + + public GTObjectDrawable setBoostFunction(Function, Integer> boostFunction) { + this.boostFunction = boostFunction; + return this; + } + + static { + renderer.setScale(0.5f); + renderer.setShadow(true); + renderer.setColor(Color.WHITE.main); + } + + @Override + public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { + renderer.setAlignment(Alignment.BottomRight, width - 1, height - 1); + drawObject(object, context, x, y, width, height, widgetTheme); + renderer.setPos(x + 1, y + 1); + String amount = NumberFormat.formatWithMaxDigits(this.amount, 3); + if (object instanceof FluidStack) amount += "L"; + renderer.draw(amount); + } + + private void drawObject(Object object, GuiContext context, int x, int y, int width, int height, + WidgetTheme widgetTheme) { + if (object instanceof ItemStack stack) { + GTGuiTextures.SLOT.draw(context, x, y, width, height, widgetTheme); + GuiDraw.drawItem(stack, x + 1, y + 1, width - 1, height - 1); + } else if (object instanceof FluidStack stack) { + GTGuiTextures.FLUID_SLOT.draw(context, x, y, width, height, widgetTheme); + GuiDraw.drawFluidTexture(stack, x + 1, y + 1, width - 1, height - 1, 0); + } else if (object instanceof BoostableChanceEntryentry) { + drawObject(entry.getIngredient(), context, x, y, width, height, widgetTheme); + String chance = "~" + this.boostFunction.apply(entry) / 100 + "%"; + renderer.setPos(x + 1, y - 3); + renderer.draw(chance); + } + } + + @Override + public Icon asIcon() { + return IDrawable.super.asIcon().size(18); + } + + @Override + public Widget asWidget() { + return IDrawable.super.asWidget().size(18); + } +} diff --git a/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedFluidOutput.java b/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedFluidOutput.java index 81a145fe1c8..5d59e6cebfa 100644 --- a/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedFluidOutput.java +++ b/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedFluidOutput.java @@ -2,10 +2,14 @@ import gregtech.api.recipes.chance.output.BoostableChanceOutput; +import net.minecraft.network.PacketBuffer; import net.minecraftforge.fluids.FluidStack; +import com.cleanroommc.modularui.network.NetworkUtils; import org.jetbrains.annotations.NotNull; +import java.util.Objects; + /** * Implementation for a chanced fluid output */ @@ -29,4 +33,15 @@ public String toString() { ", chanceBoost=" + getChanceBoost() + '}'; } + + public static ChancedFluidOutput fromBuffer(PacketBuffer buffer) { + return new ChancedFluidOutput(Objects.requireNonNull(NetworkUtils.readFluidStack(buffer)), buffer.readVarInt(), + buffer.readVarInt()); + } + + public static void toBuffer(PacketBuffer buffer, ChancedFluidOutput value) { + NetworkUtils.writeFluidStack(buffer, value.getIngredient()); + buffer.writeVarInt(value.getChance()); + buffer.writeVarInt(value.getChanceBoost()); + } } diff --git a/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedItemOutput.java b/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedItemOutput.java index b49e640d942..a186a01b392 100644 --- a/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedItemOutput.java +++ b/src/main/java/gregtech/api/recipes/chance/output/impl/ChancedItemOutput.java @@ -4,7 +4,9 @@ import gregtech.api.util.GTStringUtils; import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import com.cleanroommc.modularui.network.NetworkUtils; import org.jetbrains.annotations.NotNull; /** @@ -29,4 +31,14 @@ public String toString() { ", chanceBoost=" + getChanceBoost() + '}'; } + + public static ChancedItemOutput fromBuffer(PacketBuffer buffer) { + return new ChancedItemOutput(NetworkUtils.readItemStack(buffer), buffer.readVarInt(), buffer.readVarInt()); + } + + public static void toBuffer(PacketBuffer buffer, ChancedItemOutput value) { + NetworkUtils.writeItemStack(buffer, value.getIngredient()); + buffer.writeVarInt(value.getChance()); + buffer.writeVarInt(value.getChanceBoost()); + } } From 767f32371c3fd226f4300e6d4280e1c20ecf2fdc Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 1 Mar 2025 23:36:01 -0700 Subject: [PATCH 06/12] fix space not incrementing x --- .../mixins/mui2/RichTextCompilerMixin.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java b/src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java index fbb826a151c..79c44c7d20b 100644 --- a/src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java +++ b/src/main/java/gregtech/mixins/mui2/RichTextCompilerMixin.java @@ -1,13 +1,28 @@ package gregtech.mixins.mui2; +import net.minecraft.client.gui.FontRenderer; + +import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.drawable.text.RichTextCompiler; +import com.llamalad7.mixinextras.sugar.Local; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; @Mixin(value = RichTextCompiler.class, remap = false) public class RichTextCompilerMixin { + @Shadow + private int x; + + @Shadow + private FontRenderer fr; + @ModifyArg(method = "trimRight", at = @At(value = "INVOKE", target = "Ljava/lang/String;substring(II)Ljava/lang/String;"), @@ -15,4 +30,12 @@ public class RichTextCompilerMixin { private static int fixTrim(int beginIndex) { return beginIndex + 1; } + + @Inject(method = "compile", + at = @At(value = "INVOKE", + target = "Lcom/cleanroommc/modularui/drawable/text/RichTextCompiler;addLineElement(Ljava/lang/Object;)V", + ordinal = 0)) + private void moveXString(List raw, CallbackInfo ci, @Local IKey key) { + x += fr.getStringWidth(key.get()); + } } From 36d575ff82142ce2632eb209966b659a745d7e75 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 2 Mar 2025 11:42:45 -0700 Subject: [PATCH 07/12] fix rebase --- .../api/metatileentity/multiblock/ui/MultiblockUIBuilder.java | 3 ++- src/main/java/gregtech/api/mui/GTByteBufAdapters.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java index 22c55f86b97..3364ce0a7b4 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java @@ -529,7 +529,8 @@ public MultiblockUIBuilder addRecipeOutputLine(AbstractRecipeLogic arl, int maxL if (getSyncer().syncBoolean(recipe == null)) return this; if (getSyncer().syncBoolean(arl.getRecipeMap() == null)) return this; - long eut = getSyncer().syncLong(recipe == null ? 0 : recipe.getEUt()); + //noinspection DataFlowIssue + long eut = getSyncer().syncLong(() -> recipe.getEUt()); long maxVoltage = getSyncer().syncLong(arl.getMaximumOverclockVoltage()); List itemOutputs = new ArrayList<>(); diff --git a/src/main/java/gregtech/api/mui/GTByteBufAdapters.java b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java index 661d4685618..bf8376aaf10 100644 --- a/src/main/java/gregtech/api/mui/GTByteBufAdapters.java +++ b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java @@ -32,7 +32,7 @@ public static IByteBufAdapter makeAdapter(@NotNull IByteBufDeserializer serializer, @Nullable IEquals equals) { final IEquals tester = equals != null ? equals : IEquals.defaultTester(); - return new IByteBufAdapter() { + return new IByteBufAdapter<>() { @Override public T deserialize(PacketBuffer buffer) throws IOException { From aff89826ff3e722c55c98a699ff00ee984ac911b Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 2 Mar 2025 11:52:16 -0700 Subject: [PATCH 08/12] don't draw amount if it is 1 only shift % up if amount is > 1 --- .../multiblock/ui/MultiblockUIBuilder.java | 2 +- .../gregtech/api/mui/drawable/GTObjectDrawable.java | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java index 3364ce0a7b4..73903a160f8 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIBuilder.java @@ -529,7 +529,7 @@ public MultiblockUIBuilder addRecipeOutputLine(AbstractRecipeLogic arl, int maxL if (getSyncer().syncBoolean(recipe == null)) return this; if (getSyncer().syncBoolean(arl.getRecipeMap() == null)) return this; - //noinspection DataFlowIssue + // noinspection DataFlowIssue long eut = getSyncer().syncLong(() -> recipe.getEUt()); long maxVoltage = getSyncer().syncLong(arl.getMaximumOverclockVoltage()); diff --git a/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java index af176b14b1d..c78a7981593 100644 --- a/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java +++ b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java @@ -47,10 +47,12 @@ public GTObjectDrawable setBoostFunction(Function, Integ public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { renderer.setAlignment(Alignment.BottomRight, width - 1, height - 1); drawObject(object, context, x, y, width, height, widgetTheme); - renderer.setPos(x + 1, y + 1); - String amount = NumberFormat.formatWithMaxDigits(this.amount, 3); - if (object instanceof FluidStack) amount += "L"; - renderer.draw(amount); + if (amount > 1) { + renderer.setPos(x + 1, y + 1); + String amount = NumberFormat.formatWithMaxDigits(this.amount, 3); + if (object instanceof FluidStack) amount += "L"; + renderer.draw(amount); + } } private void drawObject(Object object, GuiContext context, int x, int y, int width, int height, @@ -64,7 +66,8 @@ private void drawObject(Object object, GuiContext context, int x, int y, int wid } else if (object instanceof BoostableChanceEntryentry) { drawObject(entry.getIngredient(), context, x, y, width, height, widgetTheme); String chance = "~" + this.boostFunction.apply(entry) / 100 + "%"; - renderer.setPos(x + 1, y - 3); + if (amount > 1) y -= 4; + renderer.setPos(x + 1, y + 1); renderer.draw(chance); } } From 7ec507e384dc372858d457c9d76b35a64cbe4dfc Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:04:15 -0700 Subject: [PATCH 09/12] fix object rendering --- src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java index c78a7981593..2e6f68c591f 100644 --- a/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java +++ b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java @@ -59,10 +59,10 @@ private void drawObject(Object object, GuiContext context, int x, int y, int wid WidgetTheme widgetTheme) { if (object instanceof ItemStack stack) { GTGuiTextures.SLOT.draw(context, x, y, width, height, widgetTheme); - GuiDraw.drawItem(stack, x + 1, y + 1, width - 1, height - 1); + GuiDraw.drawItem(stack, x + 1, y + 1, width - 2, height - 2); } else if (object instanceof FluidStack stack) { GTGuiTextures.FLUID_SLOT.draw(context, x, y, width, height, widgetTheme); - GuiDraw.drawFluidTexture(stack, x + 1, y + 1, width - 1, height - 1, 0); + GuiDraw.drawFluidTexture(stack, x + 1, y + 1, width - 2, height - 2, 0); } else if (object instanceof BoostableChanceEntryentry) { drawObject(entry.getIngredient(), context, x, y, width, height, widgetTheme); String chance = "~" + this.boostFunction.apply(entry) / 100 + "%"; From d82556dc08a25706359b4a38b81e26751205d54d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:07:30 -0700 Subject: [PATCH 10/12] move big int adapter to GTByteBufAdapters use iequals default tester --- .../api/metatileentity/multiblock/ui/UISyncer.java | 10 +++------- .../java/gregtech/api/mui/GTByteBufAdapters.java | 13 +++++++------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/UISyncer.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/UISyncer.java index cc96b789138..58cb0eee1bf 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/UISyncer.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/UISyncer.java @@ -1,10 +1,11 @@ package gregtech.api.metatileentity.multiblock.ui; +import gregtech.api.mui.GTByteBufAdapters; + import com.cleanroommc.modularui.utils.serialization.ByteBufAdapters; import com.cleanroommc.modularui.utils.serialization.IByteBufAdapter; import com.cleanroommc.modularui.utils.serialization.IByteBufDeserializer; import com.cleanroommc.modularui.utils.serialization.IByteBufSerializer; -import com.cleanroommc.modularui.utils.serialization.IEquals; import org.jetbrains.annotations.NotNull; import java.math.BigInteger; @@ -16,11 +17,6 @@ public interface UISyncer { - IByteBufAdapter BIG_INT = ByteBufAdapters.makeAdapter( - buffer -> new BigInteger(buffer.readByteArray()), - (buffer, value) -> buffer.writeByteArray(value.toByteArray()), - IEquals.defaultTester()); - /** * Calls the supplier server side only so there's no potential NPEs for the client * @@ -98,7 +94,7 @@ default float syncFloat(float initial) { } default BigInteger syncBigInt(BigInteger initial) { - return syncObject(initial, BIG_INT); + return syncObject(initial, GTByteBufAdapters.BIG_INT); } T syncObject(T initial, IByteBufSerializer serializer, IByteBufDeserializer deserializer); diff --git a/src/main/java/gregtech/api/mui/GTByteBufAdapters.java b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java index bf8376aaf10..86757aae225 100644 --- a/src/main/java/gregtech/api/mui/GTByteBufAdapters.java +++ b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java @@ -5,15 +5,12 @@ import net.minecraft.network.PacketBuffer; -import com.cleanroommc.modularui.utils.serialization.IByteBufAdapter; -import com.cleanroommc.modularui.utils.serialization.IByteBufDeserializer; -import com.cleanroommc.modularui.utils.serialization.IByteBufSerializer; -import com.cleanroommc.modularui.utils.serialization.IEquals; +import com.cleanroommc.modularui.utils.serialization.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.Objects; +import java.math.BigInteger; public class GTByteBufAdapters { @@ -23,9 +20,13 @@ public class GTByteBufAdapters { public static final IByteBufAdapter CHANCED_FLUID_OUTPUT = makeAdapter( ChancedFluidOutput::fromBuffer, ChancedFluidOutput::toBuffer); + public static final IByteBufAdapter BIG_INT = makeAdapter( + buffer -> new BigInteger(buffer.readByteArray()), + (buffer, value) -> buffer.writeByteArray(value.toByteArray())); + public static IByteBufAdapter makeAdapter(@NotNull IByteBufDeserializer deserializer, @NotNull IByteBufSerializer serializer) { - return makeAdapter(deserializer, serializer, Objects::equals); + return makeAdapter(deserializer, serializer, IEquals.defaultTester()); } public static IByteBufAdapter makeAdapter(@NotNull IByteBufDeserializer deserializer, From 901c077ddcd2dda4595b2c0ef66af51c7c918467 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:28:29 -0700 Subject: [PATCH 11/12] make recipe outputs open jei page create accessor for icon's drawable --- .../api/mui/drawable/GTObjectDrawable.java | 7 +++++++ .../mui/widget/ScrollableTextWidget.java | 21 ++++++++++++++++++- .../gregtech/mixins/mui2/IconAccessor.java | 13 ++++++++++++ src/main/resources/mixins.gregtech.mui2.json | 1 + 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/main/java/gregtech/mixins/mui2/IconAccessor.java diff --git a/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java index 2e6f68c591f..775c1b2cd24 100644 --- a/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java +++ b/src/main/java/gregtech/api/mui/drawable/GTObjectDrawable.java @@ -81,4 +81,11 @@ public Icon asIcon() { public Widget asWidget() { return IDrawable.super.asWidget().size(18); } + + public Object getObject() { + if (object instanceof BoostableChanceEntryentry) { + return entry.getIngredient(); + } + return object; + } } diff --git a/src/main/java/gregtech/common/mui/widget/ScrollableTextWidget.java b/src/main/java/gregtech/common/mui/widget/ScrollableTextWidget.java index 55e82d4f2b0..12ee6435302 100644 --- a/src/main/java/gregtech/common/mui/widget/ScrollableTextWidget.java +++ b/src/main/java/gregtech/common/mui/widget/ScrollableTextWidget.java @@ -1,5 +1,8 @@ package gregtech.common.mui.widget; +import gregtech.api.mui.drawable.GTObjectDrawable; +import gregtech.mixins.mui2.IconAccessor; + import com.cleanroommc.modularui.api.GuiAxis; import com.cleanroommc.modularui.api.drawable.IHoverable; import com.cleanroommc.modularui.api.drawable.IRichTextBuilder; @@ -7,9 +10,11 @@ import com.cleanroommc.modularui.api.layout.IViewportStack; import com.cleanroommc.modularui.api.widget.IGuiAction; import com.cleanroommc.modularui.api.widget.Interactable; +import com.cleanroommc.modularui.drawable.DelegateIcon; import com.cleanroommc.modularui.drawable.Stencil; import com.cleanroommc.modularui.drawable.text.RichText; import com.cleanroommc.modularui.drawable.text.TextRenderer; +import com.cleanroommc.modularui.integration.jei.JeiIngredientProvider; import com.cleanroommc.modularui.screen.ModularScreen; import com.cleanroommc.modularui.screen.RichTooltip; import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; @@ -24,12 +29,14 @@ import java.util.function.Consumer; public class ScrollableTextWidget extends Widget - implements IRichTextBuilder, Interactable, IViewport { + implements IRichTextBuilder, Interactable, IViewport, + JeiIngredientProvider { private final RichText text = new RichText(); private Consumer builder; private boolean dirty = false; private boolean autoUpdate = false; + private Object lastIngredient; private final ScrollArea scroll = new ScrollArea(); private final TextRenderer renderer = new TextRenderer(); @@ -66,6 +73,13 @@ public void drawForeground(ModularGuiContext context) { tooltip.draw(context); } } + if (getHoveredElement() instanceof DelegateIcon delegateIcon && + delegateIcon.findRootDelegate() instanceof IconAccessor accessor && + accessor.getDrawable() instanceof GTObjectDrawable objectDrawable) { + lastIngredient = objectDrawable.getObject(); + } else { + lastIngredient = null; + } } @Override @@ -207,4 +221,9 @@ public ScrollableTextWidget textBuilder(Consumer builder) { markDirty(); return this; } + + @Override + public @Nullable Object getIngredient() { + return this.lastIngredient; + } } diff --git a/src/main/java/gregtech/mixins/mui2/IconAccessor.java b/src/main/java/gregtech/mixins/mui2/IconAccessor.java new file mode 100644 index 00000000000..59e2ba009e4 --- /dev/null +++ b/src/main/java/gregtech/mixins/mui2/IconAccessor.java @@ -0,0 +1,13 @@ +package gregtech.mixins.mui2; + +import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.drawable.Icon; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value = Icon.class, remap = false) +public interface IconAccessor { + + @Accessor() + IDrawable getDrawable(); +} diff --git a/src/main/resources/mixins.gregtech.mui2.json b/src/main/resources/mixins.gregtech.mui2.json index a13b45e2493..dc9772d257f 100644 --- a/src/main/resources/mixins.gregtech.mui2.json +++ b/src/main/resources/mixins.gregtech.mui2.json @@ -8,6 +8,7 @@ "maxShiftBy": 10 }, "mixins": [ + "IconAccessor", "ModularPanelMixin", "RichTextCompilerMixin" ], From 20231710be7f30065b4e90801da969bb58a8ce30 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:47:10 -0700 Subject: [PATCH 12/12] delete unused methods --- .../api/capability/impl/AbstractRecipeLogic.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java index 5b587f33b20..90c43f781a0 100644 --- a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java +++ b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java @@ -1178,16 +1178,6 @@ public void setOverclockTier(final int tier) { setMaximumOverclockVoltage(GTValues.V[tier]); } - @NotNull - public List getItemOutputs() { - return itemOutputs; - } - - @NotNull - public List getFluidOutputs() { - return fluidOutputs; - } - /** * Used to reset cached values in the Recipe Logic on events such as multiblock structure deformation */