From 5042a398912e97d8fbe4066a64514d489afa8f98 Mon Sep 17 00:00:00 2001 From: YoungOnion <39562198+YoungOnionMC@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:06:33 -0700 Subject: [PATCH 1/3] skip 8625aa7f, 8fa50cab, port 1.20/1.12 branches up to 18/2/2026 --- dependencies.gradle | 4 +- gradle/libs.versions.toml | 4 +- .../java/com/gregtechceu/gtceu/GTCEu.java | 5 - .../recipe/FluidRecipeCapability.java | 10 +- .../recipe/ItemRecipeCapability.java | 10 +- .../gtceu/api/data/tag/TagPrefix.java | 2 +- .../api/gui/widget/PatternPreviewWidget.java | 2 +- .../gtceu/api/gui/widget/SlotWidget.java | 8 +- .../gtceu/api/gui/widget/TankWidget.java | 8 +- .../gtceu/api/mui/base/IPanelHandler.java | 3 +- .../gtceu/api/mui/base/IUIHolder.java | 4 +- ...ettings.java => RecipeViewerSettings.java} | 38 +- .../gtceu/api/mui/base/layout/IViewport.java | 18 +- .../api/mui/base/layout/IViewportStack.java | 2 + .../gtceu/api/mui/base/widget/IDraggable.java | 10 +- .../api/mui/base/widget/IGuiElement.java | 115 ------ .../api/mui/base/widget/IParentWidget.java | 12 - .../api/mui/base/widget/IPositioned.java | 13 +- .../gtceu/api/mui/base/widget/ISynced.java | 53 +-- .../gtceu/api/mui/base/widget/IWidget.java | 38 +- .../gtceu/api/mui/drawable/GuiDraw.java | 84 ++++- .../gtceu/api/mui/drawable/UITexture.java | 7 + .../mui/drawable/text/RichTextCompiler.java | 9 +- .../gtceu/api/mui/factory/ClientGUI.java | 22 +- .../gtceu/api/mui/factory/GuiManager.java | 4 +- .../mui/factory/PlayerInventoryUIFactory.java | 4 +- .../gtceu/api/mui/overlay/DebugOverlay.java | 66 ++-- .../gtceu/api/mui/overlay/OverlayHandler.java | 43 --- .../gtceu/api/mui/overlay/OverlayManager.java | 26 -- .../gtceu/api/mui/overlay/OverlayStack.java | 10 - .../gtceu/api/mui/schema/ArraySchema.java | 11 +- .../gtceu/api/mui/theme/ThemeManager.java | 19 +- .../gtceu/api/mui/utils/Color.java | 88 ++--- .../api/mui/utils/HoveredWidgetList.java | 6 +- .../gtceu/api/mui/utils/RectangleF.java | 95 +++++ .../gtceu/api/mui/utils/WidgetUtil.java | 24 -- .../gtceu/api/mui/value/ObjectValue.java | 3 - .../value/sync/AbstractGenericSyncValue.java | 67 ++-- .../value/sync/DynamicLinkedSyncHandler.java | 14 +- .../mui/value/sync/DynamicSyncHandler.java | 2 +- .../sync/GenericCollectionSyncHandler.java | 6 +- .../value/sync/GenericListSyncHandler.java | 29 +- .../mui/value/sync/GenericMapSyncHandler.java | 39 +- .../mui/value/sync/GenericSetSyncHandler.java | 26 +- .../api/mui/value/sync/GenericSyncValue.java | 317 +++++++++++------ .../api/mui/value/sync/ISyncRegistrar.java | 12 + .../mui/value/sync/ItemSlotSyncHandler.java | 9 + .../mui/value/sync/ModularSyncManager.java | 6 - .../api/mui/value/sync/PanelSyncManager.java | 23 +- .../gtceu/api/mui/value/sync/SyncHandler.java | 7 +- .../api/mui/value/sync/SyncHandlers.java | 2 +- .../api/mui/widget/AbstractScrollWidget.java | 27 +- .../widget/DelegatingSingleChildWidget.java | 23 -- .../gtceu/api/mui/widget/DragHandle.java | 19 +- .../gtceu/api/mui/widget/DraggableWidget.java | 4 +- .../gtceu/api/mui/widget/Widget.java | 57 +-- .../gtceu/api/mui/widget/WidgetTree.java | 7 +- .../api/mui/widget/scroll/ScrollArea.java | 6 +- .../api/mui/widget/sizer/DimensionSizer.java | 9 + .../api/mui/widget/sizer/StandardResizer.java | 21 +- .../widgets/AbstractFluidDisplayWidget.java | 6 +- .../api/mui/widgets/ColorPickerDialog.java | 4 +- .../gtceu/api/mui/widgets/Expandable.java | 16 - .../api/mui/widgets/ItemDisplayWidget.java | 6 +- .../gtceu/api/mui/widgets/ListWidget.java | 1 + .../gtceu/api/mui/widgets/SchemaWidget.java | 2 +- .../api/mui/widgets/SlotGroupWidget.java | 24 +- .../gtceu/api/mui/widgets/TextWidget.java | 5 + .../gtceu/api/mui/widgets/ToggleButton.java | 7 + .../gtceu/api/mui/widgets/layout/Flow.java | 4 +- .../mui/widgets/menu/AbstractMenuButton.java | 22 +- .../gtceu/api/mui/widgets/menu/Menu.java | 16 +- .../gtceu/api/mui/widgets/menu/MenuPanel.java | 19 + .../gtceu/api/mui/widgets/slot/FluidSlot.java | 43 +-- .../gtceu/api/mui/widgets/slot/ItemSlot.java | 4 +- .../api/mui/widgets/slot/ModularSlot.java | 38 +- .../api/mui/widgets/slot/PhantomItemSlot.java | 6 +- .../textfield/BaseTextFieldWidget.java | 2 + .../widgets/textfield/TextFieldHandler.java | 1 + .../widgets/textfield/TextFieldWidget.java | 48 ++- .../gregtechceu/gtceu/client/ClientProxy.java | 19 +- .../gtceu/client/GuiSpriteManager.java | 49 +++ .../gtceu/client/ModClientEventListener.java | 30 ++ .../mui/component/FormattedTextContents.java | 23 ++ .../mui/screen/ClientScreenHandler.java | 66 +++- .../mui/screen/ContainerScreenWrapper.java | 2 +- .../mui/screen/CustomModularScreen.java | 14 - .../mui/screen/ModularContainerMenu.java | 10 +- .../gtceu/client/mui/screen/ModularPanel.java | 22 +- .../client/mui/screen/ModularScreen.java | 24 +- ...mpl.java => RecipeViewerSettingsImpl.java} | 50 +-- .../gtceu/client/mui/screen/UISettings.java | 10 +- .../mui/screen/viewport/GuiViewportStack.java | 54 ++- .../mui/screen/viewport/LocatedWidget.java | 5 + .../screen/viewport/ModularGuiContext.java | 77 +--- .../screen/viewport/TransformationMatrix.java | 71 +++- .../gregtechceu/gtceu/common/CommonProxy.java | 7 +- .../gtceu/common/commands/GTCommands.java | 9 + .../gtceu/common/data/GCYMRecipeTypes.java | 2 +- .../gtceu/common/data/GTMenuTypes.java | 26 +- .../gtceu/common/data/GTRecipeTypes.java | 8 +- .../gtceu/common/data/mui/GTMuiWidgets.java | 4 +- .../data/mui/GTSingleblockMachinePanels.java | 6 +- .../electric/BatteryBufferMachine.java | 2 +- .../machine/electric/BlockBreakerMachine.java | 2 +- .../machine/electric/ChargerMachine.java | 2 +- .../machine/electric/FisherMachine.java | 2 +- .../electric/ItemCollectorMachine.java | 2 +- .../common/machine/electric/MinerMachine.java | 2 +- .../machine/muimachine/TestMuiMachine.java | 2 +- .../multiblock/part/DualHatchPartMachine.java | 4 +- .../part/FluidHatchPartMachine.java | 2 +- .../multiblock/primitive/CokeOvenMachine.java | 2 +- .../multiblock/steam/LargeBoilerMachine.java | 2 +- .../common/machine/storage/BufferMachine.java | 2 +- .../common/network/ModularNetworkSide.java | 1 + .../core/mixins/client/MinecraftMixin.java | 18 + .../ae2/gui/widget/mui/AEConfigWidget.java | 6 +- .../emi/{handler => }/EmiStackConverter.java | 16 +- .../gtceu/integration/emi/GTEMIPlugin.java | 10 +- .../circuit/GTProgrammedCircuitCategory.java | 2 +- .../emi/handler/EmiScreenHandler.java | 34 +- .../emi/oreprocessing/GTEmiOreProcessing.java | 2 +- .../emi/orevein/GTBedrockFluid.java | 2 +- .../integration/emi/orevein/GTBedrockOre.java | 2 +- .../integration/emi/orevein/GTEmiOreVein.java | 2 +- .../integration/emi/recipe/GTEmiRecipe.java | 2 +- .../integration/emi/recipe/GTEmiRecipe2.java | 232 ++++++++++++ .../gtceu/integration/jei/GTJEIPlugin.java | 21 +- .../integration/jei/GTJeiProperties.java | 73 ++++ .../{handler => }/GhostIngredientTarget.java | 9 +- .../circuit/GTProgrammedCircuitCategory.java | 2 +- .../jei/handler/JEIContainerHandler.java | 80 ----- .../jei/handler/JEIScreenHandler.java | 72 ---- .../jei/handler/JeiContainerHandler.java | 106 ++++++ .../jei/handler/JeiScreenHandler.java | 177 ++++++++++ .../GTOreProcessingInfoWrapper.java | 2 +- .../orevein/GTBedrockFluidInfoCategory.java | 2 +- .../orevein/GTBedrockFluidInfoWrapper.java | 2 +- .../jei/orevein/GTBedrockOreInfoCategory.java | 2 +- .../jei/orevein/GTBedrockOreInfoWrapper.java | 2 +- .../jei/orevein/GTOreVeinInfoCategory.java | 2 +- .../jei/orevein/GTOreVeinInfoWrapper.java | 2 +- .../jei/recipe/GTRecipeJEICategory.java | 271 ++++++++++++-- .../jei/recipe/GTRecipeWrapper.java | 2 +- .../map/layer/builtin/OreRenderLayer.java | 2 +- .../recipeviewer/RecipeSlotRole.java | 26 ++ .../RecipeViewerScreenWrapper.java | 28 ++ .../RecipeViewerState.java} | 4 +- .../entry/EntryList.java | 2 +- .../entry/fluid/FluidEntryList.java | 4 +- .../entry/fluid/FluidHolderSetList.java | 2 +- .../entry/fluid/FluidStackList.java | 2 +- .../entry/fluid/FluidTagList.java | 2 +- .../entry/item/ItemEntryList.java | 4 +- .../entry/item/ItemHolderSetList.java | 2 +- .../entry/item/ItemStackList.java | 2 +- .../entry/item/ItemTagList.java | 2 +- .../handlers/GhostIngredientSlot.java | 9 +- .../handlers/IngredientProvider.java | 18 +- .../handlers/RecipeTransferError.java | 119 +++++++ .../handlers/RecipeTransferHandler.java | 31 ++ .../handlers/RecipeViewerHandler.java | 6 +- .../fluid/CycleFluidEntryHandler.java | 44 +-- .../handlers/fluid/EmptyFluidTank.java | 49 +++ .../handlers/item/CycleItemEntryHandler.java | 8 +- .../util/RecipeScreenRenderingUtil.java | 67 ++++ .../widgets/GTMuiRecipeWidget.java | 15 + .../widgets/GTOreByProduct.java | 14 +- .../widgets/GTOreByProductWidget.java | 10 +- .../widgets/GTOreVeinWidget.java | 2 +- .../widgets/GTProgrammedCircuitWidget.java | 2 +- .../widgets/GTRecipeWidget.java | 2 +- .../circuit/GTProgrammedCircuitCategory.java | 2 +- .../rei/handler/REIScreenHandler.java | 16 +- .../rei/handler/REIStackConverter.java | 12 +- .../oreprocessing/GTOreProcessingDisplay.java | 2 +- .../rei/orevein/GTBedrockFluidDisplay.java | 2 +- .../GTBedrockFluidDisplayCategory.java | 2 +- .../rei/orevein/GTBedrockOreDisplay.java | 2 +- .../orevein/GTBedrockOreDisplayCategory.java | 2 +- .../rei/orevein/GTOreVeinDisplay.java | 2 +- .../rei/orevein/GTOreVeinDisplayCategory.java | 2 +- .../rei/recipe/GTRecipeDisplay.java | 2 +- .../gtceu/utils/FormattingUtil.java | 10 - .../com/gregtechceu/gtceu/utils/GTMath.java | 104 +++--- .../gtceu/utils/IMultiFluidTankHandler.java | 9 + .../gtceu/utils/MultiFluidTankHandler.java | 3 + .../gtceu/utils/math/NumberFormat.java | 332 ++++++++++++++++++ .../gtceu/utils/math/ParseResult.java | 26 +- .../utils/math/PostfixPercentOperator.java | 30 ++ .../gtceu/utils/math/SIPrefix.java | 51 ++- .../gtceu/utils/memoization/GTMemoizer.java | 36 ++ .../utils/memoization/MemoizedSupplier.java | 20 +- .../network/ByteBufAdapters.java | 9 + 195 files changed, 3280 insertions(+), 1530 deletions(-) rename src/main/java/com/gregtechceu/gtceu/api/mui/base/{XeiSettings.java => RecipeViewerSettings.java} (70%) delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IGuiElement.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayHandler.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayManager.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/mui/utils/RectangleF.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/mui/utils/WidgetUtil.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/mui/widget/DelegatingSingleChildWidget.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/GuiSpriteManager.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/ModClientEventListener.java create mode 100644 src/main/java/com/gregtechceu/gtceu/client/mui/component/FormattedTextContents.java rename src/main/java/com/gregtechceu/gtceu/client/mui/screen/{XeiSettingsImpl.java => RecipeViewerSettingsImpl.java} (71%) rename src/main/java/com/gregtechceu/gtceu/integration/emi/{handler => }/EmiStackConverter.java (90%) create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe2.java create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/jei/GTJeiProperties.java rename src/main/java/com/gregtechceu/gtceu/integration/jei/{handler => }/GhostIngredientTarget.java (73%) delete mode 100644 src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIContainerHandler.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIScreenHandler.java create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiContainerHandler.java create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiScreenHandler.java create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeSlotRole.java create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeViewerScreenWrapper.java rename src/main/java/com/gregtechceu/gtceu/integration/{xei/XeiState.java => recipeviewer/RecipeViewerState.java} (80%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/EntryList.java (63%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/fluid/FluidEntryList.java (68%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/fluid/FluidHolderSetList.java (95%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/fluid/FluidStackList.java (94%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/fluid/FluidTagList.java (96%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/item/ItemEntryList.java (67%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/item/ItemHolderSetList.java (95%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/item/ItemStackList.java (94%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/entry/item/ItemTagList.java (96%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/handlers/GhostIngredientSlot.java (86%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/handlers/IngredientProvider.java (69%) create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferError.java create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferHandler.java rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/handlers/RecipeViewerHandler.java (92%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/handlers/fluid/CycleFluidEntryHandler.java (69%) create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/fluid/EmptyFluidTank.java rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/handlers/item/CycleItemEntryHandler.java (91%) create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/util/RecipeScreenRenderingUtil.java create mode 100644 src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTMuiRecipeWidget.java rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/widgets/GTOreByProduct.java (96%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/widgets/GTOreByProductWidget.java (95%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/widgets/GTOreVeinWidget.java (99%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/widgets/GTProgrammedCircuitWidget.java (95%) rename src/main/java/com/gregtechceu/gtceu/integration/{xei => recipeviewer}/widgets/GTRecipeWidget.java (99%) create mode 100644 src/main/java/com/gregtechceu/gtceu/utils/IMultiFluidTankHandler.java create mode 100644 src/main/java/com/gregtechceu/gtceu/utils/MultiFluidTankHandler.java create mode 100644 src/main/java/com/gregtechceu/gtceu/utils/math/NumberFormat.java create mode 100644 src/main/java/com/gregtechceu/gtceu/utils/math/PostfixPercentOperator.java diff --git a/dependencies.gradle b/dependencies.gradle index e350fea92d7..15a9f452b95 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -11,8 +11,8 @@ dependencies { jarJar(modApi(forge.configuration.get())) // Math Parser - jarJar(implementation(libs.mxparser.get())) - additionalRuntimeClasspath(libs.mxparser.get()) + jarJar(implementation(libs.evalEx.get())) + additionalRuntimeClasspath(libs.evalEx.get()) // Mixin (& Extras) annotationProcessor(variantOf(libs.mixin) { classifier("processor") }) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3824a10ea3d..880fc1a6e45 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ lombok = "8.14" jetbrains-annotations = "26.0.1" renderNurse = "0.0.12" mixin = "0.8.7" -mxparser = "6.1.0" +evalEx = "3.6.0" [libraries] minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } @@ -18,7 +18,7 @@ minecraftForge = { module = "net.minecraftforge:forge", version.ref = " jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" } renderNurse = { module = "net.neoforged:render-nurse", version.ref = "renderNurse" } mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" } -mxparser = { module = "org.mariuszgromada.math:MathParser.org-mXparser", version.ref = "mxparser" } +evalEx = { module = "com.ezylang:EvalEx", version.ref = "evalEx" } [plugins] modDevGradle = { id = "net.neoforged.moddev.legacyforge", version.ref = "modDevGradle" } diff --git a/src/main/java/com/gregtechceu/gtceu/GTCEu.java b/src/main/java/com/gregtechceu/gtceu/GTCEu.java index 2485ab7b8c8..e7b1de43d39 100644 --- a/src/main/java/com/gregtechceu/gtceu/GTCEu.java +++ b/src/main/java/com/gregtechceu/gtceu/GTCEu.java @@ -21,7 +21,6 @@ import me.shedaniel.rei.api.client.REIRuntime; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.mariuszgromada.math.mxparser.License; import java.nio.file.Path; @@ -33,10 +32,6 @@ public class GTCEu { public static final String NAME = "GregTechCEu"; public static final Logger LOGGER = LogManager.getLogger(NAME); - static { - License.iConfirmNonCommercialUse("GTCEu"); - } - public static final Path GTCEU_FOLDER = getGameDir().resolve("gtceu"); public GTCEu() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java index 8f2e15d80e7..755a9c88955 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java @@ -17,11 +17,11 @@ import com.gregtechceu.gtceu.api.recipe.ui.GTRecipeTypeUI; import com.gregtechceu.gtceu.client.TooltipsHandler; import com.gregtechceu.gtceu.common.valueprovider.*; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidStackList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidTagList; -import com.gregtechceu.gtceu.integration.xei.handlers.fluid.CycleFluidEntryHandler; -import com.gregtechceu.gtceu.integration.xei.widgets.GTRecipeWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.fluid.CycleFluidEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTRecipeWidget; import com.gregtechceu.gtceu.utils.GTMath; import com.lowdragmc.lowdraglib.gui.texture.ProgressTexture; diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java index 239d8a9377b..e38611320d5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java @@ -23,11 +23,11 @@ import com.gregtechceu.gtceu.core.mixins.IngredientAccessor; import com.gregtechceu.gtceu.core.mixins.TagValueAccessor; import com.gregtechceu.gtceu.core.mixins.forge.IntersectionIngredientAccessor; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemTagList; -import com.gregtechceu.gtceu.integration.xei.handlers.item.CycleItemEntryHandler; -import com.gregtechceu.gtceu.integration.xei.widgets.GTRecipeWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.item.CycleItemEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTRecipeWidget; import com.gregtechceu.gtceu.utils.*; import com.lowdragmc.lowdraglib.gui.widget.Widget; diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java index c438c7e0167..eccb723b760 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java @@ -23,7 +23,7 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.recipe.CustomTags; import com.gregtechceu.gtceu.integration.kjs.GTRegistryInfo; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreByProduct; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreByProduct; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.gregtechceu.gtceu.utils.memoization.GTMemoizer; diff --git a/src/main/java/com/gregtechceu/gtceu/api/gui/widget/PatternPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/api/gui/widget/PatternPreviewWidget.java index 182707f3530..087670b518f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/gui/widget/PatternPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/gui/widget/PatternPreviewWidget.java @@ -10,7 +10,7 @@ import com.gregtechceu.gtceu.api.pattern.TraceabilityPredicate; import com.gregtechceu.gtceu.api.pattern.predicates.SimplePredicate; import com.gregtechceu.gtceu.config.ConfigHolder; -import com.gregtechceu.gtceu.integration.xei.handlers.item.CycleItemEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.item.CycleItemEntryHandler; import com.lowdragmc.lowdraglib.client.scene.WorldSceneRenderer; import com.lowdragmc.lowdraglib.client.utils.RenderUtils; diff --git a/src/main/java/com/gregtechceu/gtceu/api/gui/widget/SlotWidget.java b/src/main/java/com/gregtechceu/gtceu/api/gui/widget/SlotWidget.java index ef7f6b23990..52b383b7ccc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/gui/widget/SlotWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/gui/widget/SlotWidget.java @@ -1,10 +1,10 @@ package com.gregtechceu.gtceu.api.gui.widget; import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemTagList; -import com.gregtechceu.gtceu.integration.xei.handlers.item.CycleItemEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.item.CycleItemEntryHandler; import com.lowdragmc.lowdraglib.gui.editor.annotation.LDLRegister; import com.lowdragmc.lowdraglib.gui.editor.configurator.ConfiguratorGroup; diff --git a/src/main/java/com/gregtechceu/gtceu/api/gui/widget/TankWidget.java b/src/main/java/com/gregtechceu/gtceu/api/gui/widget/TankWidget.java index 5230f99742d..2e474162c67 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/gui/widget/TankWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/gui/widget/TankWidget.java @@ -4,10 +4,10 @@ import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; import com.gregtechceu.gtceu.api.transfer.fluid.IFluidHandlerModifiable; import com.gregtechceu.gtceu.client.TooltipsHandler; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidStackList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidTagList; -import com.gregtechceu.gtceu.integration.xei.handlers.fluid.CycleFluidEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.fluid.CycleFluidEntryHandler; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.gregtechceu.gtceu.utils.GTUtil; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/IPanelHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/IPanelHandler.java index fa650b94a0a..776900d4941 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/IPanelHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/IPanelHandler.java @@ -20,7 +20,8 @@ * With the difference, that the method from this interface also works on server * side. *

- * Synced panels must be created with {@link PanelSyncManager#panel(String, PanelSyncHandler.IPanelBuilder, boolean)}. + * Synced panels must be created with + * {@link PanelSyncManager#syncedPanel(String, boolean, PanelSyncHandler.IPanelBuilder)}. * If the panel does not contain any synced widgets, a simple panel handler using * {@link #simple(ModularPanel, SecondaryPanel.IPanelBuilder, boolean)} * is likely what you need. diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/IUIHolder.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/IUIHolder.java index ab921d34285..ce498c5f101 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/IUIHolder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/IUIHolder.java @@ -27,8 +27,8 @@ public interface IUIHolder { @OnlyIn(Dist.CLIENT) default ModularScreen createScreen(T data, ModularPanel mainPanel) { GTCEu.LOGGER - .warn("IGuiHolder.createScreen() should be overridden to pass your own mod id to the ModularScreen. " + - "In future versions this method must be overridden or else it will crash!"); + .warn("IGuiHolder.createScreen() should be overridden to pass your own mod id to the ModularScreen." + + " In future versions this method must be overridden or else it will crash!"); return new ModularScreen(GTCEu.MOD_ID, mainPanel); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/XeiSettings.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/RecipeViewerSettings.java similarity index 70% rename from src/main/java/com/gregtechceu/gtceu/api/mui/base/XeiSettings.java rename to src/main/java/com/gregtechceu/gtceu/api/mui/base/RecipeViewerSettings.java index cc9c4d19c12..bc644585695 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/XeiSettings.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/RecipeViewerSettings.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.utils.Rectangle; import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; import org.jetbrains.annotations.ApiStatus; @@ -13,33 +13,33 @@ * This class can be safely interacted with even when JEI/HEI is not installed. */ @ApiStatus.NonExtendable -public interface XeiSettings { +public interface RecipeViewerSettings { /** - * Force XEI to be enabled + * Force recipe viewer to be enabled */ - void forceEnabled(); + void enable(); /** - * Force XEI to be disabled + * Force recipe viewer to be disabled */ - void forceDisabled(); + void disable(); /** - * Only enabled XEI in synced GUIs + * Only enable the recipe viewer in synced GUIs */ - void defaultXei(); + void defaultState(); /** - * Checks if XEI is enabled for a given screen + * Checks if the recipe viewer is enabled for a given screen * * @param screen modular screen - * @return true if xei is enabled + * @return true if the recipe viewer is enabled */ boolean isEnabled(ModularScreen screen); /** - * Adds an exclusion zone. XEI will always try to avoid exclusion zones.
+ * Adds an exclusion zone. Recipe viewers will always try to avoid exclusion zones.
* If a widgets wishes to have an exclusion zone it should use {@link #addExclusionArea(IWidget)}! * * @param area exclusion area @@ -54,7 +54,7 @@ public interface XeiSettings { void removeExclusionArea(Rectangle area); /** - * Adds an exclusion zone of a widget. XEI will always try to avoid exclusion zones.
+ * Adds an exclusion zone of a widget. Recipe viewers will always try to avoid exclusion zones.
* Useful when a widget is outside its panel. * * @param area widget @@ -69,8 +69,8 @@ public interface XeiSettings { void removeExclusionArea(IWidget area); /** - * Adds a XEI ghost slot. Ghost slots can display an ingredient, but the ingredient does not really exist. - * By calling this method users will be able to drag ingredients from JEI into the slot. + * Adds a recipe viewer ghost slot. Ghost slots can display an ingredient, but the ingredient does not really exist. + * By calling this method users will be able to drag ingredients from recipe viewers into the slot. * * @param slot slot widget * @param slot widget type @@ -78,23 +78,23 @@ public interface XeiSettings { > void addGhostIngredientSlot(W slot); /** - * Removes a XEI ghost slot. + * Removes a recipe viewer ghost slot. * * @param slot slot widget * @param slot widget type */ > void removeGhostIngredientSlot(W slot); - XeiSettings DUMMY = new XeiSettings() { + RecipeViewerSettings DUMMY = new RecipeViewerSettings() { @Override - public void forceEnabled() {} + public void enable() {} @Override - public void forceDisabled() {} + public void disable() {} @Override - public void defaultXei() {} + public void defaultState() {} @Override public boolean isEnabled(ModularScreen screen) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewport.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewport.java index 03c2dce0535..335c229cf01 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewport.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewport.java @@ -9,7 +9,7 @@ /** * A gui element which can transform its children f.e. a scrollable list. */ -public interface IViewport { +public interface IViewport extends IWidget { /** * Apply shifts of this viewport. @@ -26,7 +26,11 @@ default void transformChildren(IViewportStack stack) {} * @param x x position * @param y y position */ - void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y); + default void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { + if (hasChildren()) { + getChildrenAt(this, stack, widgets, x, y); + } + } /** * Gathers all children at a position. Transformations from this viewport are not applied. @@ -37,7 +41,11 @@ default void transformChildren(IViewportStack stack) {} * @param x x position * @param y y position */ - default void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) {} + default void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { + if (isInside(stack, x, y)) { + widgets.add(this, stack, getAdditionalHoverInfo(stack, x, y)); + } + } /** * Called during drawing twice (before children are drawn). Once with transformation of this viewport and once @@ -73,7 +81,7 @@ static void getChildrenAt(IWidget parent, IViewportStack stack, HoveredWidgetLis stack.pushMatrix(); child.transform(stack); if (child.isInside(stack, x, y)) { - widgetList.add(child, stack.peek(), child.getAdditionalHoverInfo(stack, x, y)); + widgetList.add(child, stack, child.getAdditionalHoverInfo(stack, x, y)); } if (child.hasChildren()) { getChildrenAt(child, stack, widgetList, x, y); @@ -119,6 +127,4 @@ static boolean forEachChild(IViewportStack stack, IWidget parent, Predicate {}; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewportStack.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewportStack.java index 6e9b6b6b680..0f95085bba2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewportStack.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/layout/IViewportStack.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.client.mui.screen.viewport.TransformationMatrix; import com.mojang.blaze3d.vertex.PoseStack; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -12,6 +13,7 @@ * This handles all viewports in a GUI. Also keeps track of a matrix stack used for rendering and * user interaction. */ +@ApiStatus.NonExtendable public interface IViewportStack { /** diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IDraggable.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IDraggable.java index 721bcb0bd9f..339392b0a29 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IDraggable.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IDraggable.java @@ -1,8 +1,6 @@ package com.gregtechceu.gtceu.api.mui.base.widget; -import com.gregtechceu.gtceu.api.mui.base.layout.IViewport; import com.gregtechceu.gtceu.api.mui.base.layout.IViewportStack; -import com.gregtechceu.gtceu.api.mui.utils.HoveredWidgetList; import com.gregtechceu.gtceu.api.mui.widget.DraggableWidget; import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; @@ -18,12 +16,13 @@ * * @see DraggableWidget */ -public interface IDraggable extends IViewport { +public interface IDraggable { /** * Gets called every frame after everything else is rendered. * Is only called when {@link #isMoving()} is true. - * Translate to the mouse pos and draw with {@link WidgetTree#drawTree(IWidget, ModularGuiContext)}. + * Translate to the mouse pos and draw with + * {@link WidgetTree#drawTree(IWidget, ModularGuiContext, boolean, boolean)}. * * @param graphics * @param partialTicks difference from last from @@ -66,7 +65,4 @@ default boolean canDropHere(int x, int y, @Nullable IWidget widget) { void setMoving(boolean moving); void transform(IViewportStack viewportStack); - - @Override - default void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) {} } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IGuiElement.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IGuiElement.java deleted file mode 100644 index 9a44adc3501..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IGuiElement.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.gregtechceu.gtceu.api.mui.base.widget; - -import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; -import com.gregtechceu.gtceu.api.mui.widget.sizer.ResizeNode; -import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; - -import org.jetbrains.annotations.ApiStatus; - -/** - * Base interface for gui elements. For example widgets. - */ -@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") -@Deprecated -public interface IGuiElement { - - /** - * @return the screen this element is in - */ - ModularScreen getScreen(); - - /** - * @return the parent of this element - */ - IGuiElement getParent(); - - /** - * Returns if this element has a parent. This is the case when the widget is valid, but never if it's root widget. - */ - boolean hasParent(); - - ResizeNode resizer(); - - /** - * @return the area this element occupies - */ - Area getArea(); - - /** - * Shortcut to get the area of the parent - * - * @return parent area - */ - default Area getParentArea() { - return getParent().getArea(); - } - - /** - * Called when the mouse hovers this element. This means this element is directly below the mouse or there are - * widgets in between which all allow to pass hover through. This is not called when the element is at any point - * below the mouse. - */ - default void onMouseStartHover() {} - - /** - * Called when the mouse no longer hovers this element. This widget can still be below the mouse on some level. - */ - default void onMouseEndHover() {} - - /** - * Called when the mouse enters this element's area with any amount of widgets above it from the current panel. - */ - default void onMouseEnterArea() {} - - /** - * Called when the mouse leaves the area, or it started hovering a different panel. - */ - default void onMouseLeaveArea() {} - - /** - * @return if this widget is currently right below the mouse - */ - default boolean isHovering() { - return isHoveringFor(0); - } - - /** - * - * @param ticks time in ticks - * @return if this element is right below the mouse for a certain amount of time - */ - default boolean isHoveringFor(int ticks) { - return false; - } - - default boolean isBelowMouse() { - return isBelowMouseFor(0); - } - - default boolean isBelowMouseFor(int ticks) { - return false; - } - - /** - * Returns if this element is enabled. Disabled elements are not drawn and can not be interacted with. - */ - boolean isEnabled(); - - /** - * @return default width if it can't be calculated - */ - default int getDefaultWidth() { - return 18; - } - - /** - * @return default height if it can't be calculated - */ - default int getDefaultHeight() { - return 18; - } - - void scheduleResize(); - - boolean requiresResize(); -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IParentWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IParentWidget.java index 386a85fc6a9..6231cba2552 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IParentWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IParentWidget.java @@ -1,7 +1,5 @@ package com.gregtechceu.gtceu.api.mui.base.widget; -import org.jetbrains.annotations.ApiStatus; - import java.util.function.Supplier; public interface IParentWidget> { @@ -24,16 +22,6 @@ default W child(I child) { return getThis(); } - /** - * @deprecated use {@link #childIf(boolean, Supplier)} - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - default W childIf(boolean condition, I child) { - if (condition) return child(child); - return getThis(); - } - default W childIf(boolean condition, Supplier child) { if (condition) return child(child.get()); return getThis(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IPositioned.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IPositioned.java index d15d36627bf..5048f1c9121 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IPositioned.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IPositioned.java @@ -3,8 +3,6 @@ import com.gregtechceu.gtceu.api.mui.utils.Alignment; import com.gregtechceu.gtceu.api.mui.widget.sizer.*; -import org.jetbrains.annotations.ApiStatus; - import java.util.function.Consumer; import java.util.function.DoubleSupplier; @@ -48,12 +46,6 @@ default W expanded() { return getThis(); } - @Deprecated - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - default W relative(IGuiElement guiElement) { - return relative(guiElement.getArea()); - } - @Deprecated default W relative(Area area) { return relative(new AreaResizer(area)); @@ -318,6 +310,11 @@ default W height(float val, Unit.Measure measure) { return getThis(); } + default W heightRelOffset(float val, int offset) { + resizer().height(val, offset, Unit.Measure.RELATIVE); + return getThis(); + } + default W heightRelOffset(DoubleSupplier val, int offset) { resizer().height(val, offset, Unit.Measure.RELATIVE); return getThis(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java index 56324bacff7..5be499d2a32 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/ISynced.java @@ -1,15 +1,11 @@ package com.gregtechceu.gtceu.api.mui.base.widget; import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; -import com.gregtechceu.gtceu.api.mui.value.sync.GenericSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.ModularSyncManager; import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandler; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; /** * Marks a widget as synced @@ -34,15 +30,6 @@ default W getThis() { */ void initialiseSyncHandler(ModularSyncManager syncManager, boolean late); - /** - * @deprecated use {@link #isValidSyncOrValue(ISyncOrValue)} - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - default boolean isValidSyncHandler(SyncHandler syncHandler) { - return false; - } - /** * Returns if the given value or sync handler is valid for this widget. This is usually a call to * {@link ISyncOrValue#isTypeOrEmpty(Class)}. If the widget must specify a value (disallow null) instanceof check @@ -55,12 +42,12 @@ default boolean isValidSyncHandler(SyncHandler syncHandler) { * @return if the value or sync handler is valid for this class */ default boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { - return !(syncOrValue instanceof SyncHandler syncHandler) || isValidSyncHandler(syncHandler); + return false; } /** * Checks if the given sync handler is valid for this widget and throws an exception if not. - * Override {@link #isValidSyncHandler(SyncHandler)} + * Override {@link #isValidSyncOrValue(ISyncOrValue)} * * @param syncHandler given sync handler * @throws IllegalStateException if the given sync handler is invalid for this widget. @@ -74,42 +61,6 @@ default void checkValidSyncOrValue(ISyncOrValue syncHandler) { } } - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - default T castIfTypeElseNull(SyncHandler syncHandler, Class clazz) { - return castIfTypeElseNull(syncHandler, clazz, null); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - @SuppressWarnings("unchecked") - default T castIfTypeElseNull(SyncHandler syncHandler, Class clazz, @Nullable Consumer setup) { - if (syncHandler != null && clazz.isAssignableFrom(syncHandler.getClass())) { - T t = (T) syncHandler; - if (setup != null) setup.accept(t); - return t; - } - return null; - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - default GenericSyncValue castIfTypeGenericElseNull(SyncHandler syncHandler, Class clazz) { - return castIfTypeGenericElseNull(syncHandler, clazz, null); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - default GenericSyncValue castIfTypeGenericElseNull(SyncHandler syncHandler, Class clazz, - @Nullable Consumer> setup) { - if (syncHandler instanceof GenericSyncValue genericSyncValue && genericSyncValue.isOfType(clazz)) { - GenericSyncValue t = genericSyncValue.cast(); - if (setup != null) setup.accept(t); - return t; - } - return null; - } - /** * @return true if this widget has a valid sync handler */ diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java index 9ed5dd4da39..4137719be58 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/base/widget/IWidget.java @@ -13,7 +13,6 @@ import com.gregtechceu.gtceu.utils.FormattingUtil; import com.google.common.base.CharMatcher; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -24,7 +23,7 @@ /** * A widget in a GUI. */ -public interface IWidget extends IGuiElement, ITreeNode { +public interface IWidget extends ITreeNode { String WIDGET_TRANSLATION_KEY_FORMAT = "widget.%s.name"; /** @@ -73,7 +72,6 @@ default boolean hasParent() { /** * @return the area this widget occupies */ - @Override Area getArea(); /** @@ -311,43 +309,10 @@ default boolean hasChildren() { boolean requiresResize(); - /** - * @return flex of this widget - */ - @Deprecated - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Nullable - default StandardResizer getFlex() { - return resizer(); - } - - /** - * @return flex of this widget. Creates a new one if it doesn't already have one. - */ - @NotNull - @Deprecated - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - default StandardResizer flex() { - return resizer(); - } - - /** - * Does the same as {@link IPositioned#resizer(Consumer)} - * - * @param builder function to build flex - * @return this - */ - @Deprecated - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - default IWidget flexBuilder(Consumer builder) { - return resizerBuilder(builder); - } - /** * @return resizer of this widget */ @NotNull - @Override StandardResizer resizer(); default IWidget resizerBuilder(Consumer builder) { @@ -377,7 +342,6 @@ default void postResize() {} * * @return if this element is enabled */ - @Override boolean isEnabled(); void setEnabled(boolean enabled); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/GuiDraw.java b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/GuiDraw.java index f95927392f0..dd516c1a558 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/GuiDraw.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/GuiDraw.java @@ -3,7 +3,9 @@ import com.gregtechceu.gtceu.api.mui.drawable.text.TextRenderer; import com.gregtechceu.gtceu.api.mui.utils.Alignment; import com.gregtechceu.gtceu.api.mui.utils.Color; +import com.gregtechceu.gtceu.api.mui.utils.RectangleF; import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; +import com.gregtechceu.gtceu.client.GuiSpriteManager; import com.gregtechceu.gtceu.client.mui.screen.RichTooltip; import com.gregtechceu.gtceu.client.mui.screen.event.RichTooltipEvent; import com.gregtechceu.gtceu.client.mui.screen.viewport.GuiContext; @@ -18,6 +20,7 @@ import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; @@ -52,6 +55,7 @@ import java.util.List; import java.util.function.BiConsumer; +import static com.gregtechceu.gtceu.api.mui.drawable.UITexture.GUI_TEXTURE_ID_CONVERTER; import static net.minecraft.util.Mth.HALF_PI; import static net.minecraft.util.Mth.TWO_PI; @@ -188,7 +192,7 @@ public static void drawRoundedRect(GuiGraphics graphics, float x0, float y0, flo for (int i = 1; i <= segments; i++) { float x = x0 + cornerRadius - Mth.cos(HALF_PI / segments * i) * cornerRadius; float y = y1 - cornerRadius + Mth.sin(HALF_PI / segments * i) * cornerRadius; - bufferbuilder.vertex(x, y, 0.0f) + bufferbuilder.vertex(pose, x, y, 0.0f) .color(Color.getRed(colorBL), Color.getGreen(colorBL), Color.getBlue(colorBL), Color.getAlpha(colorBL)) .endVertex(); @@ -237,10 +241,57 @@ public static void drawRoundedRect(GuiGraphics graphics, float x0, float y0, flo .endVertex(); } + /** + * Set up the texture as a sampler differently depending on if it's part of the GUI atlas or not. + *

+ * If the texture is part of the GUI atlas, the atlas will be used for drawing and the UV coordinates will be scaled + * to the atlas texture.
+ * If it's not part of the GUI atlas, nothing special is done. + * + * @param location the texture file's location, e.g. {@code "modularui:textures/gui/slot/item.png"} + * @param u0 u0 UV coordinate + * @param v0 v0 UV coordinate + * @param u1 u1 UV coordinate + * @param v1 v1 UV coordinate + * @return If texture is in the GUI atlas, rescaled UV coordinates {@code u0, v0, u1, v1}.
+ * If not, the same coordinates that were passed in. + */ + public static RectangleF setupTexture(ResourceLocation location, float u0, float v0, float u1, float v1) { + TextureAtlasSprite sprite = GuiSpriteManager.getInstance() + .getSprite(GUI_TEXTURE_ID_CONVERTER.fileToId(location)); + + // check if the atlas doesn't have this sprite, default to using the resloc as is if so + if (!sprite.contents().name().equals(MissingTextureAtlasSprite.getLocation())) { + RenderSystem.setShaderTexture(0, sprite.atlasLocation()); + + // have to multiply by 16 here because of MC weirdness + // REMOVE THE MULTIPLICATION IN 1.21!!! + return new RectangleF(sprite.getU(u0 * 16), sprite.getV(v0 * 16), sprite.getU(u1 * 16), + sprite.getV(v1 * 16)); + } else { + RenderSystem.setShaderTexture(0, location); + return new RectangleF(u0, v0, u1, v1); + } + } + + public static boolean isGuiAtlasSprite(ResourceLocation location) { + location = GUI_TEXTURE_ID_CONVERTER.fileToId(location); + return GuiSpriteManager.getInstance().getSprite(location).atlasLocation() != + MissingTextureAtlasSprite.getLocation(); + } + public static void drawTexture(Matrix4f pose, ResourceLocation location, float x, float y, float w, float h, int u, int v, int textureWidth, int textureHeight) { - RenderSystem.setShaderTexture(0, location); - drawTexture(pose, x, y, u, v, w, h, textureWidth, textureHeight); + if (!isGuiAtlasSprite(location)) { + RenderSystem.setShaderTexture(0, location); + drawTexture(pose, x, y, u, v, w, h, textureWidth, textureHeight); + return; + } + + float tw = 1F / textureWidth; + float th = 1F / textureHeight; + RectangleF newUvs = setupTexture(location, u * tw, v * th, (u + w) * tw, (v + h) * th); + drawTexture(pose, x, y, x + w, y + h, newUvs.u0(), newUvs.v0(), newUvs.u1(), newUvs.v1()); } public static void drawTexture(Matrix4f pose, float x, float y, int u, int v, float w, float h, @@ -308,14 +359,14 @@ public static void drawTexture(Matrix4f pose, ResourceLocation location, float x public static void drawTexture(Matrix4f pose, ResourceLocation location, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, boolean withBlend) { - RenderSystem.setShaderTexture(0, location); + RectangleF newUvs = setupTexture(location, u0, v0, u1, v1); RenderSystem.setShader(GameRenderer::getPositionTexShader); if (withBlend) { RenderSystem.enableBlend(); } else { RenderSystem.disableBlend(); } - drawTexture(pose, x0, y0, x1, y1, u0, v0, u1, v1, 0); + drawTexture(pose, x0, y0, x1, y1, newUvs.u0(), newUvs.v0(), newUvs.u1(), newUvs.v1(), 0); } public static void drawTexture(Matrix4f pose, float x0, float y0, float x1, float y1, @@ -342,9 +393,19 @@ public static void drawTexture(Matrix4f pose, VertexConsumer buffer, float x0, f } public static void drawTiledTexture(Matrix4f pose, ResourceLocation location, float x, float y, float w, float h, - int u, int v, int tileW, int tileH, int tw, int th, float z) { - RenderSystem.setShaderTexture(0, location); - drawTiledTexture(pose, x, y, w, h, u, v, tileW, tileH, tw, th, z); + int u, int v, int tileWidth, int tileHeight, int textureWidth, + int textureHeight, float z) { + if (!isGuiAtlasSprite(location)) { + RenderSystem.setShaderTexture(0, location); + drawTiledTexture(pose, x, y, w, h, u, v, tileWidth, tileHeight, textureWidth, textureHeight, z); + return; + } + + float wRatio = 1f / textureWidth; + float hRatio = 1f / textureHeight; + RectangleF newUvs = setupTexture(location, u * wRatio, v * hRatio, (u + w) * wRatio, (v + h) * hRatio); + drawTiledTexture(pose, x, y, x + w, y + h, newUvs.u0(), newUvs.v0(), + newUvs.u1(), newUvs.v1(), tileWidth, tileHeight, z); } public static void drawTiledTexture(Matrix4f pose, float x, float y, float w, float h, @@ -376,8 +437,9 @@ public static void drawTiledTexture(Matrix4f pose, ResourceLocation location, fl float u0, float v0, float u1, float v1, int textureWidth, int textureHeight, float z) { RenderSystem.enableBlend(); - RenderSystem.setShaderTexture(0, location); - drawTiledTexture(pose, x, y, w, h, u0, v0, u1, v1, textureWidth, textureHeight, z); + RectangleF newUvs = setupTexture(location, u0, v0, u1, v1); + drawTiledTexture(pose, x, y, w, h, newUvs.u0(), newUvs.v0(), newUvs.u1(), newUvs.v1(), textureWidth, + textureHeight, z); RenderSystem.disableBlend(); } @@ -641,7 +703,7 @@ public static void drawStandardSlotAmountText(GuiContext context, int amount, St public static void drawAmountText(ModularGuiContext context, int amount, String format, int x, int y, int width, int height, Alignment alignment, float z) { - if (amount == 1) return; + if (amount <= 1) return; String amountText = FormattingUtil.formatNumberReadable(amount, false); if (format != null) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/UITexture.java b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/UITexture.java index 302673bcf07..d03ee52243f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/UITexture.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/UITexture.java @@ -10,6 +10,7 @@ import com.gregtechceu.gtceu.client.mui.screen.viewport.GuiContext; import com.gregtechceu.gtceu.utils.serialization.json.JsonHelper; +import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -24,6 +25,7 @@ public class UITexture implements IDrawable, IJsonSerializable { public static final UITexture DEFAULT = fullImage("gui/options_background", ColorType.DEFAULT); + public static final FileToIdConverter GUI_TEXTURE_ID_CONVERTER = new FileToIdConverter("textures/gui", ".png"); private static final ResourceLocation ICONS_LOCATION = GTCEu.id("textures/gui/icons.png"); @@ -174,6 +176,11 @@ public void drawSubArea(GuiContext context, float x, float y, float width, float lerpV(vEnd), this.nonOpaque); } + @Override + public boolean canApplyTheme() { + return this.colorType != null; + } + @Override public void applyColor(int themeColor) { if (this.colorOverride != 0) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/RichTextCompiler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/RichTextCompiler.java index 2325539690d..4228dd5dee1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/RichTextCompiler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/drawable/text/RichTextCompiler.java @@ -126,7 +126,14 @@ private void compileString(String text) { if (i == 0) { // doesn't fit at the end of the line, try new line if (this.x > 0) i = fr.getSplitter().plainIndexAtWidth(subText, this.maxWidth, Style.EMPTY); - if (i == 0) throw new IllegalStateException("No space for string '" + subText + "'"); + if (i <= 0) { + i = 1; // force at least one char + if (subText.charAt(0) == '\u00a7' && subText.length() > 1) { + // include format char if it is one + i++; + if (subText.length() > 2) i++; + } + } newLine(); } else if (i < subText.length()) { // the whole string doesn't fit diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/ClientGUI.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/ClientGUI.java index f5864255ea2..19eb36af969 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/ClientGUI.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/ClientGUI.java @@ -3,8 +3,8 @@ import com.gregtechceu.gtceu.api.mui.base.MCHelper; import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; +import com.gregtechceu.gtceu.client.mui.screen.RecipeViewerSettingsImpl; import com.gregtechceu.gtceu.client.mui.screen.UISettings; -import com.gregtechceu.gtceu.client.mui.screen.XeiSettingsImpl; import net.minecraft.client.gui.screens.Screen; import net.minecraftforge.api.distmarker.Dist; @@ -36,11 +36,11 @@ public static void open(@NotNull ModularScreen screen) { * Opens a modular screen on the next client tick with custom jei settings. * It needs to be opened in next tick, because we might break the current GUI if we open it now. * - * @param screen new modular screen - * @param jeiSettings custom jei settings + * @param screen new modular screen + * @param recipeViewerSettings custom jei settings */ - public static void open(@NotNull ModularScreen screen, @NotNull XeiSettingsImpl jeiSettings) { - GuiManager.openScreen(screen, new UISettings(jeiSettings)); + public static void open(@NotNull ModularScreen screen, @NotNull RecipeViewerSettingsImpl recipeViewerSettings) { + GuiManager.openScreen(screen, new UISettings(recipeViewerSettings)); } /** @@ -57,16 +57,16 @@ public static void open(@NotNull ModularScreen screen, @Nullable IntFunction container) { - UISettings settings = new UISettings(jeiSettings); + UISettings settings = new UISettings(recipeViewerSettings); settings.customContainer(container); GuiManager.openScreen(screen, settings); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java index b556deee40c..330056f2da9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java @@ -3,8 +3,8 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; import com.gregtechceu.gtceu.api.mui.base.MCHelper; +import com.gregtechceu.gtceu.api.mui.base.RecipeViewerSettings; import com.gregtechceu.gtceu.api.mui.base.UIFactory; -import com.gregtechceu.gtceu.api.mui.base.XeiSettings; import com.gregtechceu.gtceu.api.mui.value.sync.ModularSyncManager; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; @@ -72,7 +72,7 @@ public static void open(@NotNull UIFactory factory, @NotN if (player instanceof FakePlayer || openedContainers.contains(player)) return; openedContainers.add(player); // create panel, collect sync handlers and create menu - UISettings settings = new UISettings(XeiSettings.DUMMY); + UISettings settings = new UISettings(RecipeViewerSettings.DUMMY); settings.defaultCanInteractWith(factory, guiData); ModularSyncManager msm = new ModularSyncManager(false); PanelSyncManager syncManager = new PanelSyncManager(msm, true); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryUIFactory.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryUIFactory.java index cd1bec52668..0fb895f32ad 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryUIFactory.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/PlayerInventoryUIFactory.java @@ -33,7 +33,7 @@ public void openFromHand(Player player, InteractionHand hand) { public void openFromCurios(Player player, String type, int index) { if (!GTCEu.Mods.isCuriosLoaded()) { - throw new IllegalArgumentException("Can't open UI for curios item when bauble is not loaded!"); + throw new IllegalArgumentException("Can't open UI for curio item when curios is not loaded!"); } GuiManager.open( this, PlayerInventoryGuiData.of(player, InventoryTypes.CURIOS, type, index), verifyServerSide(player)); @@ -59,7 +59,7 @@ public void openFromHandClient(InteractionHand hand) { @SideOnly(Side.CLIENT) public void openFromCuriosClient(String type, int index) { if (!GTCEu.Mods.isCuriosLoaded()) { - throw new IllegalArgumentException("Can't open UI for baubles item when bauble is not loaded!"); + throw new IllegalArgumentException("Can't open UI for curio item when curios is not loaded!"); } GuiManager.openFromClient( this, PlayerInventoryGuiData.of(MCHelper.getPlayer(), InventoryTypes.CURIOS, type, index)); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/DebugOverlay.java b/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/DebugOverlay.java index 1db715f8ffe..c1fc2ccd812 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/DebugOverlay.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/DebugOverlay.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; import com.gregtechceu.gtceu.api.mui.base.drawable.IIcon; import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; +import com.gregtechceu.gtceu.api.mui.base.value.IBoolValue; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.drawable.NamedDrawableRow; import com.gregtechceu.gtceu.api.mui.drawable.Rectangle; @@ -24,6 +25,8 @@ import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Field; + public class DebugOverlay extends CustomModularScreen { private static final IIcon CHECKMARK = GTGuiTextures.CHECK_BOX.asIcon().size(8); @@ -47,8 +50,9 @@ public DebugOverlay(IMuiScreen screen) { .background( new Rectangle() .color(Color.withAlpha( - Long.decode(ConfigHolder.INSTANCE.dev.mui.outlineColor).intValue(), - 0.4f))) + Color.parseString(ConfigHolder.INSTANCE.dev.mui.outlineColor), + 0.4f)) + .cornerRadius(4)) .disableHoverBackground() .overlay(IKey.str("Debug Options")) .openUp() @@ -83,18 +87,12 @@ public DebugOverlay(IMuiScreen screen) { .child(new ListWidget<>() .maxSize(100) .widthRel(1f) - .child(toggleOption(0, "Any", - ConfigHolder.INSTANCE.dev.mui.showHovered)) - .child(toggleOption(1, "Pos", - ConfigHolder.INSTANCE.dev.mui.showPos)) - .child(toggleOption(2, "Size", - ConfigHolder.INSTANCE.dev.mui.showSize)) - .child(toggleOption(3, "Widget Theme", - ConfigHolder.INSTANCE.dev.mui.showWidgetTheme)) - .child(toggleOption(4, "Extra info", - ConfigHolder.INSTANCE.dev.mui.showExtra)) - .child(toggleOption(5, "Outline", - ConfigHolder.INSTANCE.dev.mui.showOutline))))) + .child(toggleOption(0, "Any", "showHovered")) + .child(toggleOption(1, "Pos", "showPos")) + .child(toggleOption(2, "Size", "showSize")) + .child(toggleOption(3, "Widget Theme", "showWidgetTheme")) + .child(toggleOption(4, "Extra info", "showExtra")) + .child(toggleOption(5, "Outline", "showOutline"))))) .child(new ContextMenuButton<>("menu_parent_hover_info") .name("menu_button_parent_hover_info") .height(10) @@ -108,25 +106,43 @@ public DebugOverlay(IMuiScreen screen) { .child(new ListWidget<>() .maxSize(100) .widthRel(1f) - .child(toggleOption(10, "Any", - ConfigHolder.INSTANCE.dev.mui.showParent)) - .child(toggleOption(11, "Pos", - ConfigHolder.INSTANCE.dev.mui.showParentPos)) - .child(toggleOption(12, "Size", - ConfigHolder.INSTANCE.dev.mui.showParentSize)) + .child(toggleOption(10, "Any", "showParent")) + .child(toggleOption(11, "Pos", "showParentPos")) + .child(toggleOption(12, "Size", "showParentSize")) .child(toggleOption(13, "Widget Theme", - ConfigHolder.INSTANCE.dev.mui.showParentWidgetTheme)) - .child(toggleOption(14, "Outline", - ConfigHolder.INSTANCE.dev.mui.showParentOutline))))))); + "showParentWidgetTheme")) + .child(toggleOption(14, "Outline", "showParentOutline"))))))); } - public static IWidget toggleOption(int i, String name, boolean boolValue) { + public static IWidget toggleOption(int i, String name, String field) { + ConfigHolder.DeveloperConfigs.MuiConfigs c = ConfigHolder.INSTANCE.dev.mui; + Field f; + try { + f = c.getClass().getField(field); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + + IBoolValue val = new BoolValue.Dynamic(() -> { + try { + return (boolean) f.get(c); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }, v -> { + try { + f.set(c, v); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + return new ToggleButton() .name("hover_info_toggle" + i) .invisible() .widthRel(1f) .height(12) - .value(new BoolValue(boolValue)) + .value(val) .overlay(true, new NamedDrawableRow() .name(IKey.str(name)) .drawable(CHECKMARK)) diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayHandler.java deleted file mode 100644 index 5dc8a02b908..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.gregtechceu.gtceu.api.mui.overlay; - -import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; - -import net.minecraft.client.gui.screens.Screen; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Function; -import java.util.function.Predicate; - -@Deprecated -@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") -public class OverlayHandler implements Comparable { - - private final Predicate test; - private final Function overlayFunction; - private final int priority; - - public OverlayHandler(Predicate test, Function overlayFunction) { - this(test, overlayFunction, 1000); - } - - public OverlayHandler(Predicate test, Function overlayFunction, int priority) { - this.test = test; - this.overlayFunction = overlayFunction; - this.priority = priority; - } - - public boolean isValidFor(Screen screen) { - return this.test.test(screen); - } - - public ModularScreen createOverlay(Screen screen) { - return this.overlayFunction.apply(screen); - } - - @Override - public int compareTo(@NotNull OverlayHandler o) { - return Integer.compare(this.priority, o.priority); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayManager.java deleted file mode 100644 index 5ee7d296c0e..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayManager.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gregtechceu.gtceu.api.mui.overlay; - -import com.gregtechceu.gtceu.GTCEu; - -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.common.Mod; - -import org.jetbrains.annotations.ApiStatus; - -import java.util.ArrayList; -import java.util.List; - -@Deprecated -@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") -@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) -public class OverlayManager { - - public static final List overlays = new ArrayList<>(); - - public static void register(OverlayHandler handler) { - if (!overlays.contains(handler)) { - overlays.add(handler); - overlays.sort(OverlayHandler::compareTo); - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayStack.java b/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayStack.java index 819cb07fbc5..1a8fe2c3325 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayStack.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/overlay/OverlayStack.java @@ -18,7 +18,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.function.Consumer; import java.util.function.Predicate; @@ -124,15 +123,6 @@ public static boolean isHoveringOverlay() { public static void onOpenScreen(Screen newScreen) { closeAll(); if (newScreen != null) { - // backwards compat - for (OverlayHandler handler : OverlayManager.overlays) { - if (handler.isValidFor(newScreen)) { - ModularScreen overlay = Objects.requireNonNull(handler.createOverlay(newScreen), - "Overlays must not be null!"); - overlay.constructOverlay(newScreen); - OverlayStack.open(overlay); - } - } OpenScreenEvent event = new OpenScreenEvent(newScreen); MinecraftForge.EVENT_BUS.post(event); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/schema/ArraySchema.java b/src/main/java/com/gregtechceu/gtceu/api/mui/schema/ArraySchema.java index b0719cde521..786fc5af0c0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/schema/ArraySchema.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/schema/ArraySchema.java @@ -171,12 +171,13 @@ public Builder where(char c, Block block) { return where(c, block.defaultBlockState()); } + public Builder where(char c, String registryName) { + return where(c, new ResourceLocation(registryName)); + } + public Builder where(char c, ResourceLocation registryName) { - Optional block = BuiltInRegistries.BLOCK.getOptional(registryName); - if (block.isEmpty()) { - throw new IllegalArgumentException(registryName + " isn't a valid block"); - } - return where(c, block.get()); + return where(c, BuiltInRegistries.BLOCK.getOptional(registryName) + .orElseThrow(() -> new IllegalArgumentException(registryName + " isn't a valid block"))); } private void validate() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/theme/ThemeManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/theme/ThemeManager.java index 003dd3d44a8..7a3e7e26815 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/theme/ThemeManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/theme/ThemeManager.java @@ -7,7 +7,7 @@ import com.gregtechceu.gtceu.utils.serialization.json.JsonBuilder; import com.gregtechceu.gtceu.utils.serialization.json.JsonHelper; -import net.minecraft.resources.FileToIdConverter; +import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; @@ -34,13 +34,23 @@ public class ThemeManager extends SimplePreparableReloadListener>> { public static final String THEMES_PATH = "themes.json"; - public static final FileToIdConverter THEME_LISTER = new FileToIdConverter("gtceu/themes", ".json"); + // public static final FileToIdConverter THEME_LISTER = new FileToIdConverter("gtceu/themes", ".json"); protected static final WidgetThemeEntry defaultFallbackWidgetTheme = IThemeApi.get().getDefaultTheme() .getWidgetTheme(IThemeApi.FALLBACK); private static final JsonObject emptyJson = new JsonObject(); public ThemeManager() {} + public static void reload() { + // hackery to reload themes on this thread + // usually resources are loaded off-thread to not block the main thread + // but this should be fine since it is currently not expected to take longer than a second + ThemeManager tm = new ThemeManager(); + ResourceManager rm = Minecraft.getInstance().getResourceManager(); + ProfilerFiller p = Minecraft.getInstance().getProfiler(); + tm.apply(tm.prepare(rm, p), rm, p); + } + @Override protected @NotNull Map> prepare(ResourceManager resourceManager, ProfilerFiller profiler) { @@ -202,11 +212,12 @@ private static ThemeJson loadThemeJson(String id, List paths, boolean override = false; for (ResourceLocation path : paths) { profiler.push(path.toString()); - ResourceLocation rl = THEME_LISTER.idToFile(path); + ResourceLocation rl = new ResourceLocation(path.getNamespace(), "themes/" + path.getPath() + ".json"); Resource resource = resourceManager.getResource(rl).orElse(null); if (resource == null) { profiler.pop(); - return null; + GTCEu.LOGGER.warn("Theme '{}' was not found at path '{}'", id, rl); + continue; } JsonElement element; try (InputStream stream = resource.open()) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/utils/Color.java b/src/main/java/com/gregtechceu/gtceu/api/mui/utils/Color.java index 12c98e94afe..e11da3a60de 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/utils/Color.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/utils/Color.java @@ -12,7 +12,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.mojang.blaze3d.systems.RenderSystem; -import org.jetbrains.annotations.ApiStatus; import java.util.Locale; import java.util.function.ToIntFunction; @@ -757,15 +756,6 @@ public static int average(ToIntFunction colorFunction, T... colorHolders) (int) Math.sqrt(b / colorHolders.length), a / colorHolders.length); } - /** - * @deprecated renamed to {@link #lerp(int, int, float)} - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public static int interpolate(int color1, int color2, float value) { - return lerp(color1, color2, value); - } - public static int average(int argb1, int argb2) { return lerp(argb1, argb2, 0.5f); } @@ -903,6 +893,49 @@ public static String componentToFullHexString(int component) { return s; } + public static int parseString(String colorString) { + if (colorString.isEmpty()) return WHITE.main; + char c = colorString.charAt(0); + // a normal int string + if (Character.isDigit(c) || c == '-' || c == '#') { + int color; + try { + color = (int) (long) Long.decode(colorString); // bruh + } catch (NumberFormatException e) { + GTCEu.LOGGER.error("Failed to decode color of string '{}'. Exception: ", colorString); + GTCEu.LOGGER.catching(e); + return WHITE.main; + } + if (color != 0 && getAlpha(color) == 0) { + return withAlpha(color, 255); + } + return color; + } + + if ("invisible".equals(colorString)) { + return withAlpha(WHITE.main, 0); + } + int i = colorString.indexOf(':'); + int index = 0; + if (i > 0) { + try { + index = Integer.parseInt(colorString.substring(i + 1)); + } catch (NumberFormatException e) { + GTCEu.LOGGER.error("[THEME] If the color is a word then after the : must come a negative or " + + "positive integer, but got '{}'", colorString.substring(i + 1)); + } + colorString = colorString.substring(0, i); + } + ColorShade colorShade = ColorShade.getFromName(colorString); + if (colorShade != null) { + if (index == 0) return colorShade.main; + if (index > 0) return colorShade.brighterSafe(index - 1); + return colorShade.darkerSafe(-index - 1); + } + GTCEu.LOGGER.error("[THEME] No color shade for name '{}' was found", colorString); + return WHITE.main; + } + /** * Parses a ARGB color of a json element. * @@ -912,40 +945,7 @@ public static String componentToFullHexString(int component) { */ public static int ofJson(JsonElement jsonElement) { if (jsonElement.isJsonPrimitive()) { - String colorString = jsonElement.getAsString(); - if (colorString.isEmpty()) return WHITE.main; - char c = colorString.charAt(0); - // a normal int string - if (Character.isDigit(c) || c == '-' || c == '#') { - int color = (int) (long) Long.decode(jsonElement.getAsString()); // bruh - if (color != 0 && getAlpha(color) == 0) { - return withAlpha(color, 255); - } - return color; - } - - if ("invisible".equals(jsonElement.getAsString())) { - return withAlpha(WHITE.main, 0); - } - int i = colorString.indexOf(':'); - int index = 0; - if (i > 0) { - try { - index = Integer.parseInt(colorString.substring(i + 1)); - } catch (NumberFormatException e) { - GTCEu.LOGGER.error("[THEME] If the color is a word then after teh : must come a negative or " + - "positive integer, but got '{}'", colorString.substring(i + 1)); - } - colorString = colorString.substring(0, i); - } - ColorShade colorShade = ColorShade.getFromName(colorString); - if (colorShade != null) { - if (index == 0) return colorShade.main; - if (index > 0) return colorShade.brighterSafe(index - 1); - return colorShade.darkerSafe(-index - 1); - } - GTCEu.LOGGER.error("[THEME] No color shade for name '{}' was found", colorString); - return WHITE.main; + return parseString(jsonElement.getAsString()); } if (jsonElement.isJsonObject()) { JsonObject json = jsonElement.getAsJsonObject(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/utils/HoveredWidgetList.java b/src/main/java/com/gregtechceu/gtceu/api/mui/utils/HoveredWidgetList.java index 530f29dd72a..d794e31bea6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/utils/HoveredWidgetList.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/utils/HoveredWidgetList.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.api.mui.utils; +import com.gregtechceu.gtceu.api.mui.base.layout.IViewportStack; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.client.mui.screen.viewport.LocatedWidget; -import com.gregtechceu.gtceu.client.mui.screen.viewport.TransformationMatrix; import org.jetbrains.annotations.Nullable; @@ -14,8 +14,8 @@ public HoveredWidgetList(ObjectList delegate) { this.delegate = delegate; } - public void add(IWidget widget, TransformationMatrix viewports, Object additionalHoverInfo) { - this.delegate.add(0, new LocatedWidget(widget, viewports, additionalHoverInfo)); + public void add(IWidget widget, IViewportStack viewports, Object additionalHoverInfo) { + this.delegate.addFirst(new LocatedWidget(widget, viewports.peek(), additionalHoverInfo)); } @Nullable diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/utils/RectangleF.java b/src/main/java/com/gregtechceu/gtceu/api/mui/utils/RectangleF.java new file mode 100644 index 00000000000..c85b7dc86ea --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/utils/RectangleF.java @@ -0,0 +1,95 @@ +package com.gregtechceu.gtceu.api.mui.utils; + +import lombok.Getter; +import lombok.Setter; + +public class RectangleF { + + @Getter + @Setter + public float x; + @Getter + @Setter + public float y; + @Getter + @Setter + public float width; + @Getter + @Setter + public float height; + + public RectangleF() { + this(0, 0, 0, 0); + } + + public RectangleF(RectangleF toCopy) { + this(toCopy.x, toCopy.y, toCopy.width, toCopy.height); + } + + public RectangleF(float x, float y, float width, float height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public RectangleF intersect(RectangleF other) { + float i = this.x; + float j = this.y; + float k = this.x + this.width; + float l = this.y + this.height; + float i1 = other.getX(); + float j1 = other.getY(); + float k1 = i1 + other.getWidth(); + float l1 = j1 + other.getHeight(); + this.x = Math.max(i, i1); + this.y = Math.max(j, j1); + this.width = Math.max(0, Math.min(k, k1) - this.x); + this.height = Math.max(0, Math.min(l, l1) - this.y); + return this; + } + + public void setPosition(float x, float y) { + this.x = x; + this.y = y; + } + + public void setBounds(RectangleF toCopy) { + setBounds(toCopy.x, toCopy.y, toCopy.width, toCopy.height); + } + + public void setBounds(float x, float y, float width, float height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public PointF getCenter() { + return new PointF(x + width / 2.0f, y + height / 2.0f); + } + + public boolean contains(float x, float y) { + return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height; + } + + public boolean contains(Point point) { + return contains(point.x, point.y); + } + + public float u0() { + return x; + } + + public float v0() { + return y; + } + + public float u1() { + return width; + } + + public float v1() { + return height; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/utils/WidgetUtil.java b/src/main/java/com/gregtechceu/gtceu/api/mui/utils/WidgetUtil.java deleted file mode 100644 index 1640fbb087f..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/utils/WidgetUtil.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gregtechceu.gtceu.api.mui.utils; - -import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; -import com.gregtechceu.gtceu.api.mui.widget.ParentWidget; - -import java.util.Objects; - -public class WidgetUtil { - - public static IWidget getWidget(ParentWidget parent, String name) { - for (IWidget child : parent.getChildren()) { - if (Objects.equals(child.getName(), name)) { - return child; - } - if (child instanceof ParentWidget childParent) { - IWidget found = getWidget(childParent, name); - if (found != null) { - return found; - } - } - } - return null; - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java index 8b4245eb3ec..32cfbbe5c06 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/ObjectValue.java @@ -2,8 +2,6 @@ import com.gregtechceu.gtceu.api.mui.base.value.IValue; -import org.jetbrains.annotations.ApiStatus; - import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; @@ -26,7 +24,6 @@ public ObjectValue(Class type, T value) { this.value = value; } - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") @Deprecated public ObjectValue(T value) { this.type = value != null ? (Class) value.getClass() : null; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/AbstractGenericSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/AbstractGenericSyncValue.java index 6d7875be455..844b9ed10c1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/AbstractGenericSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/AbstractGenericSyncValue.java @@ -4,7 +4,6 @@ import net.minecraft.network.FriendlyByteBuf; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; @@ -23,7 +22,11 @@ protected AbstractGenericSyncValue(Class type, Supplier getter, Consumer) this.cache.getClass(); } this.type = type; @@ -44,7 +47,11 @@ protected AbstractGenericSyncValue(Class type, @Nullable Supplier clientGe this.setter = serverSetter != null ? serverSetter : clientSetter; } this.cache = this.getter.get(); - if (type == null && this.cache != null) { + if (type == null) { + if (this.cache == null) { + throw new IllegalArgumentException( + "If the value class is not give, then the getter must return a non null value!"); + } type = (Class) this.cache.getClass(); } this.type = type; @@ -66,8 +73,12 @@ public T getValue() { @Override public void setValue(T value, boolean setSource, boolean sync) { this.cache = createDeepCopyOf(value); + onSetCache(setSource, sync); + } + + protected void onSetCache(boolean setSource, boolean sync) { if (setSource && this.setter != null) { - this.setter.accept(value); + this.setter.accept(this.cache); } onValueChanged(); if (sync) sync(); @@ -100,31 +111,9 @@ public void read(FriendlyByteBuf buffer) { setValue(deserialize(buffer), true, false); } - @SuppressWarnings("unchecked") @Override public Class getValueType() { - return (Class) getType(); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - @SuppressWarnings("unchecked") - public @Nullable Class getType() { - if (this.type != null) return type; - if (this.cache != null) { - return (Class) this.cache.getClass(); - } - T t = this.getter.get(); - if (t != null) { - return (Class) t.getClass(); - } - return null; - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public boolean isOfType(Class expectedType) { - return isValueOfType(expectedType); + return type; } @Override @@ -140,4 +129,28 @@ public boolean isValueOfType(Class expectedType) { public AbstractGenericSyncValue cast() { return (AbstractGenericSyncValue) this; } + + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method forces a sync after the modification. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(Consumer consumer) { + modifyValue(true, true, consumer); + } + + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method can automatically sync the cache after the modification. Be careful with potential issues when the + * sync arg is false. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(boolean setSource, boolean sync, Consumer consumer) { + consumer.accept(this.cache); + onSetCache(setSource, sync); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicLinkedSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicLinkedSyncHandler.java index a950cbedc5e..c9c12f4bfdf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicLinkedSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicLinkedSyncHandler.java @@ -17,7 +17,6 @@ public class DynamicLinkedSyncHandler> extends Syn private IWidgetProvider widgetProvider; private Consumer onWidgetUpdate; - private boolean updateQueued; private IWidget lastRejectedWidget; private final S linkedValue; @@ -45,10 +44,7 @@ public void readOnServer(int id, FriendlyByteBuf buf) { @Override public void init(String key, PanelSyncManager syncManager) { super.init(key, syncManager); - if (this.updateQueued) { - notifyUpdate(true); - this.updateQueued = false; - } + notifyUpdate(false); } private IWidget parseWidget() { @@ -58,7 +54,7 @@ private IWidget parseWidget() { // collects any unregistered sync handlers // since the sync manager is currently locked and we no longer allow bypassing the lock it will crash if it // finds any - int unregistered = WidgetTree.countUnregisteredSyncHandlers(widget); + int unregistered = WidgetTree.countUnregisteredSyncHandlers(getSyncManager(), widget); if (unregistered > 0) { throw new IllegalStateException( "Widgets created by DynamicSyncHandler can't have implicitly registered sync handlers. All" + @@ -86,11 +82,7 @@ private void updateWidget(IWidget widget) { * initialised is effective. */ private void notifyUpdate(boolean sync) { - if (!isValid()) { - // sync handler not yet initialised - this.updateQueued = true; - return; - } + if (!isValid()) return; IWidget widget = parseWidget(); if (getSyncManager().isClient()) { updateWidget(widget); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicSyncHandler.java index 423b15f7f08..f931cc20e2c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/DynamicSyncHandler.java @@ -62,7 +62,7 @@ private IWidget parseWidget(FriendlyByteBuf buf) { // collects any unregistered sync handlers // since the sync manager is currently locked and we no longer allow bypassing the lock it will crash if it // finds any - int unregistered = WidgetTree.countUnregisteredSyncHandlers(widget); + int unregistered = WidgetTree.countUnregisteredSyncHandlers(getSyncManager(), widget); if (unregistered > 0) { throw new IllegalStateException( "Widgets created by DynamicSyncHandler can't have implicitly registered sync" + diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java index 22eaa608f68..7221ba2e727 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericCollectionSyncHandler.java @@ -42,14 +42,14 @@ protected GenericCollectionSyncHandler(@NotNull Supplier getter, @Override public void setValue(C value, boolean setSource, boolean sync) { setCache(value); - onSetCache(value, setSource, sync); + onSetCache(setSource, sync); } protected abstract void setCache(C value); - protected void onSetCache(C value, boolean setSource, boolean sync) { + protected void onSetCache(boolean setSource, boolean sync) { if (setSource && this.setter != null) { - this.setter.accept(value); + this.setter.accept(getValue()); } onValueChanged(); if (sync) sync(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java index 487df9ccb23..af340aa6dbc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericListSyncHandler.java @@ -54,10 +54,11 @@ public List getValue() { @Override public void read(FriendlyByteBuf buffer) { this.cache.clear(); - for (int i = 0; i < buffer.readVarInt(); i++) { + int size = buffer.readVarInt(); + for (int i = 0; i < size; i++) { this.cache.add(deserializeValue(buffer)); } - onSetCache(getValue(), true, false); + onSetCache(true, false); } @Override @@ -65,6 +66,30 @@ public Class> getValueType() { return (Class>) (Object) List.class; } + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method forces a sync after the modification. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(Consumer> consumer) { + modifyValue(true, true, consumer); + } + + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method can automatically sync the cache after the modification. Be careful with potential issues when the + * sync arg is false. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(boolean setSource, boolean sync, Consumer> consumer) { + consumer.accept(this.cache); + onSetCache(setSource, sync); + } + public static Builder builder() { return new Builder<>(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java index 0f4d7df7fc9..df9fa89318f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericMapSyncHandler.java @@ -46,22 +46,27 @@ public GenericMapSyncHandler(Supplier> getter, this.valueSerializer = valueSerializer; this.equals = equals != null ? EqualityTest.wrapNullSafe(equals) : Objects::equals; this.keyCopy = keyCopy != null ? keyCopy : ICopy.ofSerializer(keySerializer, keyDeserializer); - this.valueCopy = valueCopy != null ? valueCopy : ICopy.ofSerializer(valueSerializer, valueDeserializer);; + this.valueCopy = valueCopy != null ? valueCopy : ICopy.ofSerializer(valueSerializer, valueDeserializer); + setCache(this.getter.get()); } @Override public void setValue(Map value, boolean setSource, boolean sync) { + setCache(value); + onSetCache(setSource, sync); + } + + protected void setCache(Map value) { this.cache.clear(); for (Map.Entry entry : value.entrySet()) { this.cache.put(this.keyCopy.createDeepCopy(entry.getKey()), this.valueCopy.createDeepCopy(entry.getValue())); } - onSetCache(value, setSource, sync); } - protected void onSetCache(Map value, boolean setSource, boolean sync) { + protected void onSetCache(boolean setSource, boolean sync) { if (setSource && this.setter != null) { - this.setter.accept(value); + this.setter.accept(getValue()); } onValueChanged(); if (sync) sync(); @@ -108,7 +113,7 @@ public void read(FriendlyByteBuf buffer) { for (int i = 0; i < size; i++) { this.cache.put(this.keyDeserializer.deserialize(buffer), this.valueDeserializer.deserialize(buffer)); } - onSetCache(getValue(), true, false); + onSetCache(true, false); } @Override @@ -121,6 +126,30 @@ public Class> getValueType() { return (Class>) (Object) Map.class; } + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method forces a sync after the modification. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(Consumer> consumer) { + modifyValue(true, true, consumer); + } + + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method can automatically sync the cache after the modification. Be careful with potential issues when the + * sync arg is false. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(boolean setSource, boolean sync, Consumer> consumer) { + consumer.accept(this.cache); + onSetCache(setSource, sync); + } + public static class Builder { private Supplier> getter; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java index 36af4cf6642..df2a78231b9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSetSyncHandler.java @@ -53,7 +53,7 @@ public void read(FriendlyByteBuf buffer) { for (int i = 0; i < size; i++) { this.cache.add(deserializeValue(buffer)); } - onSetCache(getValue(), true, false); + onSetCache(true, false); } @Override @@ -61,6 +61,30 @@ public Class> getValueType() { return (Class>) (Object) Set.class; } + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method forces a sync after the modification. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(Consumer> consumer) { + modifyValue(true, true, consumer); + } + + /** + * Allows safe modification of the cached value. Normally modifying the cached value can cause the value to never be + * synced. + * This method can automatically sync the cache after the modification. Be careful with potential issues when the + * sync arg is false. + * + * @param consumer function that operates on the current cached value + */ + public void modifyValue(boolean setSource, boolean sync, Consumer> consumer) { + consumer.accept(this.cache); + onSetCache(setSource, sync); + } + public static Builder builder() { return new Builder<>(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java index 9a0231dce17..d60b3c1710e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/GenericSyncValue.java @@ -19,16 +19,47 @@ import java.util.function.Consumer; import java.util.function.Supplier; +/** + * A highly configurable value sync handler for any type. The constructors are obsolete in favor of the builder. + * Create a builder with {@link #builder(Class)}, {@link #rawTypeBuilder(Class)} or {@link #notNullBuilder()}. + * Each of these methods has its uses, however you should always try to use the {@link #builder(Class)} method. + *

+ * Example: + * GenericSyncValue.builder(ItemStack.class) + *

+ * When you work with types which themselves have generic types, then your IDE will likely yell at you. In this case you + * can use + * {@link #rawTypeBuilder(Class)}. Only use this if you have to, since you can technically put any class inside there + * without ModularUI be + * able to verify it. Since you can't specify the type {@link T} with the type here you need to use the diamond + * operator. + *

+ * Example: GenericSyncValue.<List<ItemStack>>rawTypeBuilder(List.class) + *
+ * Note that you wouldn't actually use {@link java.util.List List} here. It's just an example for a type with a generic + * parameter. + *

+ * If the value is never null you can also use {@link #notNullBuilder()}. This will infer the type with the value + * supplier. + *

+ * Example: GenericSyncValue.<ItemStack>notNullBuilder() + *

+ *

+ * For collections, it is highly recommended to use {@link GenericListSyncHandler}, {@link GenericSetSyncHandler} or + * {@link GenericMapSyncHandler}. For custom collections {@link GenericCollectionSyncHandler} can be helpful. + * + * @param type of the value to sync + */ public class GenericSyncValue extends AbstractGenericSyncValue { public static GenericSyncValue forItem(@NotNull Supplier getter, @Nullable Consumer setter) { - return new GenericSyncValue<>(getter, setter, ByteBufAdapters.ITEM_STACK); + return new GenericSyncValue<>(ItemStack.class, getter, setter, ByteBufAdapters.ITEM_STACK); } public static GenericSyncValue forFluid(@NotNull Supplier getter, @Nullable Consumer setter) { - return new GenericSyncValue<>(getter, setter, ByteBufAdapters.FLUID_STACK); + return new GenericSyncValue<>(FluidStack.class, getter, setter, ByteBufAdapters.FLUID_STACK); } private final IByteBufDeserializer deserializer; @@ -36,85 +67,6 @@ public static GenericSyncValue forFluid(@NotNull Supplier equals; private final ICopy copy; - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @Nullable Consumer setter, - @NotNull IByteBufAdapter adapter) { - this(getter, setter, adapter, adapter, adapter, null); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @Nullable Consumer setter, - @NotNull IByteBufAdapter adapter, - @Nullable ICopy copy) { - this(getter, setter, adapter, adapter, adapter, copy); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @Nullable Consumer setter, - @NotNull IByteBufDeserializer deserializer, - @NotNull IByteBufSerializer serializer) { - this(getter, setter, deserializer, serializer, null, null); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @Nullable Consumer setter, - @NotNull IByteBufDeserializer deserializer, - @NotNull IByteBufSerializer serializer, - @Nullable ICopy copy) { - this(getter, setter, deserializer, serializer, null, copy); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @NotNull IByteBufAdapter adapter) { - this(getter, null, adapter, adapter, adapter, null); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @NotNull IByteBufAdapter adapter, - @Nullable ICopy copy) { - this(getter, null, adapter, adapter, adapter, copy); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @NotNull IByteBufDeserializer deserializer, - @NotNull IByteBufSerializer serializer) { - this(getter, null, deserializer, serializer, null, null); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @NotNull IByteBufDeserializer deserializer, - @NotNull IByteBufSerializer serializer, - @Nullable ICopy copy) { - this(getter, null, deserializer, serializer, null, copy); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Supplier getter, - @Nullable Consumer setter, - @NotNull IByteBufDeserializer deserializer, - @NotNull IByteBufSerializer serializer, - @Nullable EqualityTest equals, - @Nullable ICopy copy) { - this(null, getter, setter, deserializer, serializer, equals, copy); - } - @ApiStatus.Obsolete public GenericSyncValue(@NotNull Class type, @NotNull Supplier getter, @@ -125,34 +77,12 @@ public GenericSyncValue(@NotNull Class type, this(type, getter, setter, adapter, adapter, adapter, copy, nullable); } - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public GenericSyncValue(@NotNull Class type, - @NotNull Supplier getter, - @Nullable Consumer setter, - @NotNull IByteBufAdapter adapter, - @Nullable ICopy copy) { - this(type, getter, setter, adapter, adapter, adapter, copy); - } - @ApiStatus.Obsolete public GenericSyncValue(@NotNull Class type, @NotNull Supplier getter, @Nullable Consumer setter, @NotNull IByteBufAdapter adapter) { - this(type, getter, setter, adapter, adapter, adapter, null); - } - - @ApiStatus.ScheduledForRemoval(inVersion = "3.3.0") - @Deprecated - public GenericSyncValue(@NotNull Class type, - @NotNull Supplier getter, - @Nullable Consumer setter, - @NotNull IByteBufDeserializer deserializer, - @NotNull IByteBufSerializer serializer, - @Nullable EqualityTest equals, - @Nullable ICopy copy) { - this(type, getter, setter, deserializer, serializer, equals, copy, false); + this(type, getter, setter, adapter, adapter, adapter, null, false); } @ApiStatus.Obsolete @@ -200,6 +130,44 @@ public GenericSyncValue cast() { return (GenericSyncValue) this; } + /** + * Creates a builder for a generic sync value. This is the recommended builder method. + * The other builder methods are for when type has generic parameters. + * + * @param type Class of the value to sync. This is used to verify synced value types. + * @param type of the value to sync + * @return builder + */ + public static Builder builder(Class type) { + return new Builder<>(type); + } + + /** + * Creates a builder for a generic sync value. This method should only be used if the type has generic parameters. + * The downside of this method is that the compiler can't verify the passed in class. Technically any class can be + * passed on, + * but issues will arise later down the line. + * + * @param type Class of the value to sync. This is used to verify synced value types. + * @param type of the value to sync + * @return builder + */ + @SuppressWarnings("unchecked") + public static Builder rawTypeBuilder(Class type) { + return new Builder((Class) type); + } + + /** + * Creates a builder for a generic sync value. This method should only be used if the value is never null. + * The class is inferred from the value of the value supplier once. + * + * @param type of the value to sync + * @return builder + */ + public static Builder notNullBuilder() { + return new Builder<>(null); + } + public static class Builder { private final Class type; @@ -215,59 +183,192 @@ public Builder(Class type) { this.type = type; } + /** + * Sets the getter for the sync value. Usually this returns a field in a + * {@link net.minecraft.world.level.block.entity.BlockEntity BlockEntity} or + * similar. On server side this is called every tick and compared to the sync values cache. If the values are + * different + * (determined by {@link #equals(EqualityTest)}), it is synced to the client. + *

+ * This setter is required! + *

+ * + * @param getter function that returns the current value that may be synced + * @return this builder + */ public Builder getter(Supplier getter) { this.getter = getter; return this; } + /** + * Sets the setter for the sync value. Usually this sets a field in a + * {@link net.minecraft.world.level.block.entity.BlockEntity BlockEntity} or + * similar. This is called when a value is synced in client or server. In many cases this can be null since the + * synced value is + * cached inside the sync handler. + *

+ * This setter is optional! + *

+ * + * @param setter function that updates the source of the value + * @return this builder + */ public Builder setter(Consumer setter) { this.setter = setter; return this; } + /** + * Sets a function which writes the value to a {@link FriendlyByteBuf}. The function is called every time the + * value is synced to the + * other side. + *

+ * This setter is required! + *

+ * + * @param deserializer function that writes the value to a packet buffer + * @return this builder + */ public Builder deserializer(IByteBufDeserializer deserializer) { this.deserializer = deserializer; return this; } + /** + * Sets a function which reads the value from a {@link FriendlyByteBuf}. The function is called every time the + * value is synced to the + * other side. + *

+ * This setter is required! + *

+ * + * @param serializer function that reads the value from a packet buffer + * @return this builder + */ public Builder serializer(IByteBufSerializer serializer) { this.serializer = serializer; return this; } + /** + * Sets a function which tests two instances of the value for differences. This function is called every tick on + * server to determine + * if the value from {@link #getter(Supplier)} needs to be synced. By default, this uses + * {@link Objects#equals(Object, Object)}. + * If your value does not implement {@link Object#equals(Object)}, then this setter must be called in order for + * it to function + * properly. Otherwise {@link Objects#equals(Object, Object)} always returns false since the instances will + * always be different, + * which causes the value to be synced every tick. + *

+ * This setter is optional! + *

+ * + * @param equals function that determines if two instances of the value are equal + * @return this builder + */ public Builder equals(EqualityTest equals) { this.equals = equals; return this; } + /** + * Sets the equals function to {@link Objects#equals(Object, Object)}, which is the default function. + * + * @return this builder + * @see #equals(EqualityTest) + */ public Builder equalsDefault() { return equals(EqualityTest.defaultTester()); } - public Builder equalsReference() { - return equals((a, b) -> a == b); - } - + /** + * Sets a function which creates a copy of the value. This is called every time the value cache is updated. This + * is to prevent + * accidental mutations of the cache value. For example if you called {@link #setValue(Object)}, but keep a + * reference to the new + * value and then modify your reference, then the cached value is also updated since it's the same object. If + * now the + * {@link #getter(Supplier)} function happens to return exactly that reference, then the + * {@link #equals(EqualityTest)} function always + * compares its cache to itself (since it compare the cache to the getter value, which are the same in this + * case). This causes + * the value to be never synced from server to client. + *

+ * By default, the {@link #serializer(IByteBufSerializer)} and {@link #deserializer(IByteBufDeserializer)} + * function are called to + * create a new instance. If these functions are implemented properly, it is always guaranteed to create a new + * instance of the + * value. However, it is still recommended to provide your own proper copy method. + *

+ * If you know, that your values is immutable (can't be modified once created), then you can use + * {@link #copyImmutable()}. + * That function won't copy the value, but just return the value. + *

+ * This setter is optional! + *

+ * + * @param copy function that creates a new exact copy of the value + * @return this builder + */ public Builder copy(ICopy copy) { this.copy = copy; return this; } + /** + * Sets a {@link #copy(ICopy)} function which assumes the values are always immutable. This should only be used + * if the value is + * always immutable (can't be modified once created). See {@link #copy(ICopy)} for more info. + * + * @return this builder + * @see #copy(ICopy) + */ public Builder copyImmutable() { return copy(ICopy.immutable()); } + /** + * Sets an adapter. This combines {@link #deserializer(IByteBufDeserializer)}, + * {@link #serializer(IByteBufSerializer)} and + * {@link #equals(EqualityTest)} into one method. + * + * @param adapter byte buf adapter + * @return this builder + * @see #deserializer(IByteBufDeserializer) + * @see #serializer(IByteBufSerializer) + * @see #equals(EqualityTest) + */ public Builder adapter(IByteBufAdapter adapter) { return deserializer(adapter) .serializer(adapter) .equals(adapter); } + /** + * Sets the value to be nullable. This wraps all the used functions into null safe variants. This only for + * convenience. + * Manually having to consider nullability inside all the function is cumbersome. This setter is a shortcut. + * It is opt-in since, it creates a very minor overhead in the serializer and deserializer. + *

+ * This setter is optional! + *

+ * + * @return this builder + */ public Builder nullable() { this.nullable = true; return this; } + /** + * Creates the sync value from this builder. + * + * @return new sync value handler + * @throws NullPointerException if the getter, serializer or deserializer is null + * @throws IllegalArgumentException if the value type is null and the getter returns null + */ public GenericSyncValue build() { return new GenericSyncValue<>(type, getter, setter, deserializer, serializer, equals, copy, nullable); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ISyncRegistrar.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ISyncRegistrar.java index 09e459d8db6..c7980dcf4a0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ISyncRegistrar.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ISyncRegistrar.java @@ -123,6 +123,18 @@ default T getOrCreateSyncHandler(String name, Class c T getOrCreateSyncHandler(String name, int id, Class clazz, Supplier supplier); + default T getOrCreateSH(String name, Class clazz, Supplier supplier) { + return getOrCreateSyncHandler(name, 0, clazz, supplier); + } + + default T getOrCreateSH(String name, int id, Class clazz, Supplier supplier) { + return getOrCreateSyncHandler(name, id, clazz, supplier); + } + + default ItemSlotSyncHandler getOrCreateSlot(String name, Supplier slotSupplier) { + return getOrCreateSlot(name, 0, slotSupplier); + } + default ItemSlotSyncHandler getOrCreateSlot(String name, int id, Supplier slotSupplier) { return getOrCreateSyncHandler(name, id, ItemSlotSyncHandler.class, () -> new ItemSlotSyncHandler(slotSupplier.get())); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSyncHandler.java index acbb2385ec0..3998f85ad8b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ItemSlotSyncHandler.java @@ -51,6 +51,15 @@ public void dispose() { @Override public void detectAndSendChanges(boolean init) { + checkUpdate(init); + } + + public void checkUpdate() { + checkUpdate(false); + } + + private void checkUpdate(boolean init) { + if (!isValid() || getSyncManager().isClient()) return; ItemStack itemStack = getSlot().getItem(); if (itemStack.isEmpty() && this.lastStoredItem.isEmpty()) return; boolean onlyAmountChanged = false; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java index df284f0050a..4f53a2ce07f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/ModularSyncManager.java @@ -223,12 +223,6 @@ public SlotGroup getSlotGroup(String name) { return this.mainPSM.getSlotGroup(name); } - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public static String makeSyncKey(String name, int id) { - return ISyncRegistrar.makeSyncKey(name, id); - } - public boolean isOpen() { return this.state == State.OPEN; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java index ca3d2c724e1..77a3e42300c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java @@ -168,8 +168,8 @@ public void setCursorItem(ItemStack stack) { @Override public boolean hasSyncHandler(SyncHandler syncHandler) { - return syncHandler.isValid() && syncHandler.getSyncManager() == this && - this.reverseSyncHandlers.containsKey(syncHandler); + if (this.reverseSyncHandlers.containsKey(syncHandler)) return true; + return this != getHyperVisor() && getHyperVisor().hasSyncHandler(syncHandler); } private void putSyncValue(String name, int id, SyncHandler syncHandler) { @@ -213,19 +213,6 @@ public PanelSyncManager syncValue(String name, int id, SyncHandler syncHandler) return this; } - /** - * @deprecated replaced by {@link #syncedPanel(String, boolean, PanelSyncHandler.IPanelBuilder)} - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.3.0") - @Deprecated - public IPanelHandler panel(String key, PanelSyncHandler.IPanelBuilder panelBuilder, boolean subPanel) { - SyncHandler sh = this.subPanels.get(key); - if (sh != null) return (IPanelHandler) sh; - PanelSyncHandler syncHandler = new PanelSyncHandler(panelBuilder, subPanel); - this.subPanels.put(key, syncHandler); - return syncHandler; - } - /** * Creates a synced panel handler. This can be used to automatically handle syncing for synced panels. * Synced panels do not need to be synced themselves, but contain at least one widget which is synced. @@ -376,12 +363,6 @@ public Collection getSlotGroups() { return this.slotGroups.values(); } - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public @Nullable SyncHandler getSyncHandler(String mapKey) { - return getSyncHandlerFromMapKey(mapKey); - } - public @Nullable SyncHandler getSyncHandlerFromMapKey(String mapKey) { return this.syncHandlers.get(mapKey); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java index a29d4991d3e..6150cbbb246 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandler.java @@ -158,8 +158,11 @@ public PanelSyncManager getSyncManager() { return this.syncManager; } - public final boolean isRegistered() { - return isValid() && this.syncManager.hasSyncHandler(this); + public final boolean isRegistered(PanelSyncManager syncManager) { + if (isValid() && this.syncManager.hasSyncHandler(this)) { + return true; + } + return syncManager.hasSyncHandler(this); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java index 7c78f022083..9a33c4146d1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/SyncHandlers.java @@ -51,6 +51,6 @@ public static > EnumSyncValue enumValue(Class clazz, Sup } public static GenericSyncValue.Builder generic(Class type) { - return new GenericSyncValue.Builder<>(type); + return GenericSyncValue.builder(type); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/AbstractScrollWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/AbstractScrollWidget.java index 3449941f3e0..ed344b7a0fd 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/AbstractScrollWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/AbstractScrollWidget.java @@ -55,35 +55,30 @@ public void transformChildren(IViewportStack stack) { stack.translate(-getScrollX(), -getScrollY()); } - @Override - public void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (isInside(stack, x, y)) { - widgets.add(this, stack.peek(), getAdditionalHoverInfo(stack, x, y)); - } - } - @Override public void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (getArea().isInside(x, y) && !getScrollArea().isInsideScrollbarArea(x, y) && hasChildren()) { - IViewport.getChildrenAt(this, stack, widgets, x, y); + // if 'widgets.peek() == this' is true, only then this widget is hovered + // we should require this since a stencil is applied to this widget + if (widgets.peek() == this && !getScrollArea().isInsideScrollbarArea(x, y)) { + IViewport.super.getWidgetsAt(stack, widgets, x, y); } } public void beforeResize(boolean onOpen) { super.beforeResize(onOpen); this.scroll.applyWidgetTheme(getPanel().getTheme().getScrollbarTheme().getTheme(isHovering())); - if (onOpen) checkScrollbarActive(true); + checkScrollbarActive(false); getScrollArea().getScrollPadding().scrollPaddingAll(0); applyAdditionalOffset(this.scroll.getScrollX()); applyAdditionalOffset(this.scroll.getScrollY()); } - private void checkScrollbarActive(boolean onOpen) { + protected void checkScrollbarActive(boolean resizeOnChange) { boolean scrollYActive = this.scroll.getScrollY() != null && this.scroll.getScrollY().isScrollBarActive(getScrollArea()); boolean scrollXActive = this.scroll.getScrollX() != null && - this.scroll.getScrollX().isScrollBarActive(getScrollArea(), this.scrollYActive); - if (!onOpen && (scrollYActive != this.scrollYActive || scrollXActive != this.scrollXActive)) { + this.scroll.getScrollX().isScrollBarActive(getScrollArea(), scrollYActive); + if (resizeOnChange && (scrollYActive != this.scrollYActive || scrollXActive != this.scrollXActive)) { scheduleResize(); } this.scrollXActive = scrollXActive; @@ -137,6 +132,12 @@ public void onMouseDrag(double mouseX, double mouseY, int button, double dragX, this.scroll.drag(getContext().getMouseX(), getContext().getMouseY()); } + @Override + public void onUpdate() { + super.onUpdate(); + checkScrollbarActive(true); + } + @Override public void preDraw(ModularGuiContext context, boolean transformed) { if (!transformed) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DelegatingSingleChildWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DelegatingSingleChildWidget.java deleted file mode 100644 index b60b0052d8a..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DelegatingSingleChildWidget.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gregtechceu.gtceu.api.mui.widget; - -public class DelegatingSingleChildWidget> extends SingleChildWidget { - - @Override - public void onInit() { - super.onInit(); - if (hasChildren()) getChild().flex().relative(getParent()); - coverChildren(); - } - - @Override - public void postResize() { - super.postResize(); - if (hasChildren()) { - getArea().set(getChild().getArea()); - getArea().rx = getChild().getArea().rx; - getArea().ry = getChild().getArea().ry; - getChild().getArea().rx = 0; - getChild().getArea().ry = 0; - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DragHandle.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DragHandle.java index 9063eda9ab2..07d059f1bd7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DragHandle.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DragHandle.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.api.mui.widget; +import com.gregtechceu.gtceu.api.mui.base.layout.IViewport; import com.gregtechceu.gtceu.api.mui.base.layout.IViewportStack; import com.gregtechceu.gtceu.api.mui.base.widget.IDraggable; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; @@ -13,7 +14,7 @@ import org.jetbrains.annotations.Nullable; -public class DragHandle extends Widget implements IDraggable { +public class DragHandle extends Widget implements IDraggable, IViewport { private IDraggable parentDraggable; @@ -88,22 +89,26 @@ public void transform(IViewportStack stack) { @Override public void transformChildren(IViewportStack stack) { - if (this.parentDraggable != null) { - this.parentDraggable.transformChildren(stack); + if (this.parentDraggable instanceof IViewport viewport) { + viewport.transformChildren(stack); } } @Override public void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (this.parentDraggable != null) { - this.parentDraggable.getWidgetsAt(stack, widgets, x, y); + if (this.parentDraggable instanceof IViewport viewport) { + viewport.getWidgetsAt(stack, widgets, x, y); + } else { + IViewport.super.getWidgetsAt(stack, widgets, x, y); } } @Override public void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (this.parentDraggable != null) { - this.parentDraggable.getSelfAt(stack, widgets, x, y); + if (this.parentDraggable instanceof IViewport viewport) { + viewport.getSelfAt(stack, widgets, x, y); + } else { + IViewport.super.getSelfAt(stack, widgets, x, y); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DraggableWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DraggableWidget.java index 8f172cc7392..095b590fb10 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DraggableWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/DraggableWidget.java @@ -15,7 +15,7 @@ * A widget that can be picked up by the cursor. * Might not work as expected when a parent is scaling or rotating itself. */ -public class DraggableWidget> extends Widget implements IDraggable { +public class DraggableWidget> extends Widget implements IDraggable, IViewport { @Getter private boolean moving = false; @@ -73,7 +73,7 @@ public void setMoving(boolean moving) { @Override public void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { if (!isMoving() && isInside(stack, x, y)) { - widgets.add(this, stack.peek(), getAdditionalHoverInfo(stack, x, y)); + widgets.add(this, stack, getAdditionalHoverInfo(stack, x, y)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java index 3563c4a86f2..e7258b9d321 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/Widget.java @@ -47,7 +47,7 @@ public class Widget> extends AbstractWidget implements IPosi // other @Getter - private boolean excludeAreaInXei = false; + private boolean excludeAreaInRecipeViewer = false; // sizing private BiConsumer transform; // syncing @@ -134,8 +134,8 @@ void onInitInternal(boolean late) { if (!getScreen().isClientOnly()) { initialiseSyncHandler(getScreen().getSyncManager(), late); } - if (isExcludeAreaInXei()) { - getContext().getXeiSettings().addExclusionArea(this); + if (isExcludeAreaInRecipeViewer()) { + getContext().getRecipeViewerSettings().addExclusionArea(this); } } @@ -153,7 +153,6 @@ public void initialiseSyncHandler(ModularSyncManager syncManager, boolean late) } } if (handler != null) setSyncOrValue(handler); - setSyncHandler(handler); if (this.syncHandler instanceof ValueSyncHandler valueSyncHandler && valueSyncHandler.getChangeListener() == null) { valueSyncHandler.setChangeListener(this::markTooltipDirty); @@ -173,8 +172,8 @@ public void dispose() { getScreen().removeGuiActionListener(action); } } - if (isExcludeAreaInXei()) { - getContext().getXeiSettings().removeExclusionArea(this); + if (isExcludeAreaInRecipeViewer()) { + getContext().getRecipeViewerSettings().removeExclusionArea(this); } } super.dispose(); @@ -642,49 +641,26 @@ public W syncHandler(String name, int id) { return getThis(); } - /** - * Used for widgets to set a value handler.
- * Will also call {@link #setSyncHandler(SyncHandler)} if it is a SyncHandler - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - protected void setValue(IValue value) { - this.value = value; - if (value instanceof SyncHandler handler) { - setSyncHandler(handler); - } - } - - /** - * Used for widgets to set a sync handler. - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - protected void setSyncHandler(@Nullable SyncHandler syncHandler) { - if (syncHandler != null) checkValidSyncOrValue(syncHandler); - this.syncHandler = syncHandler; - } - @MustBeInvokedByOverriders protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) { if (!syncOrValue.isSyncHandler() && !syncOrValue.isValueHandler()) return; checkValidSyncOrValue(syncOrValue); - if (syncOrValue instanceof SyncHandler syncHandler1) setSyncHandler(syncHandler1); - if (syncOrValue instanceof IValue value1) setValue(value1); + if (syncOrValue instanceof SyncHandler syncHandler) this.syncHandler = syncHandler; + if (syncOrValue instanceof IValue value) this.value = value; } // ------------- // === Other === // ------------- - public W excludeAreaInXei() { - return excludeAreaInXei(true); + public W excludeAreaInRecipeViewer() { + return excludeAreaInRecipeViewer(true); } - public W excludeAreaInXei(boolean val) { - this.excludeAreaInXei = val; + public W excludeAreaInRecipeViewer(boolean val) { + this.excludeAreaInRecipeViewer = val; if (isValid()) { - getContext().getXeiSettings().addExclusionArea(this); + getContext().getRecipeViewerSettings().addExclusionArea(this); } return getThis(); } @@ -708,15 +684,6 @@ public Object getAdditionalHoverInfo(IViewportStack viewportStack, int mouseX, i return null; } - /** - * @deprecated this got renamed to name - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public W debugName(String name) { - return name(name); - } - /** * This can be used to find the widget with various methods from {@link WidgetTree} from a parent. * The name is also included in {@link #toString()}. diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java index a1caa48768c..cabe7bfd6cf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/WidgetTree.java @@ -206,7 +206,7 @@ public static void collectSyncValues(PanelSyncManager syncManager, String panelN String syncKey = ModularSyncManager.AUTO_SYNC_PREFIX + panelName; foreachChildBFS(panel, widget -> { if (widget instanceof ISynced synced) { - if (synced.isSynced() && !synced.getSyncHandler().isRegistered()) { + if (synced.isSynced() && !synced.getSyncHandler().isRegistered(syncManager)) { syncManager.syncValue(syncKey, id.getAndIncrement(), synced.getSyncHandler()); } } @@ -214,10 +214,11 @@ public static void collectSyncValues(PanelSyncManager syncManager, String panelN }, includePanel); } - public static int countUnregisteredSyncHandlers(IWidget parent) { + public static int countUnregisteredSyncHandlers(PanelSyncManager syncManager, IWidget parent) { MutableInt count = new MutableInt(); foreachChildBFS(parent, widget -> { - if (widget instanceof ISynced synced && synced.isSynced() && !synced.getSyncHandler().isRegistered()) { + if (widget instanceof ISynced synced && synced.isSynced() && + !synced.getSyncHandler().isRegistered(syncManager)) { count.increment(); } return true; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/scroll/ScrollArea.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/scroll/ScrollArea.java index 93b1fa6e688..7da82d30a3d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/scroll/ScrollArea.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/scroll/ScrollArea.java @@ -101,9 +101,9 @@ public boolean mouseScroll(GuiContext context) { */ public boolean mouseScroll(int x, int y, double scroll, boolean shift) { ScrollData data; - if (this.scrollX != null) { - data = this.scrollY == null || shift ? this.scrollX : this.scrollY; - } else if (this.scrollY != null) { + if (this.scrollX != null && this.scrollX.isScrollBarActive(this)) { + data = this.scrollY == null || !this.scrollY.isScrollBarActive(this) || shift ? this.scrollX : this.scrollY; + } else if (this.scrollY != null && this.scrollY.isScrollBarActive(this)) { data = this.scrollY; } else { // no scroll data present -> cant be scrolled diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/DimensionSizer.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/DimensionSizer.java index 4d83bbc6784..c20158e784c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/DimensionSizer.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/DimensionSizer.java @@ -356,6 +356,15 @@ public int calcPoint(Unit p, Box padding, int width, int parentSize, boolean par return (int) val; } + public void detectConflictingConfiguration() { + if (this.expanded && this.coverChildren) { + GTCEu.LOGGER.warn( + "Resizer '{}' has expanded() and coverChildren() on {} axis. This conflicts and may cause layout issues.", + this.resizer, this.axis); + } + // TODO detect when this depends and all siblings depend on parent and parent depends on all children + } + /** * Tries to find a unit for start, end or size. If p1 and p2 are already used, the first one will be overwritten. * diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/StandardResizer.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/StandardResizer.java index bee1a417d9e..e62f9bb0e82 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/StandardResizer.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widget/sizer/StandardResizer.java @@ -1,13 +1,16 @@ package com.gregtechceu.gtceu.api.mui.widget.sizer; +import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.mui.GuiError; import com.gregtechceu.gtceu.api.mui.base.GuiAxis; import com.gregtechceu.gtceu.api.mui.base.layout.ILayoutWidget; import com.gregtechceu.gtceu.api.mui.base.layout.IResizeable; import com.gregtechceu.gtceu.api.mui.base.widget.*; import com.gregtechceu.gtceu.api.mui.utils.Alignment; +import com.gregtechceu.gtceu.api.mui.widgets.layout.IExpander; import com.gregtechceu.gtceu.core.mixins.client.SlotAccessor; +import lombok.Getter; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -21,6 +24,7 @@ public class StandardResizer extends WidgetResizeNode implements IPositioned this.blue, this::updateBlue)))) - .childIf(alphaSlider != null, alphaSlider); + .childIf(alphaSlider != null, () -> alphaSlider); } private IWidget createHSVPage(IWidget alphaSlider) { @@ -159,7 +159,7 @@ private IWidget createHSVPage(IWidget alphaSlider) { .name("value") .bounds(0, 1) .value(new DoubleValue.Dynamic(() -> this.value, this::updateValue)))) - .childIf(alphaSlider != null, alphaSlider); + .childIf(alphaSlider != null, () -> alphaSlider); } private static SliderWidget createSlider(IDrawable background) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/Expandable.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/Expandable.java index 48ec22979a6..a9377e36bf0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/Expandable.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/Expandable.java @@ -4,10 +4,8 @@ import com.gregtechceu.gtceu.api.mui.animation.MutableObjectAnimator; import com.gregtechceu.gtceu.api.mui.base.drawable.IInterpolation; import com.gregtechceu.gtceu.api.mui.base.layout.IViewport; -import com.gregtechceu.gtceu.api.mui.base.layout.IViewportStack; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.base.widget.Interactable; -import com.gregtechceu.gtceu.api.mui.utils.HoveredWidgetList; import com.gregtechceu.gtceu.api.mui.utils.Interpolation; import com.gregtechceu.gtceu.api.mui.utils.Rectangle; import com.gregtechceu.gtceu.api.mui.widget.EmptyWidget; @@ -125,20 +123,6 @@ public void postDraw(ModularGuiContext context, boolean transformed) { } } - @Override - public void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (isInside(stack, x, y)) { - widgets.add(this, stack.peek(), getAdditionalHoverInfo(stack, x, y)); - } - } - - @Override - public void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (hasChildren()) { - IViewport.getChildrenAt(this, stack, widgets, x, y); - } - } - public Expandable expanded(boolean expanded) { if (this.expanded == expanded) return this; this.expanded = expanded; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java index 0e3b911b03a..8a6b707e559 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ItemDisplayWidget.java @@ -8,9 +8,9 @@ import com.gregtechceu.gtceu.api.mui.value.ObjectValue; import com.gregtechceu.gtceu.api.mui.widget.Widget; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; -import com.gregtechceu.gtceu.integration.xei.entry.EntryList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.EntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ListWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ListWidget.java index e172abdeed5..0aa1d39859d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ListWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ListWidget.java @@ -156,6 +156,7 @@ public boolean shouldIgnoreChildSize(IWidget child) { public void onChildChangeEnabled(IWidget child, boolean enabled) { if (this.collapseDisabledChild) { ILayoutWidget.super.onChildChangeEnabled(child, enabled); + checkScrollbarActive(true); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SchemaWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SchemaWidget.java index 94be2e93b74..90fe8945e8a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SchemaWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SchemaWidget.java @@ -24,7 +24,7 @@ public class SchemaWidget extends Widget implements Interactable { private boolean enableTranslation = true; private boolean enableScaling = true; private float scale = 10f; - private float pitch = GTMath.QUART_PI; + private float pitch = GTMath.PI_QUART; private float yaw = 0; private final Vector3f offset = new Vector3f(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java index e1cba81f5b0..ff678f520b2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java @@ -81,24 +81,6 @@ public void onInit() { } } - @Override - public void afterInit() { - super.afterInit(); - if (this.slotGroup != null) { - for (IWidget widget : getChildren()) { - if (widget instanceof ItemSlot itemSlot) { - itemSlot.getSlot().slotGroup(this.slotGroup); - } - } - } else if (this.slotGroupName != null) { - for (IWidget widget : getChildren()) { - if (widget instanceof ItemSlot itemSlot) { - itemSlot.getSlot().slotGroup(this.slotGroupName); - } - } - } - } - @Override protected void onChildAdd(IWidget child) { super.onChildAdd(child); @@ -114,6 +96,12 @@ protected void onChildAdd(IWidget child) { if (this.sortButtonsEditor != null) { this.sortButtonsEditor.accept(sortButtons); } + } else if (child instanceof ItemSlot slot && slot.isSynced() && slot.getSlot() != null) { + if (this.slotGroup != null) { + slot.getSlot().slotGroup(this.slotGroup); + } else if (this.slotGroupName != null) { + slot.getSlot().slotGroup(this.slotGroupName); + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/TextWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/TextWidget.java index ec7fb8aeb28..0409f762770 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/TextWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/TextWidget.java @@ -142,7 +142,12 @@ public void postResize() { this.textForDefaultSize = null; } + @Deprecated public W alignment(Alignment alignment) { + return textAlign(alignment); + } + + public W textAlign(Alignment alignment) { this.alignment = alignment; return getThis(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ToggleButton.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ToggleButton.java index 332779f416f..2f9b690ee36 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ToggleButton.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ToggleButton.java @@ -3,10 +3,12 @@ import com.gregtechceu.gtceu.api.mui.base.ITheme; import com.gregtechceu.gtceu.api.mui.base.drawable.IDrawable; import com.gregtechceu.gtceu.api.mui.base.value.IBoolValue; +import com.gregtechceu.gtceu.api.mui.base.value.IIntValue; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.theme.SelectableTheme; import com.gregtechceu.gtceu.api.mui.theme.WidgetTheme; import com.gregtechceu.gtceu.api.mui.theme.WidgetThemeEntry; +import com.gregtechceu.gtceu.api.mui.value.BoolValue; import com.gregtechceu.gtceu.client.mui.screen.RichTooltip; import lombok.Getter; @@ -50,6 +52,11 @@ public ToggleButton value(IBoolValue boolValue) { return super.value(boolValue); } + public ToggleButton valueWrapped(IIntValue intValue, int trueValue) { + return value( + new BoolValue.Dynamic(() -> intValue.getIntValue() == trueValue, v -> intValue.setIntValue(trueValue))); + } + public ToggleButton selectedBackground(IDrawable... selectedBackground) { return background(true, selectedBackground); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/layout/Flow.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/layout/Flow.java index bb9ee8a812c..cd911e41580 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/layout/Flow.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/layout/Flow.java @@ -224,7 +224,7 @@ public static boolean layoutCrossAxisListLike(IWidget parent, List f GuiAxis other = axis.getOther(); boolean isWrapped = flows.size() > 1; // padding is applied in layoutCrossAxis() - int availableSize = parent.resizer().hasSize(other) ? parent.getArea().getSize(other) : -1; + int availableSize = parent.resizer().isSizeCalculated(other) ? parent.getArea().getSize(other) : -1; Box padding = parent.getArea().getPadding(); if (!isWrapped) { // simplified logic for non-wrapped @@ -236,7 +236,7 @@ public static boolean layoutCrossAxisListLike(IWidget parent, List f // when covering children we can assume START crossAxisAlignment = Alignment.CrossAxis.START; } - if (crossAxisAlignment != Alignment.CrossAxis.START && !parent.resizer().hasSize(other)) return false; + if (crossAxisAlignment != Alignment.CrossAxis.START && !parent.resizer().isSizeCalculated(other)) return false; int total = (flows.size() - 1) * crossAxisSpaceBetween; // start with cross axis child padding for total size for (SimpleFlow flow : flows) { flow.calculateCrossAxisSize(axis); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/AbstractMenuButton.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/AbstractMenuButton.java index 38b50cf4f4a..79122c2ff75 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/AbstractMenuButton.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/AbstractMenuButton.java @@ -69,11 +69,11 @@ public AbstractMenuButton(String panelName) { /** * @return true if the menu is currently soft open (opened by hovering) */ - protected boolean isSoftOpen() { + public boolean isSoftOpen() { return softOpen; } - protected void toggleMenu(boolean soft) { + public void toggleMenu(boolean soft) { if (this.open) { if (this.softOpen) { if (soft) { @@ -93,7 +93,7 @@ protected void toggleMenu(boolean soft) { } } - protected void openMenu(boolean soft) { + public void openMenu(boolean soft) { if (this.open) { if (this.softOpen && !soft) { this.softOpen = false; @@ -109,11 +109,11 @@ protected void openMenu(boolean soft) { this.softOpen = soft; } - protected void closeMenu(boolean soft) { + public void closeMenu(boolean soft) { if (!this.open || (!this.softOpen && soft)) return; - if (getPanel() instanceof MenuPanel menuPanel) { + if (isValid() && getPanel() instanceof MenuPanel menuPanel) { menuPanel.remove(getMenu()); - } else { + } else if (getPanelHandler().isPanelOpen()) { getPanelHandler().closePanel(); } this.open = false; @@ -190,15 +190,15 @@ protected boolean forEachSiblingMenuButton(Predicate> test @Override public void onMouseLeaveArea() { super.onMouseLeaveArea(); - checkClose(); + checkClose(true, true); } - protected void checkClose() { - if (this.openOnHover && !isSelfOrChildHovered()) { - closeMenu(true); + protected void checkClose(boolean soft, boolean requireNoHover) { + if ((this.openOnHover || !soft) && !isSelfOrChildHovered()) { + closeMenu(soft); Menu menuParent = WidgetTree.findParent(this, Menu.class); if (menuParent != null) { - menuParent.checkClose(); + menuParent.checkClose(soft, requireNoHover); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/Menu.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/Menu.java index 21033ce776f..db235287c92 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/Menu.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/Menu.java @@ -17,14 +17,16 @@ void setMenuSource(AbstractMenuButton source) { @Override public void onMouseLeaveArea() { super.onMouseLeaveArea(); - checkClose(); + checkClose(true, true); } - protected void checkClose() { - if (this.menuSource != null && !this.menuSource.isBelowMouse() && !isSelfOrChildHovered()) { - this.menuSource.closeMenu(true); - this.menuSource.checkClose(); + public void checkClose(boolean soft, boolean requireNoHover) { + if (this.menuSource == null) return; + if (soft || requireNoHover) { + if (this.menuSource.isBelowMouse() || isSelfOrChildHovered()) return; } + this.menuSource.closeMenu(soft); + this.menuSource.checkClose(soft, requireNoHover); } @Override @@ -42,4 +44,8 @@ protected void onChildAdd(IWidget child) { protected WidgetThemeEntry getWidgetThemeInternal(ITheme theme) { return theme.getWidgetTheme(IThemeApi.PANEL); } + + public AbstractMenuButton getMenuSource() { + return menuSource; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/MenuPanel.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/MenuPanel.java index 968205fad10..09eebbd9908 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/MenuPanel.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/menu/MenuPanel.java @@ -1,10 +1,13 @@ package com.gregtechceu.gtceu.api.mui.widgets.menu; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; +import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; import org.jetbrains.annotations.ApiStatus; +import java.util.List; + @ApiStatus.Experimental public class MenuPanel extends ModularPanel { @@ -19,6 +22,13 @@ public void openSubMenu(IWidget menuList) { child(menuList); } + @Override + public void onClose() { + super.onClose(); + // close all menus that are related to this panel + closeAllMenus(false, false); + } + @Override protected void onChildAdd(IWidget child) { super.onChildAdd(child); @@ -34,4 +44,13 @@ public boolean isDraggable() { public boolean closeOnOutOfBoundsClick() { return true; } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void closeAllMenus(boolean soft, boolean requireNoHover) { + // need to collect menus first instead of closing while iterating to avoid CME + List menus = WidgetTree.flatListByType(this, Menu.class); + for (Menu menu : menus) { + menu.checkClose(soft, requireNoHover); + } + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java index 86438a1f477..21650a0dec3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/FluidSlot.java @@ -1,7 +1,6 @@ package com.gregtechceu.gtceu.api.mui.widgets.slot; import com.gregtechceu.gtceu.api.mui.base.ITheme; -import com.gregtechceu.gtceu.api.mui.base.drawable.IDrawable; import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; import com.gregtechceu.gtceu.api.mui.base.value.ISyncOrValue; import com.gregtechceu.gtceu.api.mui.base.widget.Interactable; @@ -13,8 +12,9 @@ import com.gregtechceu.gtceu.api.mui.widgets.AbstractFluidDisplayWidget; import com.gregtechceu.gtceu.client.mui.screen.RichTooltip; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; +import com.gregtechceu.gtceu.utils.IMultiFluidTankHandler; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; @@ -31,7 +31,6 @@ import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -133,7 +132,7 @@ public String formatFluidTooltipAmount(double amount) { @Override public void onInit() { - getContext().getXeiSettings().addGhostIngredientSlot(this); + getContext().getRecipeViewerSettings().addGhostIngredientSlot(this); } @Override @@ -230,19 +229,6 @@ public IFluidTank getFluidTank() { return this.syncHandler == null ? EMPTY : this.syncHandler.fluidTank(); } - /** - * Set the offset in x and y (on both sides) at which the fluid should be rendered. - * Default is 1 for both. - * - * @param x x offset - * @param y y offset - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public FluidSlot contentOffset(int x, int y) { - return contentPaddingLeft(x).contentPaddingTop(y); - } - public FluidSlot displayAmount(boolean displayAmount) { this.displayAmount = displayAmount; return this; @@ -256,24 +242,27 @@ public FluidSlot alwaysShowFull(boolean alwaysShowFull) { return this; } - /** - * @param overlayTexture texture that is rendered on top of the fluid - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public FluidSlot overlayTexture(@Nullable IDrawable overlayTexture) { - return overlay(overlayTexture); - } - public FluidSlot syncHandler(IFluidTank fluidTank) { return syncHandler(new FluidSlotSyncHandler(fluidTank)); } + public FluidSlot syncHandler(IMultiFluidTankHandler fluidTank, int index) { + return syncHandler(fluidTank.getFluidTank(index)); + } + public FluidSlot syncHandler(FluidSlotSyncHandler syncHandler) { setSyncOrValue(ISyncOrValue.orEmpty(syncHandler)); return this; } + public FluidSlot tank(IFluidTank fluidTank) { + return syncHandler(fluidTank); + } + + public FluidSlot tank(IMultiFluidTankHandler fluidTank, int index) { + return syncHandler(fluidTank, index); + } + /* === Jei ghost slot === */ @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java index 2ad591b613f..da51acdd87c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ItemSlot.java @@ -16,8 +16,8 @@ import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; import com.gregtechceu.gtceu.core.mixins.client.AbstractContainerScreenAccessor; import com.gregtechceu.gtceu.core.mixins.client.ScreenAccessor; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.screens.Screen; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ModularSlot.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ModularSlot.java index bd2e89ed9fb..aad6ef13957 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ModularSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/ModularSlot.java @@ -36,7 +36,7 @@ public class ModularSlot extends SlotItemHandler { @Getter @Setter(onMethod_ = { @ApiStatus.Internal }) private boolean enabled = true; - private boolean canTake = true, canPut = true; + private boolean canTake = true, canPut = true, canDragInto = true; private Predicate filter = stack -> true; private IOnSlotChanged changeListener = IOnSlotChanged.DEFAULT; @Getter @@ -95,6 +95,10 @@ public boolean mayPickup(Player playerIn) { return this.canTake && super.mayPickup(playerIn); } + public boolean canDragIntoSlot() { + return this.canDragInto; + } + @Override public int getMaxStackSize(@NotNull ItemStack stack) { return this.ignoreMaxStackSize ? getMaxStackSize() : super.getMaxStackSize(stack); @@ -105,8 +109,9 @@ public void setChanged() {} public void onSlotChangedReal(ItemStack itemStack, boolean onlyChangedAmount, boolean client, boolean init) { this.changeListener.onChange(itemStack, onlyChangedAmount, client, init); - if (!init && isInitialized()) + if (!init && isInitialized()) { getSyncHandler().getSyncManager().getContainer().onSlotChanged(this, itemStack, onlyChangedAmount); + } } public void onCraftShiftClick(Player playerIn, ItemStack itemStack) {} @@ -115,6 +120,7 @@ public void onCraftShiftClick(Player playerIn, ItemStack itemStack) {} public void set(@NotNull ItemStack stack) { if (ItemStack.matches(stack, getItem())) return; super.set(stack); + if (this.syncHandler != null) this.syncHandler.checkUpdate(); } @Override @@ -172,6 +178,34 @@ public ModularSlot accessibility(boolean canPut, boolean canTake) { return this; } + public ModularSlot canPut(boolean canPut) { + this.canPut = canPut; + return this; + } + + public ModularSlot canTake(boolean canTake) { + this.canTake = canTake; + return this; + } + + /** + * Sets if this slots accepts items which are dragged across the screen. This is useful to disable when the filter + * depends on the items + * in the other slots. When dragging, the item in the slot is not real and its only updated once the dragging is + * completed. + * This method is by default called from + * {@link com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu#canDragTo(Slot)} + * ModularContainer.canDragIntoSlot(Slot)} which can be + * overridden for other custom behavior. + * + * @param canDragInto if items can be dragged into this slot + * @return this + */ + public ModularSlot canDragInto(boolean canDragInto) { + this.canDragInto = canDragInto; + return this; + } + /** * Sets if the max stack size of items should be ignored. Only item handler slot limit matters if true. * diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java index 9749baaabdd..98e564e5f55 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/slot/PhantomItemSlot.java @@ -5,8 +5,8 @@ import com.gregtechceu.gtceu.api.mui.value.sync.ItemSlotSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.PhantomItemSlotSyncHandler; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; -import com.gregtechceu.gtceu.integration.xei.handlers.RecipeViewerHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.RecipeViewerHandler; import net.minecraft.world.item.ItemStack; @@ -20,7 +20,7 @@ public class PhantomItemSlot extends ItemSlot implements GhostIngredientSlot { + @Getter private IStringValue stringValue; private Function validator = val -> val; private boolean numbers = false; @@ -36,15 +39,27 @@ public class TextFieldWidget extends BaseTextFieldWidget { private String mathFailMessage = null; private double defaultNumber = 0; private boolean tooltipOverride = false; + @Getter + private boolean autoUpdateOnChange = false; + @Getter + private boolean acceptsExpression = true; public double parse(String num) { + if (!this.acceptsExpression) { + try { + return NumberFormat.AMOUNT_TEXT.format.parse(num).doubleValue(); + } catch (ParseException ex) { + this.mathFailMessage = "Unable to parse number."; + return 0.0; + } + } ParseResult result = GTMath.parseExpression(num, this.defaultNumber, true); - double value = result.getResult(); if (result.isFailure()) { - this.mathFailMessage = result.getError(); + this.mathFailMessage = result.getErrorMessage(); GTCEu.LOGGER.error("Math expression error in {}: {}", this, this.mathFailMessage); + return defaultNumber; } - return value; + return result.getResult().getNumberValue().doubleValue(); } public IStringValue createMathFailMessageValue() { @@ -135,11 +150,38 @@ public void onRemoveFocus(ModularGuiContext context) { .setStringValue(this.numbers ? format.parse(getText(), new ParsePosition(0)).toString() : getText()); } + @Override + protected void onTextChanged() { + super.onTextChanged(); + if (this.autoUpdateOnChange) { + String text = this.validator.apply(getText()); + this.stringValue + .setStringValue(this.numbers ? format.parse(text, new ParsePosition(0)).toString() : getText()); + } + } + @Override public boolean canHover() { return true; } + public TextFieldWidget acceptsExpressions(boolean acceptsExpression) { + this.acceptsExpression = acceptsExpression; + return this; + } + + /** + * Sets if the string value should be updated every time the text changes and not just when the widget is unfocused. + * This is useful for search text fields. + * + * @param autoUpdateOnChange if the string value should be updated when text changes + * @return this + */ + public TextFieldWidget autoUpdateOnChange(boolean autoUpdateOnChange) { + this.autoUpdateOnChange = autoUpdateOnChange; + return this; + } + public TextFieldWidget setMaxLength(int maxLength) { this.handler.setMaxCharacters(maxLength); return this; diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index 101a0f692d6..9d61f910e41 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -36,10 +36,7 @@ import com.gregtechceu.gtceu.client.renderer.machine.impl.*; import com.gregtechceu.gtceu.client.renderer.machine.impl.BoilerMultiPartRender; import com.gregtechceu.gtceu.common.CommonProxy; -import com.gregtechceu.gtceu.common.data.GTBlockEntities; -import com.gregtechceu.gtceu.common.data.GTEntityTypes; -import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; -import com.gregtechceu.gtceu.common.data.GTParticleTypes; +import com.gregtechceu.gtceu.common.data.*; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.entity.GTBoat; import com.gregtechceu.gtceu.common.machine.owner.MachineOwner; @@ -71,6 +68,7 @@ import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; import net.minecraftforge.registries.ForgeRegistries; import com.google.common.collect.BiMap; @@ -96,19 +94,26 @@ public static void init() { if (!GTCEu.isDataGen()) { CursorHandler.init(); AnimatorManager.init(); - // enable stencil bits, must call on render thread - RenderSystem.recordRenderCall(() -> Minecraft.getInstance().getMainRenderTarget().enableStencil()); + DrawableSerialization.init(); ClientCacheManager.registerClientCache(GTClientCache.instance, "gtceu"); Layers.registerLayer(OreRenderLayer::new, "ore_veins"); Layers.registerLayer(FluidRenderLayer::new, "bedrock_fluids"); ForgeCommonEventListener.registerCapes(new RegisterGTCapesEvent()); - DrawableSerialization.init(); } initializeDynamicRenders(); } + @Override + public void preInit(FMLConstructModEvent event) { + super.preInit(event); + if (!GTCEu.isDataGen()) { + // enable stencil bits, must call on render thread + RenderSystem.recordRenderCall(() -> Minecraft.getInstance().getMainRenderTarget().enableStencil()); + } + } + @SubscribeEvent public void onRegisterEntityRenderers(EntityRenderersEvent.RegisterRenderers event) { event.registerEntityRenderer(GTEntityTypes.DYNAMITE.get(), ThrownItemRenderer::new); diff --git a/src/main/java/com/gregtechceu/gtceu/client/GuiSpriteManager.java b/src/main/java/com/gregtechceu/gtceu/client/GuiSpriteManager.java new file mode 100644 index 00000000000..8a9611e67f0 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/GuiSpriteManager.java @@ -0,0 +1,49 @@ +package com.gregtechceu.gtceu.client; + +import com.gregtechceu.gtceu.GTCEu; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.resources.TextureAtlasHolder; +import net.minecraft.resources.ResourceLocation; + +import org.jetbrains.annotations.NotNull; + +/** + * 1.21 has this class in vanilla, it can be used via {@code Minecraft.getGuiSprites()}.
+ * Here in 1.20 land, though, we have to implement it ourselves. + *

+ * Note that the atlas JSON should be kept, as MC 1.21 only adds textures in gui/sprites to the atlas. We want + * all of them. + */ +public class GuiSpriteManager extends TextureAtlasHolder { + + public static final ResourceLocation LOCATION_GUI = GTCEu.id("textures/atlas/gui.png"); + + private static final ResourceLocation atlasInfoLocation = GTCEu.id("gui"); + private static GuiSpriteManager instance = null; + + GuiSpriteManager(TextureManager textureManager) { + super(textureManager, LOCATION_GUI, atlasInfoLocation); + + if (instance != null) { + throw new IllegalStateException("Cannot create more than one GuiTextureAtlas instance!"); + } + instance = this; + } + + public static GuiSpriteManager getInstance() { + if (instance == null) { + throw new IllegalStateException("Cannot get GuiTextureAtlas instance before it's initialized!"); + } + return instance; + } + + /** + * Gets a sprite associated with the passed resource location. + */ + @Override + public @NotNull TextureAtlasSprite getSprite(@NotNull ResourceLocation location) { + return super.getSprite(location); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/ModClientEventListener.java b/src/main/java/com/gregtechceu/gtceu/client/ModClientEventListener.java new file mode 100644 index 00000000000..299b6e35e60 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/ModClientEventListener.java @@ -0,0 +1,30 @@ +package com.gregtechceu.gtceu.client; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.mui.screen.ContainerScreenWrapper; +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; +import com.gregtechceu.gtceu.common.data.GTMenuTypes; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; + +@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) +public class ModClientEventListener { + + @SubscribeEvent + public static void registerScreens(FMLClientSetupEvent event) { + // noinspection deprecation,RedundantCast + event.enqueueWork(() -> MenuScreens.register(GTMenuTypes.MODULAR_CONTAINER.get(), + (MenuScreens.ScreenConstructor) ContainerScreenWrapper::new)); + } + + @SubscribeEvent + public static void registerClientReloadListeners(RegisterClientReloadListenersEvent event) { + event.registerReloadListener(new GuiSpriteManager(Minecraft.getInstance().textureManager)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/component/FormattedTextContents.java b/src/main/java/com/gregtechceu/gtceu/client/mui/component/FormattedTextContents.java new file mode 100644 index 00000000000..6fc576edf98 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/component/FormattedTextContents.java @@ -0,0 +1,23 @@ +package com.gregtechceu.gtceu.client.mui.component; + +import net.minecraft.network.chat.ComponentContents; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.Style; + +import org.jetbrains.annotations.NotNullByDefault; + +import java.util.Optional; + +@NotNullByDefault +public record FormattedTextContents(FormattedText text) implements ComponentContents { + + @Override + public Optional visit(FormattedText.ContentConsumer acceptor) { + return text.visit(acceptor); + } + + @Override + public Optional visit(FormattedText.StyledContentConsumer acceptor, Style style) { + return text.visit(acceptor, style); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java index bd887e74de1..f5d148ae1ce 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.mui.GuiErrorHandler; import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; +import com.gregtechceu.gtceu.api.mui.base.ITheme; import com.gregtechceu.gtceu.api.mui.base.MCHelper; import com.gregtechceu.gtceu.api.mui.base.widget.IVanillaSlot; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; @@ -24,7 +25,7 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.core.mixins.client.AbstractContainerScreenAccessor; import com.gregtechceu.gtceu.core.mixins.client.ScreenAccessor; -import com.gregtechceu.gtceu.integration.xei.handlers.RecipeViewerHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.RecipeViewerHandler; import net.minecraft.ChatFormatting; import net.minecraft.Util; @@ -84,6 +85,12 @@ public static void onOpenScreen(ScreenEvent.Opening event) { onGuiChanged(event.getCurrentScreen(), event.getNewScreen()); } + public static void onCloseScreens(Screen closing) { + // called when the next screen is null, so that the player returns to the world + // we cant use ScreenEvent.Closing since that's also called when transitioning screens + onGuiChanged(closing, null); + } + @SubscribeEvent public static void onInitScreenPost(ScreenEvent.Init.Post event) { defaultContext.updateScreenArea(event.getScreen().width, event.getScreen().height); @@ -96,7 +103,8 @@ public static void onInitScreenPost(ScreenEvent.Init.Post event) { @SubscribeEvent public static void onScreenKeyPressedHigh(ScreenEvent.KeyPressed.Pre event) { defaultContext.updateLatestKey(event.getKeyCode(), event.getScanCode(), event.getModifiers()); - // TODO: early needs to be before XEI, but emi does mixin into KeyboardHandler so it is before everything + // TODO: early needs to be before recipe viewers, but emi does mixin into KeyboardHandler so it is before + // everything if (keyPressedEvent(event, InputPhase.EARLY)) { keyPressedEvent(event, InputPhase.LATE); } @@ -117,7 +125,7 @@ private static boolean keyPressedEvent(ScreenEvent.KeyPressed.Pre event, InputPh @SubscribeEvent public static void onScreenKeyReleasedHigh(ScreenEvent.KeyReleased.Pre event) { defaultContext.updateLatestKey(event.getKeyCode(), event.getScanCode(), event.getModifiers()); - // TODO also needs to be before XEI + // TODO also needs to be before recipe viewers // dont need late for release event keyReleasedEvent(event, InputPhase.EARLY); } @@ -524,8 +532,9 @@ private static void drawFloatingItemStack(AbstractContainerScreen mcScreen, G graphics.pose().popPose(); } - private static void drawVanillaElements(GuiGraphics graphics, Screen mcScreen, int mouseX, int mouseY, - float partialTicks) { + @ApiStatus.Internal + public static void drawVanillaElements(GuiGraphics graphics, Screen mcScreen, int mouseX, int mouseY, + float partialTicks) { for (Renderable renderable : mcScreen.renderables) { renderable.render(graphics, mouseX, mouseY, partialTicks); } @@ -551,22 +560,35 @@ public static void drawDebugScreen(GuiGraphics graphics, @Nullable ModularScreen int mouseX = context.getAbsMouseX(), mouseY = context.getAbsMouseY(); int screenH = muiScreen.getScreenArea().height; - int outlineColor = Long.decode(ConfigHolder.INSTANCE.dev.mui.outlineColor).intValue();// Color.argb(180, 40, - // 115, 220); - int textColor = Long.decode(ConfigHolder.INSTANCE.dev.mui.textColor).intValue();// Color.argb(180, 40, 115, - // 220); + int outlineColor = Color.parseString(ConfigHolder.INSTANCE.dev.mui.outlineColor);// Color.argb(180, 40, + // 115, 220); + int textColor = Color.parseString(ConfigHolder.INSTANCE.dev.mui.textColor);// Color.argb(180, 40, 115, + // 220); float scale = ConfigHolder.INSTANCE.dev.mui.scale; int shift = (int) (11 * scale + 0.5f); int lineY = screenH - shift - 2; - if (GTCEu.Mods.isJEILoaded() || GTCEu.Mods.isEMILoaded() || GTCEu.Mods.isREILoaded()) lineY -= 20; + if ((GTCEu.Mods.isJEILoaded() || GTCEu.Mods.isEMILoaded() || GTCEu.Mods.isREILoaded()) && + muiScreen.getContext().hasSettings() && + muiScreen.getContext().getRecipeViewerSettings().isEnabled(muiScreen)) { + lineY -= 20; + } GuiDraw.drawText(graphics, "Mouse Pos: " + mouseX + ", " + mouseY, 5, lineY, scale, outlineColor, true); lineY -= shift; GuiDraw.drawText(graphics, "FPS: " + fpsCounter.getFps(), 5, lineY, scale, outlineColor, true); lineY -= shift; - GuiDraw.drawText(graphics, "Theme ID: " + context.getTheme().getId(), 5, lineY, scale, outlineColor, true); + // GuiDraw.drawText(graphics, "Theme ID: " + context.getTheme().getId(), 5, lineY, scale, outlineColor, true); LocatedWidget locatedHovered = muiScreen.getPanelManager().getTopWidgetLocated(true); boolean showHovered = ConfigHolder.INSTANCE.dev.mui.showHovered; boolean showParent = ConfigHolder.INSTANCE.dev.mui.showParent; + + ITheme theme; + if (locatedHovered != null && (showHovered || showParent)) { + theme = locatedHovered.getElement().getPanel().getTheme(); + } else { + theme = context.getTheme(); + } + GuiDraw.drawText(graphics, "Theme ID: " + theme.getId(), 5, lineY, scale, outlineColor, false); + if (locatedHovered != null && (showHovered || showParent)) { drawSegmentLine(graphics, lineY -= 4, scale, outlineColor); lineY -= 10; @@ -591,13 +613,13 @@ public static void drawDebugScreen(GuiGraphics graphics, @Nullable ModularScreen if (showHovered) { if (ConfigHolder.INSTANCE.dev.mui.showWidgetTheme) { GuiDraw.drawText(graphics, "Widget Theme: " + - hovered.getWidgetTheme(muiScreen.getCurrentTheme()).getKey().getFullName(), - 5, lineY, scale, textColor, true); + hovered.getWidgetTheme(hovered.getPanel().getTheme()).getKey().getFullName(), + 5, lineY, scale, textColor, false); lineY -= shift; } if (ConfigHolder.INSTANCE.dev.mui.showSize) { GuiDraw.drawText(graphics, "Size: " + area.width + ", " + area.height, 5, lineY, scale, textColor, - true); + false); lineY -= shift; } if (ConfigHolder.INSTANCE.dev.mui.showPos) { @@ -615,16 +637,22 @@ public static void drawDebugScreen(GuiGraphics graphics, @Nullable ModularScreen if (ConfigHolder.INSTANCE.dev.mui.showParentWidgetTheme) { GuiDraw.drawText(graphics, "Widget Theme: " + parent.getWidgetTheme(muiScreen.getCurrentTheme()).getKey().getFullName(), - 5, lineY, scale, textColor, true); + 5, lineY, scale, textColor, false); lineY -= shift; } area = parent.getArea(); if (ConfigHolder.INSTANCE.dev.mui.showParentSize) { GuiDraw.drawText(graphics, "Parent size: " + area.width + ", " + area.height, 5, lineY, scale, - textColor, true); + textColor, false); + lineY -= shift; + } + if (ConfigHolder.INSTANCE.dev.mui.showParentPos) { + GuiDraw.drawText(graphics, + "Parent pos: " + area.x + ", " + area.y + " Rel: " + area.rx + ", " + area.ry, 5, lineY, + scale, textColor, false); lineY -= shift; } - GuiDraw.drawText(graphics, "Parent: " + parent, 5, lineY, 1, outlineColor, true); + GuiDraw.drawText(graphics, "Parent: " + parent, 5, lineY, scale, textColor, false); } if (ConfigHolder.INSTANCE.dev.mui.showExtra) { if (hovered instanceof ItemSlot slotWidget) { @@ -642,7 +670,7 @@ public static void drawDebugScreen(GuiGraphics graphics, @Nullable ModularScreen GuiDraw.drawText(graphics, "Shift-Click Priority: " + (allowShiftTransfer ? slotGroup.getShiftClickPriority() : "DISABLED"), - 5, lineY, scale, textColor, true); + 5, lineY, scale, textColor, false); } } else if (hovered instanceof RichTextWidget richTextWidget) { drawSegmentLine(graphics, lineY -= 4, scale, outlineColor); @@ -650,7 +678,7 @@ public static void drawDebugScreen(GuiGraphics graphics, @Nullable ModularScreen locatedHovered.applyMatrix(context); Object hoveredElement = richTextWidget.getHoveredElement(); locatedHovered.unapplyMatrix(context); - GuiDraw.drawText(graphics, "Hovered: " + hoveredElement, 5, lineY, scale, textColor, true); + GuiDraw.drawText(graphics, "Hovered: " + hoveredElement, 5, lineY, scale, textColor, false); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ContainerScreenWrapper.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ContainerScreenWrapper.java index ba5bd3271b5..66705180e7a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ContainerScreenWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ContainerScreenWrapper.java @@ -31,7 +31,7 @@ public ContainerScreenWrapper(ModularContainerMenu container, @NotNull ModularSc * * @deprecated Internal use only. */ - @SuppressWarnings("DataFlowIssue") + @SuppressWarnings({ "DataFlowIssue", "DeprecatedIsStillUsed" }) @Deprecated @ApiStatus.Internal public ContainerScreenWrapper(ModularContainerMenu container, Inventory playerInventory, Component title) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/CustomModularScreen.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/CustomModularScreen.java index 430a7646f3d..5412eb82273 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/CustomModularScreen.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/CustomModularScreen.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.client.mui.screen; -import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; import net.minecraftforge.api.distmarker.Dist; @@ -15,19 +14,6 @@ @OnlyIn(Dist.CLIENT) public abstract class CustomModularScreen extends ModularScreen { - /** - * Creates a new screen with ModularUI as its owner. - */ - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - @Deprecated - public CustomModularScreen() { - super(GTCEu.MOD_ID); - if (GTCEu.isDev()) { - GTCEu.LOGGER.error("The single arg ModularScreen constructor should not be used. " + - "Use the other one and pass in your mod id."); - } - } - /** * Creates a new screen with a given owner. * diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java index 3f0ff42da25..83a8a2f0f61 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java @@ -16,7 +16,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; @@ -62,9 +61,9 @@ public ModularContainerMenu(int containerId) { super(GTMenuTypes.MODULAR_CONTAINER.get(), containerId); } - public ModularContainerMenu(MenuType type, int containerId, + public ModularContainerMenu(int containerId, Inventory playerInv, @Nullable FriendlyByteBuf data) { - super(type, containerId); + this(containerId); // TODO: Better integration with menu types for custom containers and screens. throw new IllegalArgumentException("Do not open the modular container the forge way. Use an UIFactory!"); } @@ -241,6 +240,11 @@ public List getShiftClickSlots() { public void onSlotChanged(ModularSlot slot, ItemStack stack, boolean onlyAmountChanged) {} + @Override + public boolean canDragTo(@NotNull Slot slot) { + return !(slot instanceof ModularSlot modularSlot) || modularSlot.canDragIntoSlot(); + } + @Override public boolean stillValid(@NotNull Player playerIn) { return this.settings.canPlayerInteractWithUI(playerIn); diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java index 37a886391ad..232e71b125d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularPanel.java @@ -47,7 +47,8 @@ * This class is like a window in windows. It can hold any amount of widgets. It may also be draggable. * To open another panel on top of the main panel you must use * {@link IPanelHandler#simple(ModularPanel, SecondaryPanel.IPanelBuilder, boolean)} - * or {@link PanelSyncManager#panel(String, PanelSyncHandler.IPanelBuilder, boolean)} if the panel should be synced. + * or {@link PanelSyncManager#syncedPanel(String, boolean, PanelSyncHandler.IPanelBuilder)} if the panel should be + * synced. */ public class ModularPanel extends ParentWidget implements IViewport, IDragResizeable { @@ -201,20 +202,6 @@ public void transform(IViewportStack stack) { } } - @Override - public void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (hasChildren()) { - IViewport.getChildrenAt(this, stack, widgets, x, y); - } - } - - @Override - public void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) { - if (isInside(stack, x, y)) { - widgets.add(this, stack.peek(), getAdditionalHoverInfo(stack, x, y)); - } - } - private void findHoveredWidgets() { this.hovering.clear(); if (!isEnabled()) { @@ -271,8 +258,9 @@ public void onClose() { } @Override - public boolean isExcludeAreaInXei() { - return super.isExcludeAreaInXei() || (!getScreen().isOverlay() && !this.invisible && !resizer().isFullSize()); + public boolean isExcludeAreaInRecipeViewer() { + return super.isExcludeAreaInRecipeViewer() || + (!getScreen().isOverlay() && !this.invisible && !resizer().isFullSize()); } @MustBeInvokedByOverriders diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java index f25dca88891..de4c98112b8 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularScreen.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.client.mui.screen; -import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; import com.gregtechceu.gtceu.api.mui.base.ITheme; import com.gregtechceu.gtceu.api.mui.base.IThemeApi; @@ -15,6 +14,7 @@ import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; import com.gregtechceu.gtceu.api.mui.widget.sizer.ScreenResizeNode; import com.gregtechceu.gtceu.api.mui.widget.wrapper.WidgetWrapper; +import com.gregtechceu.gtceu.api.mui.widgets.menu.MenuPanel; import com.gregtechceu.gtceu.client.mui.screen.viewport.ModularGuiContext; import net.minecraft.client.Minecraft; @@ -116,19 +116,6 @@ public static ModularScreen getCurrent() { @Getter private boolean overlay = false; - /** - * @deprecated use the other constructor - */ - @Deprecated - @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") - public ModularScreen(@NotNull ModularPanel mainPanel) { - this(GTCEu.MOD_ID, mainPanel); - if (GTCEu.isDev()) { - GTCEu.LOGGER.warn("The single arg ModularScreen constructor should not be used. " + - "Use the any of the other ones and pass in your mod id."); - } - } - /** * Creates a new screen with a given owner and {@link ModularPanel}. * @@ -398,12 +385,21 @@ public boolean handleDraggableInput(double mouseX, double mouseY, int button, bo * @return true if the action was consumed and further processing should be canceled */ public boolean onMousePressed(double mouseX, double mouseY, int button) { + // call all action listeners for (IGuiAction.MousePressed action : getGuiActionListeners(IGuiAction.MousePressed.class)) { action.press(mouseX, mouseY, button); } + // check if any context menu is open and close them if they or their children are not hovered + for (ModularPanel panel : this.panelManager.getOpenPanels()) { + if (panel instanceof MenuPanel menuPanel) { + menuPanel.closeAllMenus(false, true); + } + } + // handle dragging of draggable widgets if (this.context.onMousePressed(mouseX, mouseY, button)) { return true; } + // finally click hovered widgets for (ModularPanel panel : this.panelManager.getOpenPanels()) { if (panel.onMousePressed(mouseX, mouseY, button)) { return true; diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/XeiSettingsImpl.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/RecipeViewerSettingsImpl.java similarity index 71% rename from src/main/java/com/gregtechceu/gtceu/client/mui/screen/XeiSettingsImpl.java rename to src/main/java/com/gregtechceu/gtceu/client/mui/screen/RecipeViewerSettingsImpl.java index d142957c079..08da46495a8 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/XeiSettingsImpl.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/RecipeViewerSettingsImpl.java @@ -1,10 +1,10 @@ package com.gregtechceu.gtceu.client.mui.screen; -import com.gregtechceu.gtceu.api.mui.base.XeiSettings; +import com.gregtechceu.gtceu.api.mui.base.RecipeViewerSettings; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.utils.Rectangle; -import com.gregtechceu.gtceu.integration.xei.XeiState; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.RecipeViewerState; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -23,35 +23,35 @@ * This class can be safely interacted with even when JEI/HEI is not installed. */ @OnlyIn(Dist.CLIENT) -public class XeiSettingsImpl implements XeiSettings { +public class RecipeViewerSettingsImpl implements RecipeViewerSettings { - private XeiState xeiState = XeiState.DEFAULT; - private final List jeiExclusionWidgets = new ArrayList<>(); - private final List jeiExclusionAreas = new ArrayList<>(); + private RecipeViewerState recipeViewerState = RecipeViewerState.DEFAULT; + private final List exclusionWidgets = new ArrayList<>(); + private final List exclusionAreas = new ArrayList<>(); private final List> ghostIngredientSlots = new ArrayList<>(); /** * Force JEI to be enabled */ @Override - public void forceEnabled() { - this.xeiState = XeiState.ENABLED; + public void enable() { + this.recipeViewerState = RecipeViewerState.ENABLED; } /** * Force JEI to be disabled */ @Override - public void forceDisabled() { - this.xeiState = XeiState.DISABLED; + public void disable() { + this.recipeViewerState = RecipeViewerState.DISABLED; } /** * Only enabled JEI in synced GUIs */ @Override - public void defaultXei() { - this.xeiState = XeiState.DEFAULT; + public void defaultState() { + this.recipeViewerState = RecipeViewerState.DEFAULT; } /** @@ -62,7 +62,7 @@ public void defaultXei() { */ @Override public boolean isEnabled(ModularScreen screen) { - return this.xeiState.test(screen); + return this.recipeViewerState.test(screen); } /** @@ -73,8 +73,8 @@ public boolean isEnabled(ModularScreen screen) { */ @Override public void addExclusionArea(Rectangle area) { - if (!this.jeiExclusionAreas.contains(area)) { - this.jeiExclusionAreas.add(area); + if (!this.exclusionAreas.contains(area)) { + this.exclusionAreas.add(area); } } @@ -85,7 +85,7 @@ public void addExclusionArea(Rectangle area) { */ @Override public void removeExclusionArea(Rectangle area) { - this.jeiExclusionAreas.remove(area); + this.exclusionAreas.remove(area); } /** @@ -96,8 +96,8 @@ public void removeExclusionArea(Rectangle area) { */ @Override public void addExclusionArea(IWidget area) { - if (!this.jeiExclusionWidgets.contains(area)) { - this.jeiExclusionWidgets.add(area); + if (!this.exclusionWidgets.contains(area)) { + this.exclusionWidgets.add(area); } } @@ -108,7 +108,7 @@ public void addExclusionArea(IWidget area) { */ @Override public void removeExclusionArea(IWidget area) { - this.jeiExclusionWidgets.remove(area); + this.exclusionWidgets.remove(area); } /** @@ -138,12 +138,12 @@ public > void removeGhostIngredientSl @UnmodifiableView public List getExclusionAreas() { - return Collections.unmodifiableList(this.jeiExclusionAreas); + return Collections.unmodifiableList(this.exclusionAreas); } @UnmodifiableView public List getExclusionWidgets() { - return Collections.unmodifiableList(this.jeiExclusionWidgets); + return Collections.unmodifiableList(this.exclusionWidgets); } @UnmodifiableView @@ -153,9 +153,9 @@ public List> getGhostIngredientSlots() { @ApiStatus.Internal public List getAllExclusionAreas() { - this.jeiExclusionWidgets.removeIf(widget -> !widget.isValid()); - List areas = new ArrayList<>(this.jeiExclusionAreas); - for (Iterator iterator = this.jeiExclusionWidgets.iterator(); iterator.hasNext();) { + this.exclusionWidgets.removeIf(widget -> !widget.isValid()); + List areas = new ArrayList<>(this.exclusionAreas); + for (Iterator iterator = this.exclusionWidgets.iterator(); iterator.hasNext();) { IWidget widget = iterator.next(); if (!widget.isValid()) { iterator.remove(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/UISettings.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/UISettings.java index 2bbd20cbf2d..e6992ad3026 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/UISettings.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/UISettings.java @@ -2,8 +2,8 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; +import com.gregtechceu.gtceu.api.mui.base.RecipeViewerSettings; import com.gregtechceu.gtceu.api.mui.base.UIFactory; -import com.gregtechceu.gtceu.api.mui.base.XeiSettings; import com.gregtechceu.gtceu.api.mui.factory.GuiData; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; @@ -34,14 +34,14 @@ public class UISettings { @Getter private String theme; @Getter - private final XeiSettings xeiSettings; + private final RecipeViewerSettings recipeViewerSettings; public UISettings() { - this(new XeiSettingsImpl()); + this(new RecipeViewerSettingsImpl()); } - public UISettings(XeiSettings xeiSettings) { - this.xeiSettings = xeiSettings; + public UISettings(RecipeViewerSettings recipeViewerSettings) { + this.recipeViewerSettings = recipeViewerSettings; } /** diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/GuiViewportStack.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/GuiViewportStack.java index fb84c95725a..379212238a2 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/GuiViewportStack.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/GuiViewportStack.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.ListIterator; /** * This class is a matrix stack aka pose stack. It keeps track of widget transformations (including position) @@ -23,6 +22,7 @@ public class GuiViewportStack implements IViewportStack { private static final Vector3f sharedVec = new Vector3f(); + private final ObjectArrayList matrixPool = new ObjectArrayList<>(); private final ObjectArrayList viewportStack = new ObjectArrayList<>(); private final List viewportAreas = new ArrayList<>(); private TransformationMatrix top; @@ -54,17 +54,29 @@ public void pushViewport(IViewport viewport, Area area) { } this.topViewport.getArea().clamp(child); } - this.viewportStack.push(new TransformationMatrix(viewport, child, parent)); + this.viewportStack.push(newMatrix().construct(viewport, child, parent)); updateViewport(false); this.topViewport = this.viewportStack.top(); } @Override public void pushMatrix() { - this.viewportStack.push(new TransformationMatrix(this.top == null ? null : this.top.getMatrix())); + this.viewportStack.push(newMatrix().construct(this.top == null ? null : this.top.getMatrix())); updateViewport(false); } + private TransformationMatrix newMatrix() { + return !this.matrixPool.isEmpty() ? this.matrixPool.pop() : new TransformationMatrix(); + } + + private void pop() { + TransformationMatrix matrix = this.viewportStack.pop(); + matrix.dispose(); + if (this.matrixPool.size() < 256) { + this.matrixPool.add(matrix); + } + } + private Area getCurrentViewportArea() { while (this.viewportAreas.size() < this.viewportStack.size() + 1) { this.viewportAreas.add(new Area()); @@ -75,7 +87,12 @@ private Area getCurrentViewportArea() { @Override public void popViewport(IViewport viewport) { if (this.top == null || !this.top.isViewportMatrix() || this.top.getViewport() != viewport) { - String name = this.top == null ? "null" : this.top.getViewport().toString(); + String name; + if (this.top == null) { + name = "none"; + } else { + name = this.top.isViewportMatrix() ? asString(this.top.getViewport()) : "not a viewport"; + } throw new IllegalStateException( "Viewports must be popped in reverse order they were pushed. Tried to pop '" + viewport + "', but last pushed is '" + name + "'."); @@ -84,17 +101,21 @@ public void popViewport(IViewport viewport) { updateViewport(true); } + private static String asString(IViewport viewport) { + return viewport == null ? "screen viewport" : viewport.toString(); + } + @Override public void popMatrix() { if (this.top.isViewportMatrix()) { throw new IllegalStateException("Tried to pop viewport matrix, but at the top is a normal matrix."); } - this.viewportStack.pop(); + pop(); updateViewport(false); } public void push(TransformationMatrix transformationMatrix) { - this.viewportStack.push(new TransformationMatrix(transformationMatrix, + this.viewportStack.push(newMatrix().construct(transformationMatrix, this.top == null ? null : this.top.getMatrix())); updateViewport(false); if (this.top.isViewportMatrix()) { @@ -106,8 +127,9 @@ public void pop(TransformationMatrix transformationMatrix) { if (this.top.getWrapped() != transformationMatrix) { throw new IllegalArgumentException(); } - TransformationMatrix tm = this.viewportStack.pop(); - updateViewport(tm.isViewportMatrix()); + boolean isViewport = this.top.isViewportMatrix(); + pop(); + updateViewport(isViewport); } @Override @@ -118,7 +140,7 @@ public int getStackSize() { @Override public void popUntilIndex(int index) { for (int i = this.viewportStack.size() - 1; i > index; i--) { - this.viewportStack.pop(); + pop(); } updateViewport(true); } @@ -127,7 +149,7 @@ public void popUntilIndex(int index) { public void popUntilViewport(IViewport viewport) { int i = this.viewportStack.size(); while (--i >= 0 && this.viewportStack.top().getViewport() != viewport) { - this.viewportStack.pop(); + pop(); } updateViewport(true); } @@ -191,16 +213,14 @@ private void checkViewport() { private void updateViewport(boolean findTopViewport) { this.top = this.viewportStack.isEmpty() ? null : this.viewportStack.top(); - if (!findTopViewport || this.topViewport == null || !this.topViewport.isViewportMatrix()) return; + if (!findTopViewport) return; // find new top viewport this.topViewport = null; if (this.viewportStack.isEmpty()) return; - ListIterator it = this.viewportStack.listIterator(this.viewportStack.size() - 1); - while (it.hasPrevious()) { - TransformationMatrix transformationMatrix1 = it.previous(); - if (transformationMatrix1.isViewportMatrix()) { - this.topViewport = transformationMatrix1; - break; + for (int i = this.viewportStack.size() - 1; i >= 0; i--) { + TransformationMatrix matrix = this.viewportStack.get(i); + if (matrix.isViewportMatrix()) { + this.topViewport = matrix; } } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/LocatedWidget.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/LocatedWidget.java index c6d48e984a0..cc3d8633db6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/LocatedWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/LocatedWidget.java @@ -55,6 +55,11 @@ public LocatedWidget(IWidget element, TransformationMatrix transformationMatrix, this.additionalHoverInfo = additionalHoverInfo; } + @Override + public String toString() { + return "LocatedWidget[" + getElement() + " | " + additionalHoverInfo + "]"; + } + public static class HashStrategy implements Hash.Strategy { @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java index 73a92338b75..ae66652ffe6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/ModularGuiContext.java @@ -23,7 +23,7 @@ /** * This class contains all the info from {@link GuiContext} and additional MUI specific info like the current * {@link ModularScreen}, - * current hovered widget, current dragged widget, current focused widget and XEI settings. + * current hovered widget, current dragged widget, current focused widget and recipe viewer settings. * An instance can only be obtained from {@link ModularScreen#getContext()}. One instance is created every time a * {@link ModularScreen} * is created. @@ -73,7 +73,7 @@ public class ModularGuiContext extends GuiContext { public ModularGuiContext(ModularScreen screen) { this.screen = screen; - this.hoveredWidgets = new HoveredIterable(this.screen.getPanelManager()); + this.hoveredWidgets = new HoveredIterable(); } /** @@ -83,39 +83,6 @@ public boolean isHovered() { return !this.hovered.isEmpty(); } - /** - * @return true if the widget is directly below the mouse - */ - @ApiStatus.ScheduledForRemoval(inVersion = "2.7.0") - @Deprecated - public boolean isHovered(IWidget guiElement) { - return guiElement.isHovering(); - } - - /** - * Checks if a widget is hovered for a certain amount of ticks - * - * @param guiElement widget - * @param ticks time hovered - * @return true if the widget is hovered for at least a certain number of ticks - */ - @ApiStatus.ScheduledForRemoval(inVersion = "2.7.0") - @Deprecated - public boolean isHoveredFor(IWidget guiElement, int ticks) { - // convert from frames per second to ticks per second - return guiElement.isHoveringFor(ticks); - } - - /** - * @return the hovered widget (widget directly below the mouse) - */ - @ApiStatus.ScheduledForRemoval(inVersion = "2.7.0") - @Deprecated - @Nullable - public IWidget getHovered() { - return getTopHovered(); - } - public @Nullable IWidget getTopHovered() { return this.hovered.isEmpty() ? null : this.hovered.get(0).getElement(); } @@ -458,11 +425,11 @@ public UISettings getUISettings() { return this.settings; } - public XeiSettingsImpl getXeiSettings() { + public RecipeViewerSettingsImpl getRecipeViewerSettings() { if (this.screen.isOverlay()) { throw new IllegalStateException("Overlays don't have JEI settings!"); } - return (XeiSettingsImpl) getUISettings().getXeiSettings(); + return (RecipeViewerSettingsImpl) getUISettings().getRecipeViewerSettings(); } @ApiStatus.Internal @@ -476,40 +443,28 @@ public void setSettings(UISettings settings) { } } - private static class HoveredIterable implements Iterable { - - private final PanelManager panelManager; + public boolean hasSettings() { + return this.settings != null; + } - private HoveredIterable(PanelManager panelManager) { - this.panelManager = panelManager; - } + private class HoveredIterable implements Iterable { @NotNull @Override public Iterator iterator() { - return new Iterator<>() { + return new AbstractIterator<>() { - private final Iterator panelIt = HoveredIterable.this.panelManager.getOpenPanels() - .iterator(); + private final Iterator panelIt = ModularGuiContext.this.getScreen() + .getPanelManager().getOpenPanels().iterator(); private Iterator widgetIt; @Override - public boolean hasNext() { - if (this.widgetIt == null) { - if (!this.panelIt.hasNext()) { - return false; - } - this.widgetIt = this.panelIt.next().getHovering().iterator(); - } - return this.widgetIt.hasNext(); - } - - @Override - public IWidget next() { - if (this.widgetIt == null || !this.widgetIt.hasNext()) { - this.widgetIt = this.panelIt.next().getHovering().iterator(); + protected IWidget computeNext() { + while (widgetIt == null || !widgetIt.hasNext()) { + if (!panelIt.hasNext()) return endOfData(); + widgetIt = panelIt.next().getHovering().iterator(); } - return this.widgetIt.next().getElement(); + return widgetIt.next().getElement(); } }; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/TransformationMatrix.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/TransformationMatrix.java index 9d613548290..625dbcd6540 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/TransformationMatrix.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/viewport/TransformationMatrix.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; import lombok.Getter; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -11,56 +12,88 @@ /** * A single matrix in a matrix stack. Also has some other information. */ +@ApiStatus.Internal public class TransformationMatrix { public static final TransformationMatrix EMPTY = new TransformationMatrix(null); @Getter - private final TransformationMatrix wrapped; + private TransformationMatrix wrapped; @Getter - private final IViewport viewport; + private IViewport viewport; @Getter - private final Area area; + private Area area; @Getter - private final Matrix4f matrix; + private final Matrix4f matrix = new Matrix4f(); private final Matrix4f invertedMatrix = new Matrix4f(); + private boolean inUse = false; @Getter - private final boolean viewportMatrix; + private boolean viewportMatrix; @Getter private boolean dirty = true; + public TransformationMatrix() {} + + public TransformationMatrix(@Nullable Matrix4f parent) { + construct(parent); + } + public TransformationMatrix(TransformationMatrix parent, @Nullable Matrix4f parentMatrix) { + construct(parent, parentMatrix); + } + + TransformationMatrix construct(TransformationMatrix parent, @Nullable Matrix4f parentMatrix) { + checkInUse(); this.wrapped = parent; this.viewport = parent.viewport; this.area = parent.area; - this.matrix = parentMatrix == null ? new Matrix4f(parent.getMatrix()) : - parentMatrix.mul(parent.getMatrix(), new Matrix4f()); + if (parentMatrix == null) { + this.matrix.set(parent.getMatrix()); + } else { + parentMatrix.mul(parent.getMatrix(), this.matrix); + } this.viewportMatrix = parent.viewportMatrix; + return this; } - public TransformationMatrix(@Nullable Matrix4f parent) { + TransformationMatrix construct(@Nullable Matrix4f parent) { + return construct(null, null, parent, false); + } + + TransformationMatrix construct(IViewport viewport, Area area, @Nullable Matrix4f parent) { + return construct(viewport, area, parent, true); + } + + private TransformationMatrix construct(IViewport viewport, Area area, @Nullable Matrix4f parent, + boolean isViewport) { + checkInUse(); this.wrapped = null; - this.viewport = null; - this.area = null; - this.matrix = new Matrix4f(); - this.viewportMatrix = false; + this.viewport = viewport; + this.area = area; + this.viewportMatrix = isViewport; if (parent != null) { this.matrix.set(parent); } else { this.matrix.identity(); } + return this; } - public TransformationMatrix(IViewport viewport, Area area, @Nullable Matrix4f parent) { + void dispose() { this.wrapped = null; - this.viewport = viewport; - this.area = area; - this.matrix = new Matrix4f(); - this.viewportMatrix = true; - if (parent != null) { - this.matrix.set(parent); + this.viewport = null; + this.area = null; + this.inUse = false; + this.viewportMatrix = false; + } + + private void checkInUse() { + if (this.inUse) { + throw new IllegalStateException("Transformation matrix is already in use!"); } + this.inUse = true; + this.dirty = true; } public Matrix4f getInvertedMatrix() { diff --git a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java index 1a2a29151fd..ec7314970f8 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java @@ -157,7 +157,10 @@ public static void init() { GTCovers.init(); GTCreativeModeTabs.init(); - GTMenuTypes.init(); + + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + GTMenuTypes.init(modBus); + GTBlocks.init(); GTFluids.init(); GTEntityTypes.init(); @@ -218,6 +221,8 @@ public static void init() { FusionReactorMachine.registerFusionTier(GTValues.UV, " (MKIII)"); } + public void preInit(FMLConstructModEvent event) {} + private static void initMaterials() { // First, register other mods' Registries MaterialRegistryManager managerInternal = (MaterialRegistryManager) GTCEuAPI.materialManager; diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java b/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java index 3b9463eb764..623fb88f198 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java @@ -9,6 +9,8 @@ import com.gregtechceu.gtceu.api.data.worldgen.ores.OreGenerator; import com.gregtechceu.gtceu.api.data.worldgen.ores.OrePlacer; import com.gregtechceu.gtceu.api.gui.factory.GTUIEditorFactory; +import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; +import com.gregtechceu.gtceu.api.mui.theme.ThemeManager; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.api.registry.GTRegistry; import com.gregtechceu.gtceu.common.commands.arguments.GTRegistryArgument; @@ -34,6 +36,7 @@ import com.google.common.collect.Sets; import com.google.gson.JsonElement; +import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -72,6 +75,12 @@ public class GTCommands { public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { dispatcher.register( literal("gtceu") + .then(Commands.literal("reload_themes") + .executes(ctx -> { + ThemeManager.reload(); + ctx.getSource().sendSuccess(() -> Component.literal("GTCEu MUI Themes reloaded").withStyle(IKey.GREEN), true); + return Command.SINGLE_SUCCESS; + })) .then(literal("ui_editor") .requires(ctx -> ctx.hasPermission(LEVEL_ADMINS)) .executes(context -> { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GCYMRecipeTypes.java b/src/main/java/com/gregtechceu/gtceu/common/data/GCYMRecipeTypes.java index 36189576669..0e4c49b1226 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GCYMRecipeTypes.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GCYMRecipeTypes.java @@ -6,7 +6,7 @@ import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.widget.SlotWidget; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; -import com.gregtechceu.gtceu.integration.xei.handlers.item.CycleItemEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.item.CycleItemEntryHandler; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.lowdragmc.lowdraglib.utils.LocalizationUtils; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMenuTypes.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMenuTypes.java index 543a35088a4..7706ecfb731 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMenuTypes.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMenuTypes.java @@ -1,19 +1,25 @@ package com.gregtechceu.gtceu.common.data; -import com.gregtechceu.gtceu.client.mui.screen.ContainerScreenWrapper; +import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; -import com.tterrag.registrate.util.entry.MenuEntry; - -import static com.gregtechceu.gtceu.common.registry.GTRegistration.REGISTRATE; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.inventory.MenuType; +import net.minecraftforge.common.extensions.IForgeMenuType; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.RegistryObject; public class GTMenuTypes { - @SuppressWarnings("deprecation") - public static final MenuEntry MODULAR_CONTAINER = REGISTRATE - .menu("modular", - ModularContainerMenu::new, () -> ContainerScreenWrapper::new) - .register(); + private static final DeferredRegister> MENU_TYPES = DeferredRegister.create(Registries.MENU, + GTCEu.MOD_ID); + + public static final RegistryObject> MODULAR_CONTAINER = MENU_TYPES.register( + "modular", + () -> IForgeMenuType.create(ModularContainerMenu::new)); - public static void init() {} + public static void init(IEventBus modBus) { + MENU_TYPES.register(modBus); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java index a7e4a76126e..85e59dc40d8 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java @@ -22,10 +22,10 @@ import com.gregtechceu.gtceu.common.recipe.condition.AdjacentFluidCondition; import com.gregtechceu.gtceu.data.recipe.builder.GTRecipeBuilder; import com.gregtechceu.gtceu.integration.kjs.GTRegistryInfo; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidHolderSetList; -import com.gregtechceu.gtceu.integration.xei.handlers.fluid.CycleFluidEntryHandler; -import com.gregtechceu.gtceu.integration.xei.handlers.item.CycleItemEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidHolderSetList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.fluid.CycleFluidEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.item.CycleItemEntryHandler; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.gregtechceu.gtceu.utils.GTMath; import com.gregtechceu.gtceu.utils.ResearchManager; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java b/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java index 7c3cf299f4d..0f23490f46d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java @@ -263,8 +263,8 @@ public static ButtonWidget createCircuitSlotPanel(IHasCircuitSlot machine, Mo syncManager) .relative(parentPanel) .leftRelOffset(0.0f, -180); - IPanelHandler circuitPanelHandler = syncManager.panel("circuit_panel", - (sm, sh) -> circuitPanel, true); + IPanelHandler circuitPanelHandler = syncManager.syncedPanel("circuit_panel", true, + (sm, sh) -> circuitPanel); return new ButtonWidget<>() .size(18) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTSingleblockMachinePanels.java b/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTSingleblockMachinePanels.java index f91615ed720..f17d233222d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTSingleblockMachinePanels.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTSingleblockMachinePanels.java @@ -107,7 +107,7 @@ public class GTSingleblockMachinePanels { panel.child(GTMuiWidgets.createXEIWidget(GTRecipeTypeUIs.recipeTypeUIs.get(workableMachine.getRecipeType())) .left(190)); } - panel.excludeAreaInXei(); + panel.excludeAreaInRecipeViewer(); return panel; }; @@ -195,7 +195,7 @@ public class GTSingleblockMachinePanels { panel.child(GTMuiWidgets.createXEIWidget(GTRecipeTypeUIs.recipeTypeUIs.get(workableMachine.getRecipeType())) .left(190)); } - panel.excludeAreaInXei(); + panel.excludeAreaInRecipeViewer(); return panel; }; @@ -283,7 +283,7 @@ public class GTSingleblockMachinePanels { panel.child(GTMuiWidgets.createXEIWidget(GTRecipeTypeUIs.recipeTypeUIs.get(workableMachine.getRecipeType())) .left(190)); } - panel.excludeAreaInXei(); + panel.excludeAreaInRecipeViewer(); return panel; }; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java index 7fdd51a741e..68fb4a8d4b6 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java @@ -139,7 +139,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .bottom(16) .padding(0, 8, 4, 4) .childPadding(2) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) .child(GTMuiWidgets.createPowerButton(this::isWorkingEnabled, this::setWorkingEnabled, syncManager))) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java index 63cf19377c4..9bdfeca8425 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java @@ -376,7 +376,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet syncManager)) .child(createBatterySlot(syncManager)) .child(GTMuiWidgets.createAutoOutputItemButton(autoOutput, syncManager)) - .excludeAreaInXei()); + .excludeAreaInRecipeViewer()); return panel; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java index 0a02a1c5d0d..48a2c2c5f0b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java @@ -162,7 +162,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .bottom(16) .padding(0, 8, 4, 4) .childPadding(2) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) .child(GTMuiWidgets.createPowerButton(this::isWorkingEnabled, this::setWorkingEnabled, syncManager))) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java index 19174c6c523..87618d7c9bf 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java @@ -372,7 +372,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .coverChildrenWidth() .mainAxisAlignment(Alignment.MainAxis.CENTER) .childIf(!(outputItemGrid.length == 0), - GTMuiMachineUtil.createSlotGroupFromInventory(cache, + () -> GTMuiMachineUtil.createSlotGroupFromInventory(cache, "output_item_inv", cache.getSize(), 'i', syncManager, outputItemGrid) .alignX(Alignment.CenterRight)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java index 824fa83e4c7..c905ff8d5cb 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ItemCollectorMachine.java @@ -347,7 +347,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .bottom(16) .padding(0, 8, 4, 4) .childPadding(2) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) .child(GTMuiWidgets.createPowerButton(this::isWorkingEnabled, this::setWorkingEnabled, syncManager)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/MinerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/MinerMachine.java index ad9807c65fc..d42f87c0509 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/MinerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/MinerMachine.java @@ -252,7 +252,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .bottom(16) .padding(0, 8, 4, 4) .childPadding(2) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) .child(GTMuiWidgets.createPowerButton(this::isWorkingEnabled, this::setWorkingEnabled, syncManager)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java index 5b2cab5f976..3b577256bc3 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java @@ -209,7 +209,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .top(0) .leftRelOffset(1f, 1) .background(GTGuiTextures.BACKGROUND) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .stencilTransform((r, expanded) -> { r.width = Math.max(20, r.width - 5); r.height = Math.max(20, r.height - 5); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/DualHatchPartMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/DualHatchPartMachine.java index f7961fa730f..db844fd2526 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/DualHatchPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/DualHatchPartMachine.java @@ -206,7 +206,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .bottom(16) .padding(0, 8, 4, 4) .childPadding(2) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) .child(new ToggleButton() .value(new BoolValue.Dynamic(this::isWorkingEnabled, this::setWorkingEnabled)) @@ -216,7 +216,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .tooltipBuilder((r) -> r.addLine(IKey.lang(Component.translatable( isWorkingEnabled() ? "behaviour.soft_hammer.enabled" : "behaviour.soft_hammer.disabled"))))) - .childIf(io.support(IO.IN), new ToggleButton() + .childIf(io.support(IO.IN), () -> new ToggleButton() .value(new BoolValue.Dynamic(this::isDistinct, this::setDistinct)) .stateOverlay(GTGuiTextures.BUTTON_DISTINCT) .tooltipAutoUpdate(true) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/FluidHatchPartMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/FluidHatchPartMachine.java index bb97a0a1265..e8dad4d84b0 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/FluidHatchPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/FluidHatchPartMachine.java @@ -323,7 +323,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .padding(8, 0, 4, 4) .childPadding(2) .background(backgroundTexture.getSubArea(0.0f, 0f, 0.75f, 1.0f)) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .child(GTMuiWidgets.createPowerButton(this::isWorkingEnabled, this::setWorkingEnabled, syncManager)) .childIf(this.isCircuitSlotEnabled(), diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java index 8a5bb88fb8c..6f440ae01e2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java @@ -69,7 +69,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .texture(GTGuiTextures.PRIMITIVE_BLAST_FURNACE_PROGRESS_BAR, 18).margin(76, 32)) .child(createTankWidget() - .overlayTexture(GTGuiTextures.PRIMITIVE_LARGE_FLUID_TANK_OVERLAY) + .overlay(GTGuiTextures.PRIMITIVE_LARGE_FLUID_TANK_OVERLAY) .background(GTGuiTextures.PRIMITIVE_LARGE_FLUID_TANK) .syncHandler(new FluidSlotSyncHandler( exportFluids.getStorages()[0]) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/LargeBoilerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/LargeBoilerMachine.java index 6ef6d76aae0..fe1d0322c55 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/LargeBoilerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/LargeBoilerMachine.java @@ -237,7 +237,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .padding(0, 4, 4, 4) .childPadding(2) .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) - .excludeAreaInXei() + .excludeAreaInRecipeViewer() .child(GTMuiWidgets.createPowerButton(this, syncManager))) .child(SlotGroupWidget.playerInventory(false).left(7).bottom(7)); return panel; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/storage/BufferMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/storage/BufferMachine.java index 2ad3dc25903..9d9f3ca05a1 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/storage/BufferMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/storage/BufferMachine.java @@ -141,7 +141,7 @@ protected NotifiableFluidTank createTank() { .child(GTMuiWidgets.createAutoOutputFluidButton(autoOutput, syncManager)) .child(GTMuiWidgets.createInputFromOutputItem(autoOutput, syncManager)) .child(GTMuiWidgets.createInputFromOutputFluid(autoOutput, syncManager)) - .excludeAreaInXei()); + .excludeAreaInRecipeViewer()); } /* * @Override diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java b/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java index deb91835105..f2a38f5c0f2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java +++ b/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java @@ -74,6 +74,7 @@ public void receivePacket(SyncHandlerPacket packet) { msm.receiveWidgetUpdate(packet.panel, packet.key, packet.action, id, packet.packet); } catch (IndexOutOfBoundsException e) { GTCEu.LOGGER.error("Failed to read packet for sync handler {} in panel {}", packet.key, packet.panel); + GTCEu.LOGGER.catching(e); } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/MinecraftMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/MinecraftMixin.java index d041d282613..c8ee2288d26 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/MinecraftMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/MinecraftMixin.java @@ -5,15 +5,23 @@ import net.minecraft.Util; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; 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.callback.CallbackInfo; +import javax.annotation.Nullable; + @Mixin(Minecraft.class) public class MinecraftMixin { + @Shadow + @Nullable + public Screen screen; + @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Timer;advanceTime(J)I", shift = At.Shift.AFTER)) public void timer(CallbackInfo ci) { @@ -22,4 +30,14 @@ public void timer(CallbackInfo ci) { ClientScreenHandler.onFrameUpdate(); } } + + @Inject(method = "setScreen", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;removed()V")) + public void setScreen(Screen guiScreen, CallbackInfo ci) { + if (guiScreen == null) { + // the ScreenEvent.Closing is also closed when the screen is transitioning to another screen, + // but we only want to know when the next screen null is, so that all screens close. + ClientScreenHandler.onCloseScreens(this.screen); + } + } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/mui/AEConfigWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/mui/AEConfigWidget.java index 0cba8cf993f..b81702351de 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/mui/AEConfigWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/gui/widget/mui/AEConfigWidget.java @@ -17,8 +17,8 @@ import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEFluidList; import com.gregtechceu.gtceu.integration.ae2.slot.ExportOnlyAEItemList; import com.gregtechceu.gtceu.integration.ae2.slot.IConfigurableSlotList; -import com.gregtechceu.gtceu.integration.emi.handler.EmiStackConverter; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.emi.EmiStackConverter; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; @@ -78,7 +78,7 @@ public AEConfigWidget syncManager(PanelSyncManager syncManager) { @Override public void onInit() { super.onInit(); - getContext().getXeiSettings().addGhostIngredientSlot(this); + getContext().getRecipeViewerSettings().addGhostIngredientSlot(this); editingSlotIndex = -1; pendingAmount = "0"; amountEditorPanel = new SecondaryPanel(getPanel(), this::buildAmountEditor, true); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/handler/EmiStackConverter.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/EmiStackConverter.java similarity index 90% rename from src/main/java/com/gregtechceu/gtceu/integration/emi/handler/EmiStackConverter.java rename to src/main/java/com/gregtechceu/gtceu/integration/emi/EmiStackConverter.java index a15b033a077..79c5effc913 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/handler/EmiStackConverter.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/EmiStackConverter.java @@ -1,11 +1,11 @@ -package com.gregtechceu.gtceu.integration.emi.handler; - -import com.gregtechceu.gtceu.integration.xei.entry.EntryList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidStackList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidTagList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemTagList; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; +package com.gregtechceu.gtceu.integration.emi; + +import com.gregtechceu.gtceu.integration.recipeviewer.entry.EntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; import com.gregtechceu.gtceu.utils.GTMath; import net.minecraft.world.item.Item; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/GTEMIPlugin.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/GTEMIPlugin.java index 912de0be34a..c23a3779658 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/GTEMIPlugin.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/GTEMIPlugin.java @@ -45,6 +45,9 @@ public class GTEMIPlugin implements EmiPlugin { @Override public void register(EmiRegistry registry) { + EmiScreenHandler.register(ScreenWrapper.class, registry); + EmiScreenHandler.register(ContainerScreenWrapper.class, registry); + // Categories registry.addCategory(MultiblockInfoEmiCategory.CATEGORY); if (!ConfigHolder.INSTANCE.compat.hideOreProcessingDiagrams) @@ -106,12 +109,5 @@ public void register(EmiRegistry registry) { FluidStack stack = PotionFluidHelper.getFluidFromPotion(potion, PotionFluidHelper.BOTTLE_AMOUNT); registry.addEmiStack(EmiStack.of(stack.getFluid(), stack.getTag())); } - - registry.addExclusionArea(ScreenWrapper.class, EmiScreenHandler.of(ScreenWrapper.class)); - registry.addExclusionArea(ContainerScreenWrapper.class, EmiScreenHandler.of(ContainerScreenWrapper.class)); - registry.addDragDropHandler(ScreenWrapper.class, EmiScreenHandler.of(ScreenWrapper.class)); - registry.addDragDropHandler(ContainerScreenWrapper.class, EmiScreenHandler.of(ContainerScreenWrapper.class)); - registry.addStackProvider(ScreenWrapper.class, EmiScreenHandler.of(ScreenWrapper.class)); - registry.addStackProvider(ContainerScreenWrapper.class, EmiScreenHandler.of(ContainerScreenWrapper.class)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/circuit/GTProgrammedCircuitCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/circuit/GTProgrammedCircuitCategory.java index 8a56d47c0fe..f5e680154e9 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/circuit/GTProgrammedCircuitCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/circuit/GTProgrammedCircuitCategory.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; -import com.gregtechceu.gtceu.integration.xei.widgets.GTProgrammedCircuitWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTProgrammedCircuitWidget; import com.lowdragmc.lowdraglib.emi.ModularEmiRecipe; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/handler/EmiScreenHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/handler/EmiScreenHandler.java index 297636f4d59..d979606e673 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/handler/EmiScreenHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/handler/EmiScreenHandler.java @@ -1,10 +1,11 @@ package com.gregtechceu.gtceu.integration.emi.handler; import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; -import com.gregtechceu.gtceu.api.mui.base.widget.IGuiElement; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; -import com.gregtechceu.gtceu.integration.xei.handlers.RecipeViewerHandler; +import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; +import com.gregtechceu.gtceu.integration.emi.EmiStackConverter; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.RecipeViewerHandler; import net.minecraft.client.gui.screens.Screen; import net.minecraft.world.item.Item; @@ -12,6 +13,7 @@ import dev.emi.emi.api.EmiDragDropHandler; import dev.emi.emi.api.EmiExclusionArea; +import dev.emi.emi.api.EmiRegistry; import dev.emi.emi.api.EmiStackProvider; import dev.emi.emi.api.stack.EmiIngredient; import dev.emi.emi.api.stack.EmiStack; @@ -33,15 +35,29 @@ public class EmiScreenHandler extends RecipeViewe @SuppressWarnings("unchecked") public static EmiScreenHandler of(Class cls) { - return (EmiScreenHandler) CACHE.computeIfAbsent(cls, c -> new EmiScreenHandler()); + return (EmiScreenHandler) CACHE.computeIfAbsent(cls, c -> new EmiScreenHandler((Class) c)); } - private EmiScreenHandler() {} + protected final Class clazz; + + private EmiScreenHandler(Class clazz) { + this.clazz = clazz; + } + + public void register(EmiRegistry registry) { + registry.addExclusionArea(this.clazz, this); + registry.addDragDropHandler(this.clazz, this); + registry.addStackProvider(this.clazz, this); + } + + public static void register(Class clazz, EmiRegistry registry) { + of(clazz).register(registry); + } @Override public boolean dropStack(T screen, EmiIngredient stack, int x, int y) { List> ghostSlots = screen.getScreen().getContext() - .getXeiSettings().getGhostIngredientSlots(); + .getRecipeViewerSettings().getGhostIngredientSlots(); var stacks = stack.getEmiStacks(); if (stacks.isEmpty()) return false; @@ -72,7 +88,7 @@ public boolean dropStack(T screen, EmiIngredient stack, int x, int y) { @Override public void addExclusionArea(T screen, Consumer consumer) { screen.getScreen().getContext() - .getXeiSettings().getAllExclusionAreas() + .getRecipeViewerSettings().getAllExclusionAreas() .stream() .map(rect -> new Bounds(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight())) .forEach(consumer); @@ -80,7 +96,7 @@ public void addExclusionArea(T screen, Consumer consumer) { @Override public EmiStackInteraction getStackAt(T screen, int x, int y) { - IGuiElement hovered = screen.getScreen().getContext().getTopHovered(); + IWidget hovered = screen.getScreen().getContext().getTopHovered(); if (hovered instanceof IngredientProvider provider) { var override = provider.ingredientOverride(); if (override != null) { diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/oreprocessing/GTEmiOreProcessing.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/oreprocessing/GTEmiOreProcessing.java index ff3eac37e13..fedffb74b58 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/oreprocessing/GTEmiOreProcessing.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/oreprocessing/GTEmiOreProcessing.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.emi.oreprocessing; import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreByProductWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreByProductWidget; import com.lowdragmc.lowdraglib.emi.ModularEmiRecipe; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockFluid.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockFluid.java index 5af61528004..8500635056f 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockFluid.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockFluid.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.bedrockfluid.BedrockFluidDefinition; import com.gregtechceu.gtceu.client.ClientProxy; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.emi.ModularEmiRecipe; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockOre.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockOre.java index 4f2e701bd3c..40b5034d035 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockOre.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTBedrockOre.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; import com.gregtechceu.gtceu.client.ClientProxy; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.emi.ModularEmiRecipe; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTEmiOreVein.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTEmiOreVein.java index 250103a54cc..fa48694355b 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTEmiOreVein.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/orevein/GTEmiOreVein.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.GTOreDefinition; import com.gregtechceu.gtceu.client.ClientProxy; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.emi.ModularEmiRecipe; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe.java index 125dac7b7cd..b1f8593b29c 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.emi.recipe; import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.integration.xei.widgets.GTRecipeWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTRecipeWidget; import com.lowdragmc.lowdraglib.emi.ModularEmiRecipe; import com.lowdragmc.lowdraglib.emi.ModularForegroundRenderWidget; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe2.java b/src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe2.java new file mode 100644 index 00000000000..7200b2a9509 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/emi/recipe/GTEmiRecipe2.java @@ -0,0 +1,232 @@ +package com.gregtechceu.gtceu.integration.emi.recipe; + +import com.gregtechceu.gtceu.api.mui.base.widget.ITooltip; +import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; +import com.gregtechceu.gtceu.api.mui.drawable.text.RichText; +import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; +import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; +import com.gregtechceu.gtceu.api.mui.widgets.slot.FluidSlot; +import com.gregtechceu.gtceu.api.mui.widgets.slot.ItemSlot; +import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; +import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; +import com.gregtechceu.gtceu.integration.emi.EmiStackConverter; +import com.gregtechceu.gtceu.integration.recipeviewer.RecipeSlotRole; +import com.gregtechceu.gtceu.integration.recipeviewer.RecipeViewerScreenWrapper; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.fluid.EmptyFluidTank; +import com.gregtechceu.gtceu.integration.recipeviewer.util.RecipeScreenRenderingUtil; +import com.gregtechceu.gtceu.utils.memoization.GTMemoizer; +import com.gregtechceu.gtceu.utils.memoization.MemoizedSupplier; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.locale.Language; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Recipe; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.*; +import lombok.Getter; +import org.jetbrains.annotations.Nullable; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public abstract class GTEmiRecipe2, W extends IWidget> implements EmiRecipe { + + @Getter + protected final T recipe; + protected final EmiRecipeCategory category; + protected final MemoizedSupplier screen; + + @Getter + public final List inputs; + @Getter + public final List outputs; + @Getter + public final List catalysts; + + @Getter + private final Bounds bounds; + @Getter + private final int displayWidth, displayHeight; + + public boolean allowRecipeTree = true; + + public GTEmiRecipe2(T recipe, EmiRecipeCategory category, Supplier widgetSupplier) { + this.recipe = recipe; + this.category = category; + + this.inputs = new ArrayList<>(); + this.outputs = new ArrayList<>(); + this.catalysts = new ArrayList<>(); + + W recipeWidget = widgetSupplier.get(); + this.displayWidth = recipeWidget.getArea().width; + this.displayHeight = recipeWidget.getArea().height; + this.bounds = new Bounds(0, 0, this.displayWidth, this.displayHeight); + + this.screen = GTMemoizer.memoize(() -> { + W widget = widgetSupplier.get(); + ModularPanel panel = ModularPanel.defaultPanel(recipe.getId().toString(), widget.getArea().w(), + widget.getArea().h()); + panel.child(widget); + return new ModularScreen(recipe.getId().getNamespace(), panel); + }, Duration.ofSeconds(10)); + + WidgetTree.foreachChildBFS(recipeWidget, widget -> { + if (!(widget instanceof IngredientProvider provider)) { + return true; + } + RecipeSlotRole role = provider.recipeRole(); + if (role == RecipeSlotRole.RENDER_ONLY) { + return true; + } + + EmiStackConverter.Converter converter = EmiStackConverter.getForNullable(provider.ingredientClass()); + if (converter == null) { + return true; + } + @SuppressWarnings({ "rawtypes", "unchecked" }) + EmiIngredient ingredient = ((EmiStackConverter.Converter) converter).convertTo(provider); + + switch (role) { + case INPUT -> inputs.add(ingredient); + case OUTPUT -> { + if (ingredient.getEmiStacks().size() > 1) { + allowRecipeTree = false; + } + outputs.addAll(ingredient.getEmiStacks()); + } + case CATALYST -> catalysts.add(ingredient); + } + return true; + }, true); + } + + @Override + public EmiRecipeCategory getCategory() { + return category; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + widgets.add(new UIWrapperWidget()); + + WidgetTree.foreachChildBFS(this.screen.get().getMainPanel(), widget -> { + if (!(widget instanceof IngredientProvider provider)) return true; + + RecipeSlotRole role = provider.recipeRole(); + if (role == RecipeSlotRole.RENDER_ONLY) { + return true; + } + EmiStackConverter.Converter converter = EmiStackConverter.getForNullable(provider.ingredientClass()); + if (converter == null) { + return true; + } + @SuppressWarnings({ "rawtypes", "unchecked" }) + EmiIngredient ingredient = ((EmiStackConverter.Converter) converter).convertTo(provider); + Area widgetArea = widget.getArea(); + + SlotWidget slotWidget = null; + // Clear the MUI slots and add EMI slots based on them. + if (provider instanceof ItemSlot itemSlot) { + itemSlot.slot(RecipeScreenRenderingUtil.EMPTY_ITEM_HANDLER, 0) + .invisible(); + } else if (provider instanceof FluidSlot fluidSlot) { + fluidSlot.syncHandler(EmptyFluidTank.INSTANCE) + .invisible(); + + long capacity = Math.max(1, ingredient.getAmount()); + slotWidget = new TankWidget(ingredient, widgetArea.x, widgetArea.y, widgetArea.width, widgetArea.height, + capacity); + } + if (slotWidget == null) { + slotWidget = new SlotWidget(ingredient, widgetArea.x, widgetArea.y); + } + + slotWidget.customBackground(null, widgetArea.x, widgetArea.y, widgetArea.width, widgetArea.height) + .drawBack(false); + + if (role == RecipeSlotRole.CATALYST) { + slotWidget.catalyst(true); + } else if (role == RecipeSlotRole.OUTPUT) { + slotWidget.recipeContext(this); + } + if (widget instanceof ITooltip tooltip && tooltip.hasTooltip()) { + if (tooltip.tooltip().getRichText() instanceof RichText richText) { + var textList = richText.getAsText(); + for (FormattedText line : textList) { + slotWidget + .appendTooltip(() -> ClientTooltipComponent + .create(Language.getInstance().getVisualOrder(line))); + } + } + } + widgets.add(slotWidget); + return true; + }, true); + widgets.add(new UIForegroundRenderWidget()); + } + + @Override + public @Nullable ResourceLocation getId() { + return this.recipe.getId(); + } + + @Override + public boolean supportsRecipeTree() { + return this.allowRecipeTree && EmiRecipe.super.supportsRecipeTree(); + } + + public class UIWrapperWidget extends Widget { + + public UIWrapperWidget() { + ModularScreen screen = GTEmiRecipe2.this.screen.get(); + screen.construct(new RecipeViewerScreenWrapper(screen)); + } + + @Override + public Bounds getBounds() { + return GTEmiRecipe2.this.bounds; + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + ModularScreen screen = GTEmiRecipe2.this.screen.get(); + RecipeScreenRenderingUtil.drawScreenBackground(guiGraphics, screen, mouseX, mouseY, partialTick); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return screen.get().onMousePressed(mouseX, mouseY, button); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + return screen.get().keyPressed(keyCode, scanCode, modifiers); + } + } + + public class UIForegroundRenderWidget extends Widget { + + public UIForegroundRenderWidget() {} + + @Override + public Bounds getBounds() { + return GTEmiRecipe2.this.bounds; + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + ModularScreen screen = GTEmiRecipe2.this.screen.get(); + RecipeScreenRenderingUtil.drawScreenForeground(guiGraphics, screen, mouseX, mouseY, partialTick); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/GTJEIPlugin.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/GTJEIPlugin.java index cfc9389b326..f35b1a64f81 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/GTJEIPlugin.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/GTJEIPlugin.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.recipe.category.GTRecipeCategory; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.client.mui.screen.ContainerScreenWrapper; +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; import com.gregtechceu.gtceu.client.mui.screen.ScreenWrapper; import com.gregtechceu.gtceu.common.data.GTFluids; import com.gregtechceu.gtceu.common.data.GTItems; @@ -13,8 +14,8 @@ import com.gregtechceu.gtceu.common.item.IntCircuitBehaviour; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.integration.jei.circuit.GTProgrammedCircuitCategory; -import com.gregtechceu.gtceu.integration.jei.handler.JEIContainerHandler; -import com.gregtechceu.gtceu.integration.jei.handler.JEIScreenHandler; +import com.gregtechceu.gtceu.integration.jei.handler.JeiContainerHandler; +import com.gregtechceu.gtceu.integration.jei.handler.JeiScreenHandler; import com.gregtechceu.gtceu.integration.jei.multipage.MultiblockInfoCategory; import com.gregtechceu.gtceu.integration.jei.oreprocessing.GTOreProcessingInfoCategory; import com.gregtechceu.gtceu.integration.jei.orevein.GTBedrockFluidInfoCategory; @@ -77,7 +78,7 @@ public void registerCategories(@NotNull IRecipeCategoryRegistration registry) { registry.addRecipeCategories(new GTBedrockOreInfoCategory(jeiHelpers)); for (GTRecipeCategory category : GTRegistries.RECIPE_CATEGORIES) { if (category.shouldRegisterDisplays()) { - registry.addRecipeCategories(new GTRecipeJEICategory(jeiHelpers, category)); + // registry.addRecipeCategories(new GTRecipeJEICategory(jeiHelpers, category)); } } registry.addRecipeCategories(new GTProgrammedCircuitCategory(jeiHelpers)); @@ -151,9 +152,15 @@ public void registerExtraIngredients(IExtraIngredientRegistration registration) @Override public void registerGuiHandlers(IGuiHandlerRegistration registration) { if (GTCEu.Mods.isREILoaded() || GTCEu.Mods.isEMILoaded()) return; - registration.addGhostIngredientHandler(ScreenWrapper.class, JEIScreenHandler.of(ScreenWrapper.class)); - registration.addGhostIngredientHandler(ContainerScreenWrapper.class, - JEIScreenHandler.of(ContainerScreenWrapper.class)); - registration.addGuiContainerHandler(ContainerScreenWrapper.class, JEIContainerHandler.INSTANCE); + + JeiScreenHandler.register(ScreenWrapper.class, registration); + JeiScreenHandler.register(ContainerScreenWrapper.class, registration); + } + + @Override + public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { + if (GTCEu.Mods.isREILoaded() || GTCEu.Mods.isEMILoaded()) return; + + JeiContainerHandler.register(ModularContainerMenu.class, registration); } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/GTJeiProperties.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/GTJeiProperties.java new file mode 100644 index 00000000000..c3e89a1cbb9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/GTJeiProperties.java @@ -0,0 +1,73 @@ +package com.gregtechceu.gtceu.integration.jei; + +import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; +import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; + +import net.minecraft.client.gui.screens.Screen; + +import lombok.Getter; +import mezz.jei.api.gui.handlers.IGuiProperties; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.util.Objects; + +/** + * This needs to be an immutable class. + */ +public class GTJeiProperties implements IGuiProperties { + + @Getter + private final Class screenClass; + @Getter + private final int guiLeft; + @Getter + private final int guiTop; + @Getter + private final int guiXSize; + @Getter + private final int guiYSize; + @Getter + private final int screenWidth; + @Getter + private final int screenHeight; + + public GTJeiProperties(IMuiScreen screen) { + Area mainArea = screen.getScreen().getMainPanel().getArea(); + Area screenArea = screen.getScreen().getScreenArea(); + this.screenClass = screen.getWrappedScreen().getClass(); + this.guiLeft = mainArea.x; + this.guiTop = mainArea.y; + this.guiXSize = mainArea.width; + this.guiYSize = mainArea.height; + this.screenWidth = screenArea.width; + this.screenHeight = screenArea.height; + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("x", getGuiLeft()) + .append("y", getGuiTop()) + .append("width", getGuiXSize()) + .append("height", getGuiYSize()) + .append("screenWidth", getScreenWidth()) + .append("screenHeight", getScreenHeight()) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GTJeiProperties that = (GTJeiProperties) o; + return guiLeft == that.guiLeft && guiTop == that.guiTop && guiXSize == that.guiXSize && + guiYSize == that.guiYSize && + screenWidth == that.screenWidth && screenHeight == that.screenHeight && + Objects.equals(screenClass, that.screenClass); + } + + @Override + public int hashCode() { + return Objects.hash(screenClass, guiLeft, guiTop, guiXSize, guiYSize, screenWidth, screenHeight); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/GhostIngredientTarget.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/GhostIngredientTarget.java similarity index 73% rename from src/main/java/com/gregtechceu/gtceu/integration/jei/handler/GhostIngredientTarget.java rename to src/main/java/com/gregtechceu/gtceu/integration/jei/GhostIngredientTarget.java index 23743ed271e..a8bf9f95eb3 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/GhostIngredientTarget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/GhostIngredientTarget.java @@ -1,7 +1,6 @@ -package com.gregtechceu.gtceu.integration.jei.handler; +package com.gregtechceu.gtceu.integration.jei; -import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; import net.minecraft.client.renderer.Rect2i; @@ -12,10 +11,6 @@ public class GhostIngredientTarget implements IGhostIngredientHandler.Target< private final GhostIngredientSlot ghostSlot; - public static > GhostIngredientTarget of(W slot) { - return new GhostIngredientTarget<>(slot); - } - public GhostIngredientTarget(GhostIngredientSlot ghostSlot) { this.ghostSlot = ghostSlot; } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/circuit/GTProgrammedCircuitCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/circuit/GTProgrammedCircuitCategory.java index fdf85cb2564..1e0af9725af 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/circuit/GTProgrammedCircuitCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/circuit/GTProgrammedCircuitCategory.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.common.data.GTItems; -import com.gregtechceu.gtceu.integration.xei.widgets.GTProgrammedCircuitWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTProgrammedCircuitWidget; import com.lowdragmc.lowdraglib.jei.ModularUIRecipeCategory; import com.lowdragmc.lowdraglib.jei.ModularWrapper; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIContainerHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIContainerHandler.java deleted file mode 100644 index b80f025dc7a..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIContainerHandler.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.gregtechceu.gtceu.integration.jei.handler; - -import com.gregtechceu.gtceu.api.mui.base.widget.IGuiElement; -import com.gregtechceu.gtceu.api.mui.utils.Rectangle; -import com.gregtechceu.gtceu.client.mui.screen.ContainerScreenWrapper; -import com.gregtechceu.gtceu.integration.jei.GTJEIPlugin; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; - -import net.minecraft.client.renderer.Rect2i; - -import lombok.Getter; -import mezz.jei.api.gui.handlers.IGuiContainerHandler; -import mezz.jei.api.ingredients.IIngredientType; -import mezz.jei.api.ingredients.ITypedIngredient; -import mezz.jei.api.runtime.IClickableIngredient; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.Optional; - -public class JEIContainerHandler implements IGuiContainerHandler { - - public static final JEIContainerHandler INSTANCE = new JEIContainerHandler(); - - private JEIContainerHandler() {} - - @Override - public @NotNull List getGuiExtraAreas(ContainerScreenWrapper screen) { - return screen.getScreen().getContext() - .getXeiSettings().getAllExclusionAreas() - .stream().map(Rectangle::asRect2i) - .toList(); - } - - @Override - public @NotNull Optional> getClickableIngredientUnderMouse(@NotNull ContainerScreenWrapper screen, - double mouseX, double mouseY) { - IGuiElement hovered = screen.getScreen().getContext().getTopHovered(); - if (hovered instanceof IngredientProvider provider) { - var override = provider.ingredientOverride(); - if (override != null) { - JEIScreenHandler.currentIngredient = ((IClickableIngredient) override).getTypedIngredient(); - return Optional.of((IClickableIngredient) override); - } - if (provider.getIngredients().isEmpty()) return Optional.empty(); - - Optional> ingredient = GTJEIPlugin.getRuntime() - .getIngredientManager() - .createTypedIngredient(mapFirstIngredient(provider)); - - JEIScreenHandler.currentIngredient = ingredient.orElse(null); - return ingredient.map(i -> new ClickableIngredient<>(i, hovered.getArea().asRect2i())); - } - return Optional.empty(); - } - - private T mapFirstIngredient(IngredientProvider provider) { - return provider.renderMappingFunction().apply(provider.getIngredients().getStacks().get(0)); - } - - private record ClickableIngredient(ITypedIngredient ingredient, @Getter Rect2i area) - implements IClickableIngredient { - - @SuppressWarnings("removal") // I have to override this. - @Override - public @NotNull ITypedIngredient getTypedIngredient() { - return ingredient; - } - - @Override - public @NotNull IIngredientType getIngredientType() { - return ingredient.getType(); - } - - @Override - public @NotNull T getIngredient() { - return ingredient.getIngredient(); - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIScreenHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIScreenHandler.java deleted file mode 100644 index 5282451beb6..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JEIScreenHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.gregtechceu.gtceu.integration.jei.handler; - -import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; -import com.gregtechceu.gtceu.core.mixins.jei.IngredientListOverlayAccessor; -import com.gregtechceu.gtceu.integration.jei.GTJEIPlugin; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; -import com.gregtechceu.gtceu.integration.xei.handlers.RecipeViewerHandler; - -import net.minecraft.client.gui.screens.Screen; - -import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import mezz.jei.api.gui.handlers.IGhostIngredientHandler; -import mezz.jei.api.ingredients.ITypedIngredient; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class JEIScreenHandler extends RecipeViewerHandler - implements IGhostIngredientHandler { - - private static final Map, JEIScreenHandler> CACHE = new Reference2ReferenceOpenHashMap<>(); - - @SuppressWarnings("unchecked") - public static JEIScreenHandler of(Class cls) { - return (JEIScreenHandler) CACHE.computeIfAbsent(cls, c -> new JEIScreenHandler()); - } - - private JEIScreenHandler() {} - - @Override - public @NotNull List> getTargetsTyped(T screen, - @NotNull ITypedIngredient ingredient, - boolean doStart) { - currentIngredient = ingredient; - - List> ghostSlots = screen.getScreen().getContext() - .getXeiSettings().getGhostIngredientSlots(); - List> ghostHandlerTargets = new ArrayList<>(); - for (var slot : ghostSlots) { - if (slot.isEnabled() && slot.castGhostIngredientIfValid(ingredient.getIngredient()) != null) { - @SuppressWarnings("unchecked") - GhostIngredientSlot slotWithType = (GhostIngredientSlot) slot; - ghostHandlerTargets.add(new GhostIngredientTarget<>(slotWithType)); - } - } - return ghostHandlerTargets; - } - - @Override - public void onComplete() { - currentIngredient = null; - } - - static ITypedIngredient currentIngredient = null; - - @Override - public void setSearchFocused(boolean focused) { - // only set the search field state if it's JEI's actual search field and not JEMI - if (GTJEIPlugin.getRuntime().getIngredientListOverlay() instanceof IngredientListOverlayAccessor accessor) { - accessor.getSearchField().setFocused(focused); - } - } - - @Override - public @Nullable Object getCurrentlyDragged() { - if (currentIngredient == null) return null; - return currentIngredient.getIngredient(); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiContainerHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiContainerHandler.java new file mode 100644 index 00000000000..21f676a4c06 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiContainerHandler.java @@ -0,0 +1,106 @@ +package com.gregtechceu.gtceu.integration.jei.handler; + +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; +import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.RecipeTransferError; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.RecipeTransferHandler; + +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; + +import mezz.jei.api.gui.builder.ITooltipBuilder; +import mezz.jei.api.gui.ingredient.IRecipeSlotsView; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper; +import mezz.jei.api.recipe.transfer.IUniversalRecipeTransferHandler; +import mezz.jei.api.registration.IRecipeTransferRegistration; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.Optional; + +public class JeiContainerHandler implements IUniversalRecipeTransferHandler { + + public static void register(Class clz, + IRecipeTransferRegistration registration) { + new JeiContainerHandler<>(clz, registration.getTransferHelper()).register(registration); + } + + private final Class clazz; + private final IRecipeTransferHandlerHelper handlerHelper; + + private JeiContainerHandler(Class clazz, IRecipeTransferHandlerHelper handlerHelper) { + this.clazz = clazz; + this.handlerHelper = handlerHelper; + } + + private void register(IRecipeTransferRegistration registration) { + registration.addUniversalRecipeTransferHandler(this); + } + + @Override + public Class getContainerClass() { + return clazz; + } + + @Override + public Optional> getMenuType() { + return Optional.empty(); + } + + @Override + public @Nullable IRecipeTransferError transferRecipe(T container, Object recipe, IRecipeSlotsView recipeSlots, + Player player, boolean maxTransfer, boolean doTransfer) { + ModularScreen screen = container.getScreen(); + if (screen instanceof RecipeTransferHandler transferHandler && + Objects.equals(recipe.getClass(), transferHandler.getRecipeClass())) { + RecipeTransferError muiError = transferHandler.transferRecipeSafe(recipe, maxTransfer, !doTransfer); + if (muiError != null) { + return new CosmeticJeiTransferError(muiError); + } + } + return null; + } + + public record CosmeticJeiTransferError(RecipeTransferError muiError) implements IRecipeTransferError { + + @Override + public Type getType() { + if (muiError instanceof RecipeTransferError.Internal) { + return Type.INTERNAL; + } else if (muiError instanceof RecipeTransferError.UserFacing) { + return Type.USER_FACING; + } else if (muiError instanceof RecipeTransferError.Cosmetic) { + return Type.COSMETIC; + } else { + throw new IllegalStateException( + "Recipe transfer error %s is not an internal, user facing or cosmetic error" + .formatted(muiError)); + } + } + + @Override + public int getButtonHighlightColor() { + return muiError.getButtonHighlightColor(); + } + + @Override + public void getTooltip(ITooltipBuilder tooltip) { + if (this.muiError instanceof RecipeTransferError.UserFacing) { + tooltip.add(Component.translatable("jei.tooltip.transfer")); + for (Component component : muiError.getTooltip()) { + tooltip.add(component.copy().withStyle(ChatFormatting.RED)); + } + } else { + tooltip.addAll(muiError.getTooltip()); + } + } + + @Override + public int getMissingCountHint() { + return muiError.getMissingCountHint(); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiScreenHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiScreenHandler.java new file mode 100644 index 00000000000..ede283437c2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/handler/JeiScreenHandler.java @@ -0,0 +1,177 @@ +package com.gregtechceu.gtceu.integration.jei.handler; + +import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; +import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; +import com.gregtechceu.gtceu.api.mui.utils.Rectangle; +import com.gregtechceu.gtceu.core.mixins.jei.IngredientListOverlayAccessor; +import com.gregtechceu.gtceu.integration.jei.GTJEIPlugin; +import com.gregtechceu.gtceu.integration.jei.GTJeiProperties; +import com.gregtechceu.gtceu.integration.jei.GhostIngredientTarget; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.RecipeViewerHandler; + +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.world.inventory.AbstractContainerMenu; + +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import mezz.jei.api.gui.handlers.IGhostIngredientHandler; +import mezz.jei.api.gui.handlers.IGuiContainerHandler; +import mezz.jei.api.gui.handlers.IGuiProperties; +import mezz.jei.api.gui.handlers.IScreenHandler; +import mezz.jei.api.ingredients.ITypedIngredient; +import mezz.jei.api.registration.IGuiHandlerRegistration; +import mezz.jei.api.runtime.IClickableIngredient; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class JeiScreenHandler extends RecipeViewerHandler + implements IGhostIngredientHandler, IScreenHandler { + + private static final Map, JeiScreenHandler> CACHE = new Reference2ReferenceOpenHashMap<>(); + + @SuppressWarnings("unchecked") + public static JeiScreenHandler of(Class clazz) { + return (JeiScreenHandler) CACHE.computeIfAbsent(clazz, clz -> new JeiScreenHandler<>((Class) clz)); + } + + protected final Class clazz; + + private JeiScreenHandler(Class clazz) { + this.clazz = clazz; + } + + public static & IMuiScreen> void register(Class clazz, + IGuiHandlerRegistration registration) { + if (AbstractContainerScreen.class.isAssignableFrom(clazz)) { + // noinspection unchecked + ContainerScreen.ofContainer((Class) clazz).register(registration); + } else { + of(clazz).register(registration); + } + } + + public void register(IGuiHandlerRegistration registration) { + registration.addGhostIngredientHandler(this.clazz, this); + registration.addGuiScreenHandler(this.clazz, this); + } + + @Override + public List> getTargetsTyped(T screen, ITypedIngredient ingredient, boolean doStart) { + currentIngredient = ingredient; + + List> ghostSlots = screen.getScreen().getContext() + .getRecipeViewerSettings().getGhostIngredientSlots(); + List> ghostHandlerTargets = new ArrayList<>(); + for (var slot : ghostSlots) { + if (slot.isEnabled() && slot.castGhostIngredientIfValid(ingredient.getIngredient()) != null) { + @SuppressWarnings("unchecked") + GhostIngredientSlot slotWithType = (GhostIngredientSlot) slot; + ghostHandlerTargets.add(new GhostIngredientTarget<>(slotWithType)); + } + } + return ghostHandlerTargets; + } + + @Override + public boolean shouldHighlightTargets() { + return false; + } + + @Override + public @Nullable IGuiProperties apply(T guiScreen) { + return guiScreen.getScreen().getContext().getRecipeViewerSettings().isEnabled(guiScreen.getScreen()) ? + new GTJeiProperties(guiScreen) : null; + } + + @Override + public void onComplete() { + currentIngredient = null; + } + + // this is an actual ItemStack/FluidStack instance, **not** an ITypedIngredient or such + private static Object currentIngredient = null; + + @Override + public void setSearchFocused(boolean focused) { + // only set the search field state if it's JEI's actual search field and not JEMI + if (GTJEIPlugin.getRuntime().getIngredientListOverlay() instanceof IngredientListOverlayAccessor accessor) { + accessor.getSearchField().setFocused(focused); + } + } + + @Override + public @Nullable Object getCurrentlyDragged() { + if (currentIngredient == null) return null; + return currentIngredient; + } + + public static class ContainerScreen & IMuiScreen> + extends JeiScreenHandler + implements IGuiContainerHandler { + + @SuppressWarnings("unchecked") + public static & IMuiScreen> ContainerScreen ofContainer(Class clazz) { + return (ContainerScreen) CACHE.computeIfAbsent(clazz, clz -> new ContainerScreen<>((Class) clz)); + } + + private ContainerScreen(Class clazz) { + super(clazz); + } + + @Override + public void register(IGuiHandlerRegistration registry) { + super.register(registry); + registry.addGuiContainerHandler(this.clazz, this); + } + + @Override + public List getGuiExtraAreas(T1 screen) { + return screen.getScreen().getContext() + .getRecipeViewerSettings().getAllExclusionAreas() + .stream().map(Rectangle::asRect2i) + .toList(); + } + + @Override + public Optional> getClickableIngredientUnderMouse(T1 screen, double mouseX, + double mouseY) { + IWidget hovered = screen.getScreen().getContext().getTopHovered(); + if (hovered instanceof IngredientProvider provider) { + var override = provider.ingredientOverride(); + if (override instanceof IClickableIngredient clickableIngredient) { + JeiScreenHandler.currentIngredient = clickableIngredient.getIngredient(); + return Optional.of(clickableIngredient); + } + if (provider.getIngredients().isEmpty()) return Optional.empty(); + + Optional> ingredient = this + .createClickableIngredient(mapFirstIngredient(provider), hovered.getArea()); + + JeiScreenHandler.currentIngredient = ingredient.map(IClickableIngredient::getIngredient).orElse(null); + // noinspection unchecked + return (Optional>) ingredient; + } + return Optional.empty(); + } + + private I mapFirstIngredient(IngredientProvider provider) { + return provider.renderMappingFunction().apply(provider.getIngredients().getStacks().get(0)); + } + + private Optional> createClickableIngredient(I ingredient, Rectangle area) { + return GTJEIPlugin.getRuntime() + .getIngredientManager() + .createClickableIngredient(ingredient, area.asRect2i(), false); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/oreprocessing/GTOreProcessingInfoWrapper.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/oreprocessing/GTOreProcessingInfoWrapper.java index 3f33de6d446..3ab837f790c 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/oreprocessing/GTOreProcessingInfoWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/oreprocessing/GTOreProcessingInfoWrapper.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.jei.oreprocessing; import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreByProductWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreByProductWidget; import com.lowdragmc.lowdraglib.jei.ModularWrapper; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoCategory.java index badbc830993..ea01410570f 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoCategory.java @@ -4,7 +4,7 @@ import com.gregtechceu.gtceu.client.ClientProxy; import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.common.data.GTMaterials; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.jei.ModularUIRecipeCategory; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoWrapper.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoWrapper.java index 5d0d784a48c..8c97cd1c534 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockFluidInfoWrapper.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.jei.orevein; import com.gregtechceu.gtceu.api.data.worldgen.bedrockfluid.BedrockFluidDefinition; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.jei.ModularWrapper; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoCategory.java index 496fb4bbc52..b0589480b87 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoCategory.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.client.ClientProxy; import com.gregtechceu.gtceu.common.data.GTItems; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.jei.ModularUIRecipeCategory; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoWrapper.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoWrapper.java index 918a802a8d2..2a6446090e0 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTBedrockOreInfoWrapper.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.jei.orevein; import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.jei.ModularWrapper; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoCategory.java index 5337954a192..0abe2f636c1 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoCategory.java @@ -6,7 +6,7 @@ import com.gregtechceu.gtceu.client.ClientProxy; import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.common.data.GTMaterials; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.jei.ModularUIRecipeCategory; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoWrapper.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoWrapper.java index 6fbc0feb30b..a782c538a12 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/orevein/GTOreVeinInfoWrapper.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.jei.orevein; import com.gregtechceu.gtceu.api.data.worldgen.GTOreDefinition; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.jei.ModularWrapper; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeJEICategory.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeJEICategory.java index 93d359fa065..616dc0a2fbc 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeJEICategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeJEICategory.java @@ -2,56 +2,107 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.MachineDefinition; +import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; +import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; +import com.gregtechceu.gtceu.api.mui.widget.sizer.Area; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; import com.gregtechceu.gtceu.api.recipe.category.GTRecipeCategory; import com.gregtechceu.gtceu.api.registry.GTRegistries; +import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; +import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; import com.gregtechceu.gtceu.common.data.GTRecipeTypes; - -import com.lowdragmc.lowdraglib.jei.IGui2IDrawable; -import com.lowdragmc.lowdraglib.jei.ModularUIRecipeCategory; +import com.gregtechceu.gtceu.integration.jei.GTJEIPlugin; +import com.gregtechceu.gtceu.integration.recipeviewer.RecipeSlotRole; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.util.RecipeScreenRenderingUtil; import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.ScreenPosition; +import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.crafting.Recipe; -import lombok.Getter; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import mezz.jei.api.constants.RecipeTypes; -import mezz.jei.api.gui.drawable.IDrawable; -import mezz.jei.api.helpers.IGuiHelper; -import mezz.jei.api.helpers.IJeiHelpers; +import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; +import mezz.jei.api.gui.builder.IRecipeSlotBuilder; +import mezz.jei.api.gui.builder.ITooltipBuilder; +import mezz.jei.api.gui.ingredient.IRecipeSlotsView; +import mezz.jei.api.gui.inputs.IJeiGuiEventListener; +import mezz.jei.api.gui.widgets.IRecipeExtrasBuilder; +import mezz.jei.api.gui.widgets.IRecipeWidget; +import mezz.jei.api.ingredients.IIngredientRenderer; +import mezz.jei.api.recipe.IFocusGroup; +import mezz.jei.api.recipe.RecipeIngredientRole; import mezz.jei.api.recipe.RecipeType; +import mezz.jei.api.recipe.category.IRecipeCategory; import mezz.jei.api.registration.IRecipeCatalystRegistration; import mezz.jei.api.registration.IRecipeRegistration; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.apache.commons.lang3.mutable.MutableInt; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.function.Function; -public class GTRecipeJEICategory extends ModularUIRecipeCategory { +public abstract class GTRecipeJEICategory, W extends IWidget> implements IRecipeCategory { public static final Function> TYPES = Util .memoize(c -> new RecipeType<>(c.registryKey, GTRecipe.class)); - private final GTRecipeCategory category; - @Getter - private final IDrawable background; - @Getter - private final IDrawable icon; - - public GTRecipeJEICategory(IJeiHelpers helpers, - @NotNull GTRecipeCategory category) { - super(GTRecipeWrapper::new); - this.category = category; - var recipeType = category.getRecipeType(); - IGuiHelper guiHelper = helpers.getGuiHelper(); - var size = recipeType.getRecipeUI().getJEISize(); - this.background = guiHelper.createBlankDrawable(size.width, size.height); - this.icon = IGui2IDrawable.toDrawable(category.getIcon(), 16, 16); + private final LoadingCache modularScreenCache; + + /* + * private final GTRecipeCategory category; + * + * @Getter + * private final IDrawable background; + * + * @Getter + * private final IDrawable icon; + */ + + protected GTRecipeJEICategory(Function wrapperFunction, Function recipeIdGetter) { + this.modularScreenCache = CacheBuilder.newBuilder() + .expireAfterAccess(10, TimeUnit.SECONDS) + .maximumSize(10) + .build(new CacheLoader<>() { + + @Override + public ModularScreen load(T recipe) { + W widget = wrapperFunction.apply(recipe); + ResourceLocation recipeId = recipeIdGetter.apply(recipe); + + ModularPanel panel = ModularPanel.defaultPanel(recipeId.toString(), + widget.getArea().width, widget.getArea().height); + panel.child(widget); + return new ModularScreen(recipeId.getNamespace(), panel); + } + }); } + /* + * public GTRecipeJEICategory(IJeiHelpers helpers, + * + * @NotNull GTRecipeCategory category) { + * super(GTRecipeWrapper::new); + * this.category = category; + * var recipeType = category.getRecipeType(); + * IGuiHelper guiHelper = helpers.getGuiHelper(); + * var size = recipeType.getRecipeUI().getJEISize(); + * this.background = guiHelper.createBlankDrawable(size.width, size.height); + * this.icon = IGui2IDrawable.toDrawable(category.getIcon(), 16, 16); + * } + */ + public static void registerRecipes(IRecipeRegistration registration) { List subCategories = new ArrayList<>(); // run main categories first @@ -92,20 +143,174 @@ public static RecipeType machineType(GTRecipeCategory category) { return TYPES.apply(category); } + private ModularScreen getModularScreen(T recipe) { + return this.modularScreenCache.getUnchecked(recipe); + } + + private static void addJEISlot(IRecipeLayoutBuilder builder, IngredientProvider widget, + RecipeIngredientRole role, int index) { + var type = GTJEIPlugin.getRuntime().getIngredientManager() + .getIngredientTypeChecked(widget.ingredientClass()); + if (type.isEmpty()) { + return; + } + + Area widgetArea = widget.getArea(); + IRecipeSlotBuilder slotBuilder = builder.addSlot(role, widgetArea.x, widgetArea.y); + + slotBuilder.addIngredients(type.get(), widget.getIngredients().getStacks()); + slotBuilder.setCustomRenderer(type.get(), new IIngredientRenderer<>() { + + @Override + public void render(GuiGraphics guiGraphics, T ingredient) {} + + @SuppressWarnings("removal") + @Override + public List getTooltip(T ingredient, TooltipFlag tooltipFlag) { + return Collections.emptyList(); + } + + @Override + public int getWidth() { + return widgetArea.width; + } + + @Override + public int getHeight() { + return widgetArea.height; + } + }); + // set slot name + slotBuilder.setSlotName("slot_" + index); + } + @Override - @NotNull - public RecipeType getRecipeType() { - return TYPES.apply(category); + public void setRecipe(IRecipeLayoutBuilder builder, T recipe, IFocusGroup focuses) { + ModularScreen screen = getModularScreen(recipe); + + MutableInt i = new MutableInt(0); + WidgetTree.foreachChildBFS(screen.getMainPanel(), widget -> { + if (!(widget instanceof IngredientProvider provider)) { + return true; + } + RecipeIngredientRole role = mapToRole(provider.recipeRole()); + addJEISlot(builder, provider, role, i.getAndIncrement()); + return true; + }, true); } @Override - @NotNull - public Component getTitle() { - return Component.translatable(category.getLanguageKey()); + public void createRecipeExtras(IRecipeExtrasBuilder builder, T recipe, IFocusGroup focuses) { + builder.addGuiEventListener(new ModularUIGuiEventListener(recipe)); + builder.addWidget(new UIForegroundRenderWidget(recipe)); } @Override - public @Nullable ResourceLocation getRegistryName(@NotNull GTRecipe recipe) { - return recipe.id; + public void draw(T recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics guiGraphics, double mouseX, + double mouseY) { + ModularScreen screen = getModularScreen(recipe); + + RecipeScreenRenderingUtil.drawScreenBackground(guiGraphics, screen, (int) mouseX, (int) mouseY, + Minecraft.getInstance().getPartialTick()); + } + + @Override + public void getTooltip(ITooltipBuilder tooltip, T recipe, IRecipeSlotsView recipeSlotsView, double mouseX, + double mouseY) { + // tooltip.clear(); + } + + public static RecipeIngredientRole mapToRole(RecipeSlotRole slotRole) { + return switch (slotRole) { + case INPUT -> RecipeIngredientRole.INPUT; + case OUTPUT -> RecipeIngredientRole.OUTPUT; + case CATALYST -> RecipeIngredientRole.CATALYST; + case RENDER_ONLY -> RecipeIngredientRole.RENDER_ONLY; + }; } + + public class ModularUIGuiEventListener implements IJeiGuiEventListener { + + private final T recipe; + + public ModularUIGuiEventListener(T recipe) { + this.recipe = recipe; + } + + public ScreenRectangle getArea() { + return getModularScreen(this.recipe).getRectangle(); + } + + @Override + public void mouseMoved(double mouseX, double mouseY) { + getModularScreen(this.recipe).mouseMoved(mouseX, mouseY); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return getModularScreen(this.recipe).mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return getModularScreen(this.recipe).mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { + return getModularScreen(this.recipe).mouseDragged(mouseX, mouseY, button, dragX, dragY); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double scrollDelta) { + return getModularScreen(this.recipe).mouseScrolled(mouseX, mouseY, scrollDelta); + } + + @Override + public boolean keyPressed(double mouseX, double mouseY, int keyCode, int scanCode, int modifiers) { + return getModularScreen(this.recipe).keyPressed(keyCode, scanCode, modifiers); + } + } + + public class UIForegroundRenderWidget implements IRecipeWidget { + + private final T recipe; + + public UIForegroundRenderWidget(T recipe) { + this.recipe = recipe; + } + + @Override + public ScreenPosition getPosition() { + return new ScreenPosition(0, 0); + } + + @Override + public void drawWidget(GuiGraphics guiGraphics, double mouseX, double mouseY) { + ModularScreen screen = getModularScreen(this.recipe); + RecipeScreenRenderingUtil.drawScreenForeground(guiGraphics, screen, (int) mouseX, (int) mouseY, + Minecraft.getInstance().getPartialTick()); + } + } + + /* + * @Override + * + * @NotNull + * public RecipeType getRecipeType() { + * return TYPES.apply(category); + * } + * + * @Override + * + * @NotNull + * public Component getTitle() { + * return Component.translatable(category.getLanguageKey()); + * } + * + * @Override + * public @Nullable ResourceLocation getRegistryName(@NotNull GTRecipe recipe) { + * return recipe.id; + * } + */ } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeWrapper.java b/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeWrapper.java index 602b9586ac8..cce39320743 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeWrapper.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jei/recipe/GTRecipeWrapper.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.jei.recipe; import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.integration.xei.widgets.GTRecipeWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTRecipeWidget; import com.lowdragmc.lowdraglib.gui.widget.Widget; import com.lowdragmc.lowdraglib.jei.ModularWrapper; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/map/layer/builtin/OreRenderLayer.java b/src/main/java/com/gregtechceu/gtceu/integration/map/layer/builtin/OreRenderLayer.java index 31237f97976..dea2be0b90e 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/map/layer/builtin/OreRenderLayer.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/map/layer/builtin/OreRenderLayer.java @@ -9,7 +9,7 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.integration.map.GenericMapRenderer; import com.gregtechceu.gtceu.integration.map.layer.MapRenderLayer; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeSlotRole.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeSlotRole.java new file mode 100644 index 00000000000..936798237b5 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeSlotRole.java @@ -0,0 +1,26 @@ +package com.gregtechceu.gtceu.integration.recipeviewer; + +/** + * The relationship between an ingredient and a recipe. + */ +public enum RecipeSlotRole { + /** + * Input ingredients are consumed when a recipe is crafted. + */ + INPUT, + /** + * Output ingredients are the result of a crafted recipe. + */ + OUTPUT, + /** + * Catalysts are ingredients that are necessary for crafting, but are not consumed. + * These are treated similarly to {@link #INPUT}. + * Examples may be a crafting table, a furnace, or an ingredient that sits in the crafting grid but is not used up. + */ + CATALYST, + /** + * Render-only ingredients should be drawn, and can be navigated on, + * but are ignored when looking up the recipe. + */ + RENDER_ONLY +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeViewerScreenWrapper.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeViewerScreenWrapper.java new file mode 100644 index 00000000000..94061b7eec6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeViewerScreenWrapper.java @@ -0,0 +1,28 @@ +package com.gregtechceu.gtceu.integration.recipeviewer; + +import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; +import com.gregtechceu.gtceu.api.mui.utils.Rectangle; +import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; + +import org.jetbrains.annotations.NotNull; + +public record RecipeViewerScreenWrapper(ModularScreen screen) implements IMuiScreen { + + @Override + public Screen getWrappedScreen() { + return Minecraft.getInstance().screen; + } + + @Override + public @NotNull ModularScreen getScreen() { + return screen; + } + + @Override + public void updateGuiArea(Rectangle area) { + // overlay should not modify screen + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/XeiState.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeViewerState.java similarity index 80% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/XeiState.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeViewerState.java index 751dd1ad884..37ef796b5f8 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/XeiState.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/RecipeViewerState.java @@ -1,10 +1,10 @@ -package com.gregtechceu.gtceu.integration.xei; +package com.gregtechceu.gtceu.integration.recipeviewer; import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; import java.util.function.Predicate; -public enum XeiState implements Predicate { +public enum RecipeViewerState implements Predicate { ENABLED { diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/EntryList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/EntryList.java similarity index 63% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/EntryList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/EntryList.java index 6c069d54849..449b161a476 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/EntryList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/EntryList.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.entry; +package com.gregtechceu.gtceu.integration.recipeviewer.entry; import java.util.List; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidEntryList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidEntryList.java similarity index 68% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidEntryList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidEntryList.java index 1e6a139e124..c12930cba2d 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidEntryList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidEntryList.java @@ -1,6 +1,6 @@ -package com.gregtechceu.gtceu.integration.xei.entry.fluid; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid; -import com.gregtechceu.gtceu.integration.xei.entry.EntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.EntryList; import net.minecraftforge.fluids.FluidStack; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidHolderSetList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidHolderSetList.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidHolderSetList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidHolderSetList.java index e220c96009b..4cf0200be90 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidHolderSetList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidHolderSetList.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.entry.fluid; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid; import net.minecraft.core.HolderSet; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidStackList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidStackList.java similarity index 94% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidStackList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidStackList.java index c24e5ecb76d..196f26261b1 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidStackList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidStackList.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.entry.fluid; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid; import net.minecraftforge.fluids.FluidStack; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidTagList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidTagList.java similarity index 96% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidTagList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidTagList.java index 032eead252b..615d6c19510 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/fluid/FluidTagList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/fluid/FluidTagList.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.entry.fluid; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid; import net.minecraft.core.HolderSet; import net.minecraft.core.registries.BuiltInRegistries; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemEntryList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemEntryList.java similarity index 67% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemEntryList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemEntryList.java index ec711b7c00a..8fba73c48b8 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemEntryList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemEntryList.java @@ -1,6 +1,6 @@ -package com.gregtechceu.gtceu.integration.xei.entry.item; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.item; -import com.gregtechceu.gtceu.integration.xei.entry.EntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.EntryList; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemHolderSetList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemHolderSetList.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemHolderSetList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemHolderSetList.java index 7ceeeb8798f..c0bf2a3a672 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemHolderSetList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemHolderSetList.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.entry.item; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.item; import net.minecraft.core.HolderSet; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemStackList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemStackList.java similarity index 94% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemStackList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemStackList.java index f6d336f9798..19946e51e35 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemStackList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemStackList.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.entry.item; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.item; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemTagList.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemTagList.java similarity index 96% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemTagList.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemTagList.java index d8a4e3a7fd8..f269f42d817 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/entry/item/ItemTagList.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/entry/item/ItemTagList.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.entry.item; +package com.gregtechceu.gtceu.integration.recipeviewer.entry.item; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/GhostIngredientSlot.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/GhostIngredientSlot.java similarity index 86% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/GhostIngredientSlot.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/GhostIngredientSlot.java index 8a59bdb7d72..6299cf1c3e7 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/GhostIngredientSlot.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/GhostIngredientSlot.java @@ -1,7 +1,6 @@ -package com.gregtechceu.gtceu.integration.xei.handlers; +package com.gregtechceu.gtceu.integration.recipeviewer.handlers; -import com.gregtechceu.gtceu.api.mui.base.XeiSettings; -import com.gregtechceu.gtceu.api.mui.base.widget.IGuiElement; +import com.gregtechceu.gtceu.api.mui.base.RecipeViewerSettings; import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.drawable.GuiDraw; import com.gregtechceu.gtceu.api.mui.utils.Color; @@ -16,11 +15,11 @@ * An interface for compat with recipe viewers' ghost slots. * Implement this on any {@link IWidget}. * This slot must then be manually registered in something like {@link Widget#onInit()} - * with {@link XeiSettings#addGhostIngredientSlot(IWidget)} + * with {@link RecipeViewerSettings#addGhostIngredientSlot(IWidget)} * * @param type of the ingredient */ -public interface GhostIngredientSlot extends IGuiElement { +public interface GhostIngredientSlot extends IWidget { /** * Puts the ingredient in this ghost slot. diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/IngredientProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/IngredientProvider.java similarity index 69% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/IngredientProvider.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/IngredientProvider.java index ad31a1afb4e..65fa348e505 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/IngredientProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/IngredientProvider.java @@ -1,7 +1,8 @@ -package com.gregtechceu.gtceu.integration.xei.handlers; +package com.gregtechceu.gtceu.integration.recipeviewer.handlers; -import com.gregtechceu.gtceu.api.capability.recipe.IO; -import com.gregtechceu.gtceu.integration.xei.entry.EntryList; +import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.RecipeSlotRole; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.EntryList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,7 +16,7 @@ * * @param type of the ingredient */ -public interface IngredientProvider { +public interface IngredientProvider extends IWidget { EntryList getIngredients(); @@ -27,10 +28,6 @@ default float chance() { return 1.0f; } - default IO ingredientIO() { - return null; - } - /** * @return the class of the ingredient this slot contains */ @@ -44,4 +41,9 @@ default IO ingredientIO() { default Object ingredientOverride() { return null; } + + @NotNull + default RecipeSlotRole recipeRole() { + return RecipeSlotRole.RENDER_ONLY; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferError.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferError.java new file mode 100644 index 00000000000..50f045bfbb2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferError.java @@ -0,0 +1,119 @@ +package com.gregtechceu.gtceu.integration.recipeviewer.handlers; + +import net.minecraft.network.chat.Component; + +import lombok.Getter; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper; + +import java.util.List; + +/** + * A reason that a recipe transfer couldn't happen. + *

+ * Recipe transfer errors can be created with {@link IRecipeTransferHandlerHelper} or you can implement your own. + * These errors are returned from {@link RecipeTransferHandler#transferRecipe(Object, boolean, boolean)}. + *

+ */ +public abstract sealed class RecipeTransferError permits RecipeTransferError.Internal, RecipeTransferError.UserFacing, + RecipeTransferError.Cosmetic { + + public abstract boolean allowsTransfer(); + + /** + * Return the ARGB color of the additional button highlight for {@link Cosmetic}. + * For example, return 0 to disable the colored highlight. Default color is orange. + */ + public int getButtonHighlightColor() { + return 0x80FFA500; + } + + /** + * Called on {@link UserFacing} and {@link Cosmetic} errors. + */ + public List getTooltip() { + return List.of(); + } + + /** + * Get the estimated number of inputs of the recipe that cannot be found in the container. + * + * This is used to help sort recipes with more matches first, so that if a player + * has many (or all) of the items required for a recipe in their inventory, it is shown first. + * + * @return the number of input recipes slots are missing ingredient's in the player's inventory. + * Return -1 by default to avoid sorting + * + * @since 19.2.0 + */ + public int getMissingCountHint() { + return -1; + } + + /** + * Errors where the Transfer handler is broken or does not work. + * These errors will hide the recipe transfer button, and do not display anything to the user. + */ + public static final class Internal extends RecipeTransferError { + + public static final Internal INSTANCE = new Internal(); + + private Internal() {} + + @Override + public boolean allowsTransfer() { + return false; + } + } + + /** + * Errors that the player can fix. Missing items, inventory full, etc. + * Something informative will be shown to the player. + */ + public static non-sealed class UserFacing extends RecipeTransferError { + + public UserFacing() {} + + @Override + public boolean allowsTransfer() { + return false; + } + + /** + * An error that shows a tooltip. + */ + public static class Tooltip extends UserFacing { + + @Getter + private final List message; + + public Tooltip(Component message) { + this(List.of(message)); + } + + public Tooltip(List message) { + this.message = message; + } + + @Override + public List getTooltip() { + return message; + } + } + } + + /** + * Errors that still allow the usage of the recipe transfer button. + * Hovering over the button will display the error, however the button is active and can be used. + * + * @since 6.0.2 + */ + public static non-sealed class Cosmetic extends RecipeTransferError { + + public Cosmetic() {} + + @Override + public boolean allowsTransfer() { + return true; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferHandler.java new file mode 100644 index 00000000000..528aec852e4 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeTransferHandler.java @@ -0,0 +1,31 @@ +package com.gregtechceu.gtceu.integration.recipeviewer.handlers; + +import org.jetbrains.annotations.ApiStatus; + +/** + * An interface to handle recipe transfers. + * Implement this on {@link com.gregtechceu.gtceu.client.mui.screen.ModularScreen}. + * No further registration needed. + */ +@ApiStatus.Experimental +public interface RecipeTransferHandler { + + @SuppressWarnings("unchecked") + @ApiStatus.NonExtendable + @ApiStatus.Internal + default RecipeTransferError transferRecipeSafe(Object recipe, boolean maxTransfer, boolean simulate) { + return this.transferRecipe((T) recipe, maxTransfer, simulate); + } + + /** + * Transfers a recipe viewer recipe. + * + * @param recipe the recipe + * @param maxTransfer true if shift is being held + * @param simulate if the transfer is simulated + * @return a transfer error or null if successful + */ + RecipeTransferError transferRecipe(T recipe, boolean maxTransfer, boolean simulate); + + Class getRecipeClass(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/RecipeViewerHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeViewerHandler.java similarity index 92% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/RecipeViewerHandler.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeViewerHandler.java index 859f6aadd6d..fa0e7a51e93 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/RecipeViewerHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/RecipeViewerHandler.java @@ -1,10 +1,10 @@ -package com.gregtechceu.gtceu.integration.xei.handlers; +package com.gregtechceu.gtceu.integration.recipeviewer.handlers; import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.client.mui.screen.ScreenWrapper; import com.gregtechceu.gtceu.integration.emi.handler.EmiScreenHandler; -import com.gregtechceu.gtceu.integration.jei.handler.JEIScreenHandler; +import com.gregtechceu.gtceu.integration.jei.handler.JeiScreenHandler; import com.gregtechceu.gtceu.integration.rei.handler.REIScreenHandler; import org.jetbrains.annotations.NotNull; @@ -26,7 +26,7 @@ public static RecipeViewerHandler getCurrent() { } else if (GTCEu.isModLoaded(GTValues.MODID_REI)) { supplier = () -> REIScreenHandler::of; } else if (GTCEu.isModLoaded(GTValues.MODID_JEI)) { - supplier = () -> JEIScreenHandler::of; + supplier = () -> JeiScreenHandler::of; } else { supplier = () -> cls -> DUMMY; } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/fluid/CycleFluidEntryHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/fluid/CycleFluidEntryHandler.java similarity index 69% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/fluid/CycleFluidEntryHandler.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/fluid/CycleFluidEntryHandler.java index 5da77a94151..96444cd34d1 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/fluid/CycleFluidEntryHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/fluid/CycleFluidEntryHandler.java @@ -1,19 +1,19 @@ -package com.gregtechceu.gtceu.integration.xei.handlers.fluid; +package com.gregtechceu.gtceu.integration.recipeviewer.handlers.fluid; -import com.gregtechceu.gtceu.api.transfer.fluid.IFluidHandlerModifiable; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidEntryList; import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; import lombok.Getter; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -public class CycleFluidEntryHandler implements IFluidHandlerModifiable { +public class CycleFluidEntryHandler implements IFluidHandler { @Getter private final List entries; @@ -33,7 +33,7 @@ public List> getUnwrapped() { return unwrapped; } - private static List getStacksNullable(FluidEntryList list) { + private static @Nullable List getStacksNullable(FluidEntryList list) { if (list == null) return null; return list.getStacks(); } @@ -55,13 +55,15 @@ public FluidStack getFluidInTank(int tank) { stackList.get(Math.abs((int) (System.currentTimeMillis() / 1000) % stackList.size())); } - @Override - public void setFluidInTank(int tank, @NotNull FluidStack fluidStack) { - if (tank >= 0 && tank < entries.size()) { - entries.set(tank, FluidStackList.of(fluidStack)); - unwrapped = null; - } - } + /* + * @Override + * public void setFluidInTank(int tank, @NotNull FluidStack fluidStack) { + * if (tank >= 0 && tank < entries.size()) { + * entries.set(tank, FluidStackList.of(fluidStack)); + * unwrapped = null; + * } + * } + */ @Override public int getTankCapacity(int tank) { @@ -78,10 +80,10 @@ public int fill(FluidStack resource, FluidAction action) { return 0; } - @Override - public boolean supportsFill(int tank) { - return false; - } + // @Override + // public boolean supportsFill(int tank) { + // return false; + // } @NotNull @Override @@ -94,8 +96,8 @@ public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; } - @Override - public boolean supportsDrain(int tank) { - return false; - } + // @Override + // public boolean supportsDrain(int tank) { + // return false; + // } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/fluid/EmptyFluidTank.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/fluid/EmptyFluidTank.java new file mode 100644 index 00000000000..d57216d41ea --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/fluid/EmptyFluidTank.java @@ -0,0 +1,49 @@ +package com.gregtechceu.gtceu.integration.recipeviewer.handlers.fluid; + +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; +import net.minecraftforge.fluids.capability.IFluidHandler; + +import org.jetbrains.annotations.NotNull; + +public class EmptyFluidTank implements IFluidTank { + + public static final EmptyFluidTank INSTANCE = new EmptyFluidTank(); + + protected EmptyFluidTank() {} + + @Override + public @NotNull FluidStack getFluid() { + return FluidStack.EMPTY; + } + + @Override + public int getFluidAmount() { + return 0; + } + + @Override + public int getCapacity() { + return 0; + } + + @Override + public boolean isFluidValid(@NotNull FluidStack stack) { + return false; + } + + @Override + public int fill(@NotNull FluidStack resource, @NotNull IFluidHandler.FluidAction action) { + return 0; + } + + @Override + public @NotNull FluidStack drain(int maxDrain, IFluidHandler.FluidAction action) { + return FluidStack.EMPTY; + } + + @Override + public @NotNull FluidStack drain(FluidStack resource, IFluidHandler.FluidAction action) { + return FluidStack.EMPTY; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/item/CycleItemEntryHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/item/CycleItemEntryHandler.java similarity index 91% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/item/CycleItemEntryHandler.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/item/CycleItemEntryHandler.java index c2229967630..469c560a2a6 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/handlers/item/CycleItemEntryHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/handlers/item/CycleItemEntryHandler.java @@ -1,7 +1,7 @@ -package com.gregtechceu.gtceu.integration.xei.handlers.item; +package com.gregtechceu.gtceu.integration.recipeviewer.handlers.item; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; import net.minecraft.world.item.ItemStack; import net.minecraftforge.items.IItemHandlerModifiable; @@ -92,6 +92,6 @@ public int getSlotLimit(int slot) { @Override public boolean isItemValid(int slot, @NotNull ItemStack stack) { - return false; + return true; } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/util/RecipeScreenRenderingUtil.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/util/RecipeScreenRenderingUtil.java new file mode 100644 index 00000000000..ee6582f2641 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/util/RecipeScreenRenderingUtil.java @@ -0,0 +1,67 @@ +package com.gregtechceu.gtceu.integration.recipeviewer.util; + +import com.gregtechceu.gtceu.api.mui.utils.Stencil; +import com.gregtechceu.gtceu.client.mui.screen.ClientScreenHandler; +import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.wrapper.EmptyHandler; + +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.systems.RenderSystem; +import org.jetbrains.annotations.ApiStatus; + +public class RecipeScreenRenderingUtil { + + public static final IItemHandlerModifiable EMPTY_ITEM_HANDLER = new EmptyHandler(); + + @ApiStatus.Internal + public static void drawScreenBackground(GuiGraphics guiGraphics, ModularScreen screen, + int mouseX, int mouseY, float partialTick) { + screen.getContext().setGraphics(guiGraphics); + screen.getContext().updateState(mouseX, mouseY, partialTick); + screen.getContext().graphicsPose().pushPose(); + + // copied from ClientScreenHandler#drawScreenInternal to + // let us draw foreground elements separately after everything else. + Stencil.reset(); + screen.getContext().getStencil().push(screen.getScreenArea()); + + screen.render(guiGraphics, mouseX, mouseY, partialTick); + + RenderSystem.disableDepthTest(); + + ClientScreenHandler.drawVanillaElements(guiGraphics, screen.getScreenWrapper().getWrappedScreen(), + mouseX, mouseY, partialTick); + + RenderSystem.enableDepthTest(); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + + screen.getContext().getStencil().pop(); + screen.getContext().graphicsPose().popPose(); + } + + @ApiStatus.Internal + public static void drawScreenForeground(GuiGraphics guiGraphics, ModularScreen screen, + int mouseX, int mouseY, float partialTick) { + screen.getContext().setGraphics(guiGraphics); + screen.getContext().updateState(mouseX, mouseY, partialTick); + screen.getContext().graphicsPose().pushPose(); + + // copied from ClientScreenHandler#drawScreenInternal to + // let us draw foreground elements separately after everything else. + screen.getContext().getStencil().push(screen.getScreenArea()); + RenderSystem.disableDepthTest(); + Lighting.setupForFlatItems(); + + screen.drawForeground(guiGraphics, partialTick); + + RenderSystem.enableDepthTest(); + Lighting.setupFor3DItems(); + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + + screen.getContext().getStencil().pop(); + screen.getContext().graphicsPose().popPose(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTMuiRecipeWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTMuiRecipeWidget.java new file mode 100644 index 00000000000..f39359efe27 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTMuiRecipeWidget.java @@ -0,0 +1,15 @@ +package com.gregtechceu.gtceu.integration.recipeviewer.widgets; + +import com.gregtechceu.gtceu.api.mui.widget.ParentWidget; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; + +public class GTMuiRecipeWidget extends ParentWidget { + + private final GTRecipe recipe; + + public GTMuiRecipeWidget(GTRecipe recipe) { + this.recipe = recipe; + } + + private void initializeWidgets() {} +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreByProduct.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreByProduct.java similarity index 96% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreByProduct.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreByProduct.java index 6e1f89112d0..386f21d108b 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreByProduct.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreByProduct.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.widgets; +package com.gregtechceu.gtceu.integration.recipeviewer.widgets; import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; @@ -11,12 +11,12 @@ import com.gregtechceu.gtceu.api.recipe.content.Content; import com.gregtechceu.gtceu.common.data.GTMachines; import com.gregtechceu.gtceu.common.data.GTMaterials; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidStackList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidTagList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemTagList; import com.gregtechceu.gtceu.utils.FormattingUtil; import net.minecraft.core.NonNullList; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreByProductWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreByProductWidget.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreByProductWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreByProductWidget.java index 750baa14cc2..fd4da1417a5 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreByProductWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreByProductWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.widgets; +package com.gregtechceu.gtceu.integration.recipeviewer.widgets; import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.gui.GuiTextures; @@ -7,10 +7,10 @@ import com.gregtechceu.gtceu.api.recipe.content.Content; import com.gregtechceu.gtceu.api.transfer.fluid.CustomFluidTank; import com.gregtechceu.gtceu.api.transfer.item.CustomItemStackHandler; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidEntryList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemEntryList; -import com.gregtechceu.gtceu.integration.xei.handlers.fluid.CycleFluidEntryHandler; -import com.gregtechceu.gtceu.integration.xei.handlers.item.CycleItemEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemEntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.fluid.CycleFluidEntryHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.item.CycleItemEntryHandler; import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; import com.lowdragmc.lowdraglib.gui.widget.ImageWidget; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreVeinWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreVeinWidget.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreVeinWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreVeinWidget.java index c1dfe009a6c..ae7fcf3d6d7 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTOreVeinWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTOreVeinWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.widgets; +package com.gregtechceu.gtceu.integration.recipeviewer.widgets; import com.gregtechceu.gtceu.api.data.DimensionMarker; import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTProgrammedCircuitWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTProgrammedCircuitWidget.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTProgrammedCircuitWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTProgrammedCircuitWidget.java index 3846d3c0635..3cbf8cf30fc 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTProgrammedCircuitWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTProgrammedCircuitWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.widgets; +package com.gregtechceu.gtceu.integration.recipeviewer.widgets; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.widget.SlotWidget; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTRecipeWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTRecipeWidget.java similarity index 99% rename from src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTRecipeWidget.java rename to src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTRecipeWidget.java index f08ffa59d66..36b8f1c5a0d 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/xei/widgets/GTRecipeWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/GTRecipeWidget.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.integration.xei.widgets; +package com.gregtechceu.gtceu.integration.recipeviewer.widgets; import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.GTValues; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/circuit/GTProgrammedCircuitCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/circuit/GTProgrammedCircuitCategory.java index 871f56969f7..b28c65433a8 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/circuit/GTProgrammedCircuitCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/circuit/GTProgrammedCircuitCategory.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.common.data.GTItems; -import com.gregtechceu.gtceu.integration.xei.widgets.GTProgrammedCircuitWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTProgrammedCircuitWidget; import com.lowdragmc.lowdraglib.gui.texture.ItemStackTexture; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIScreenHandler.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIScreenHandler.java index e3cfc62a73d..43b05694c52 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIScreenHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIScreenHandler.java @@ -1,11 +1,11 @@ package com.gregtechceu.gtceu.integration.rei.handler; import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; -import com.gregtechceu.gtceu.api.mui.base.widget.IGuiElement; +import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; import com.gregtechceu.gtceu.api.mui.utils.Rectangle; -import com.gregtechceu.gtceu.integration.xei.handlers.GhostIngredientSlot; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; -import com.gregtechceu.gtceu.integration.xei.handlers.RecipeViewerHandler; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.GhostIngredientSlot; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.RecipeViewerHandler; import net.minecraft.client.gui.screens.Screen; @@ -47,7 +47,7 @@ public Stream getDraggableAcceptingBounds(DraggingContext con DraggableStack stack) { currentIngredient = stack; return context.getScreen().getScreen().getContext() - .getXeiSettings().getGhostIngredientSlots().stream() + .getRecipeViewerSettings().getGhostIngredientSlots().stream() .map(target -> BoundsProvider.ofRectangle(asREIRect(target.getArea()))); } @@ -55,7 +55,7 @@ public Stream getDraggableAcceptingBounds(DraggingContext con public DraggedAcceptorResult acceptDraggedStack(DraggingContext context, DraggableStack stack) { List> ghostSlots = context.getScreen().getScreen().getContext() - .getXeiSettings().getGhostIngredientSlots(); + .getRecipeViewerSettings().getGhostIngredientSlots(); for (var slot : ghostSlots) { if (!slot.isEnabled()) { continue; @@ -87,7 +87,7 @@ private REIScreenHandler() {} @Override public @Nullable DraggableStack getHoveredStack(DraggingContext context, double mouseX, double mouseY) { - IGuiElement hovered = context.getScreen().getScreen().getContext().getTopHovered(); + IWidget hovered = context.getScreen().getScreen().getContext().getTopHovered(); if (hovered instanceof IngredientProvider provider) { var override = provider.ingredientOverride(); if (override != null) { @@ -141,7 +141,7 @@ public double getPriority() { @Override public Collection provide(T screen) { return screen.getScreen().getContext() - .getXeiSettings().getAllExclusionAreas().stream() + .getRecipeViewerSettings().getAllExclusionAreas().stream() .map(REIScreenHandler::asREIRect) .toList(); } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIStackConverter.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIStackConverter.java index 907cdfa4602..9eeac1add41 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIStackConverter.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/handler/REIStackConverter.java @@ -1,11 +1,11 @@ package com.gregtechceu.gtceu.integration.rei.handler; -import com.gregtechceu.gtceu.integration.xei.entry.EntryList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidStackList; -import com.gregtechceu.gtceu.integration.xei.entry.fluid.FluidTagList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemStackList; -import com.gregtechceu.gtceu.integration.xei.entry.item.ItemTagList; -import com.gregtechceu.gtceu.integration.xei.handlers.IngredientProvider; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.EntryList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.fluid.FluidTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemStackList; +import com.gregtechceu.gtceu.integration.recipeviewer.entry.item.ItemTagList; +import com.gregtechceu.gtceu.integration.recipeviewer.handlers.IngredientProvider; import com.gregtechceu.gtceu.utils.GTMath; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/oreprocessing/GTOreProcessingDisplay.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/oreprocessing/GTOreProcessingDisplay.java index 0e47c68a237..a0b17b42ab2 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/oreprocessing/GTOreProcessingDisplay.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/oreprocessing/GTOreProcessingDisplay.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.rei.oreprocessing; import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreByProductWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreByProductWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; import com.lowdragmc.lowdraglib.rei.ModularDisplay; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplay.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplay.java index 8dbef3a050f..c7ca98bdeb7 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplay.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplay.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.rei.orevein; import com.gregtechceu.gtceu.api.data.worldgen.bedrockfluid.BedrockFluidDefinition; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; import com.lowdragmc.lowdraglib.rei.ModularDisplay; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplayCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplayCategory.java index 69dd53d0809..1d32a4b855a 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplayCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockFluidDisplayCategory.java @@ -5,7 +5,7 @@ import com.gregtechceu.gtceu.client.ClientProxy; import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.common.data.GTMaterials; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.gui.texture.ItemStackTexture; import com.lowdragmc.lowdraglib.rei.IGui2Renderer; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplay.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplay.java index 22e570e2523..43d10393d5f 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplay.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplay.java @@ -4,7 +4,7 @@ import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; import com.lowdragmc.lowdraglib.rei.ModularDisplay; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplayCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplayCategory.java index 273de569831..07db738a459 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplayCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTBedrockOreDisplayCategory.java @@ -5,7 +5,7 @@ import com.gregtechceu.gtceu.client.ClientProxy; import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.common.data.GTMaterials; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.gui.texture.ItemStackTexture; import com.lowdragmc.lowdraglib.rei.IGui2Renderer; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplay.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplay.java index 730ec06f0ad..ffd68cfb57e 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplay.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplay.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.rei.orevein; import com.gregtechceu.gtceu.api.data.worldgen.GTOreDefinition; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; import com.lowdragmc.lowdraglib.rei.ModularDisplay; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplayCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplayCategory.java index 0a9d538f50d..0935a15e5d6 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplayCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/orevein/GTOreVeinDisplayCategory.java @@ -4,7 +4,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.GTOreDefinition; import com.gregtechceu.gtceu.client.ClientProxy; import com.gregtechceu.gtceu.common.data.GTItems; -import com.gregtechceu.gtceu.integration.xei.widgets.GTOreVeinWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreVeinWidget; import com.lowdragmc.lowdraglib.gui.texture.ItemStackTexture; import com.lowdragmc.lowdraglib.rei.IGui2Renderer; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/rei/recipe/GTRecipeDisplay.java b/src/main/java/com/gregtechceu/gtceu/integration/rei/recipe/GTRecipeDisplay.java index d017e7aec76..9e84d189fea 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/rei/recipe/GTRecipeDisplay.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/rei/recipe/GTRecipeDisplay.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.integration.rei.recipe; import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.integration.xei.widgets.GTRecipeWidget; +import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTRecipeWidget; import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; import com.lowdragmc.lowdraglib.rei.ModularDisplay; diff --git a/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java b/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java index 493f7798fb9..eef8d94e753 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java @@ -7,7 +7,6 @@ import net.minecraft.network.chat.MutableComponent; import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -102,15 +101,6 @@ public static String toLowerCaseUnderscore(String string) { return result.toString(); } - /** - * @deprecated use {@link FormattingUtil#toLowerCaseUnderscore(String) toLowerCaseUnderscore} instead. - */ - @ApiStatus.Obsolete(since = "7.0.0") - @Deprecated(since = "7.0.0") - public static String toLowerCaseUnder(String string) { - return toLowerCaseUnderscore(string); - } - /** * Check if {@code string} has any uppercase characters. * diff --git a/src/main/java/com/gregtechceu/gtceu/utils/GTMath.java b/src/main/java/com/gregtechceu/gtceu/utils/GTMath.java index f1d000d61a1..7462aac69f7 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/GTMath.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/GTMath.java @@ -1,6 +1,8 @@ package com.gregtechceu.gtceu.utils; import com.gregtechceu.gtceu.utils.math.ParseResult; +import com.gregtechceu.gtceu.utils.math.PostfixPercentOperator; +import com.gregtechceu.gtceu.utils.math.SIPrefix; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.Direction; @@ -8,6 +10,10 @@ import net.minecraft.world.item.ItemStack; import net.minecraftforge.fluids.FluidStack; +import com.ezylang.evalex.BaseException; +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.config.ExpressionConfiguration; +import com.ezylang.evalex.data.EvaluationValue; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -16,8 +22,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.joml.Vector3fc; -import org.mariuszgromada.math.mxparser.Constant; -import org.mariuszgromada.math.mxparser.Expression; import java.math.BigDecimal; import java.math.BigInteger; @@ -32,25 +36,45 @@ @ParametersAreNonnullByDefault public class GTMath { - // SI prefixes - public static final Constant k = new Constant("k", 1e3); - public static final Constant M = new Constant("M", 1e6); - public static final Constant G = new Constant("G", 1e9); - public static final Constant T = new Constant("T", 1e12); - public static final Constant P = new Constant("P", 1e15); - public static final Constant E = new Constant("E", 1e18); - public static final Constant Z = new Constant("Z", 1e21); - public static final Constant Y = new Constant("Y", 1e24); - public static final Constant m = new Constant("m", 1e-3); - public static final Constant u = new Constant("u", 1e-6); - public static final Constant n = new Constant("n", 1e-9); - public static final Constant p = new Constant("p", 1e-12); - public static final Constant f = new Constant("f", 1e-15); - public static final Constant a = new Constant("a", 1e-18); - public static final Constant z = new Constant("z", 1e-21); - public static final Constant y = new Constant("y", 1e-24); - - public static final float QUART_PI = Mth.PI / 4f; + public static final float PI = (float) Math.PI; + public static final float PI2 = 2f * PI; + public static final float PI_HALF = PI / 2f; + public static final float PI_QUART = PI / 4f; + + public static final ExpressionConfiguration MATH_CFG = ExpressionConfiguration.builder() + .arraysAllowed(false) + .structuresAllowed(false) + .stripTrailingZeros(true) + .build() + .withAdditionalOperators(Pair.of("%", new PostfixPercentOperator())); + + public static ParseResult parseExpression(String expression) { + return parseExpression(expression, Double.NaN, false); + } + + public static ParseResult parseExpression(String expression, boolean useSiPrefixes) { + return parseExpression(expression, Double.NaN, useSiPrefixes); + } + + public static ParseResult parseExpression(String expression, double defaultValue) { + return parseExpression(expression, defaultValue, true); + } + + public static ParseResult parseExpression(String expression, double defaultValue, boolean useSiPrefixes) { + if (expression == null || expression.isEmpty()) { + return ParseResult.success(EvaluationValue.numberValue(new BigDecimal(defaultValue))); + } + + Expression e = new Expression(expression, MATH_CFG); + if (useSiPrefixes) { + SIPrefix.addAllToExpression(e); + } + try { + return ParseResult.success(e.evaluate()); + } catch (BaseException exception) { + return ParseResult.failure(exception); + } + } public static final Vector3fc UNIT_X = new Vector3f(1f, 0f, 0f); public static final Vector3fc UNIT_Y = new Vector3f(0f, 1f, 0f); @@ -125,31 +149,6 @@ public static int ceilDiv(int x, int y) { return q; } - public static ParseResult parseExpression(@Nullable String expression) { - return parseExpression(expression, Double.NaN, false); - } - - public static ParseResult parseExpression(@Nullable String expression, boolean useSiPrefixes) { - return parseExpression(expression, Double.NaN, useSiPrefixes); - } - - public static ParseResult parseExpression(@Nullable String expression, double defaultValue) { - return parseExpression(expression, defaultValue, true); - } - - public static ParseResult parseExpression(@Nullable String expression, double defaultValue, boolean useSiPrefixes) { - if (expression == null || expression.isEmpty()) return ParseResult.success(defaultValue); - Expression e = new Expression(expression); - if (useSiPrefixes) { - e.addConstants(k, M, G, T, P, E, Z, Y, m, u, n, p, f, a, z, y); - } - double result = e.calculate(); - if (Double.isNaN(result)) { - return ParseResult.failure(defaultValue, e.getErrorMessage()); - } - return ParseResult.success(result); - } - public static long clamp(long v, long min, long max) { return Math.max(min, Math.min(max, v)); } @@ -288,4 +287,17 @@ public static float rescaleLinear(float v, float fromMin, float fromMax, float t v = (v - fromMin) / (fromMax - fromMin); // reverse lerp return toMin + (toMax - toMin) * v; // forward lerp } + + public static int intPlaces(BigDecimal x) { + return Math.max(1, x.precision() - x.scale()); + } + + public static int intPlaces(double x) { + if (x == 0.0) return 1; + x = Math.abs(x); + int d = (int) Math.floor(Math.log10(x)) + 1; + // correct rounding errors + if (Math.pow(10, d - 1) > x) d--; + return Math.max(d, 1); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/IMultiFluidTankHandler.java b/src/main/java/com/gregtechceu/gtceu/utils/IMultiFluidTankHandler.java new file mode 100644 index 00000000000..eff979b6edb --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/IMultiFluidTankHandler.java @@ -0,0 +1,9 @@ +package com.gregtechceu.gtceu.utils; + +import net.minecraftforge.fluids.IFluidTank; +import net.minecraftforge.fluids.capability.IFluidHandler; + +public interface IMultiFluidTankHandler extends IFluidHandler { + + IFluidTank getFluidTank(int index); +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/MultiFluidTankHandler.java b/src/main/java/com/gregtechceu/gtceu/utils/MultiFluidTankHandler.java new file mode 100644 index 00000000000..a1239ceb94a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/MultiFluidTankHandler.java @@ -0,0 +1,3 @@ +package com.gregtechceu.gtceu.utils; + +public class MultiFluidTankHandler {} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/math/NumberFormat.java b/src/main/java/com/gregtechceu/gtceu/utils/math/NumberFormat.java new file mode 100644 index 00000000000..61f356dff9b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/math/NumberFormat.java @@ -0,0 +1,332 @@ +package com.gregtechceu.gtceu.utils.math; + +import com.gregtechceu.gtceu.utils.GTMath; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; + +/** + * A number formatter for large, small, positive, negative, integers and decimals with adjustable format parameters. + * Test results can be seen at test/java/com.cleanroommc.modularui.FormatTest. + */ +public class NumberFormat { + + public static final BigDecimal TEN_THOUSAND = new BigDecimal(10_000); + + public static final Params DEFAULT = paramsBuilder() + .roundingMode(RoundingMode.HALF_UP) + .maxLength(4) + .considerMinusForLength(false) + .considerDecimalSeparatorForLength(false) + .considerOnlyDecimalsForLength(false) + .considerSuffixForLength(true) + .spaceAfterNumber(false) + .build(); + + public static final Params DECIMALS_3 = DEFAULT.copyToBuilder() + .considerSuffixForLength(false) + .considerOnlyDecimalsForLength(true) + .maxLength(3) + .build(); + + public static final Params AMOUNT_TEXT = DEFAULT.copyToBuilder() + .roundingMode(RoundingMode.DOWN) + .build(); + + public static Params params(DecimalFormat format, int maxLength, boolean considerOnlyDecimalsForLength, + boolean considerDecimalSeparatorForLength, boolean considerMinusForLength, + boolean considerSuffixForLength, + boolean spaceAfterNumber) { + return new Params(format, maxLength, considerOnlyDecimalsForLength, considerDecimalSeparatorForLength, + considerMinusForLength, considerSuffixForLength, spaceAfterNumber); + } + + public static ParamsBuilder paramsBuilder() { + return new ParamsBuilder(); + } + + public static class Params { + + public final DecimalFormat format; + public final int maxLength; + public final boolean considerOnlyDecimalsForLength; + public final boolean considerDecimalSeparatorForLength; + public final boolean considerMinusForLength; + public final boolean considerSuffixForLength; + public final boolean spaceAfterNumber; + + public Params(DecimalFormat format, int maxLength, boolean considerOnlyDecimalsForLength, + boolean considerDecimalSeparatorForLength, + boolean considerMinusForLength, boolean considerSuffixForLength, boolean spaceAfterNumber) { + this.format = format; + this.maxLength = maxLength; + this.considerOnlyDecimalsForLength = considerOnlyDecimalsForLength; + this.considerDecimalSeparatorForLength = considerDecimalSeparatorForLength; + this.considerMinusForLength = considerMinusForLength; + this.considerSuffixForLength = considerSuffixForLength; + this.spaceAfterNumber = spaceAfterNumber; + if (!this.considerOnlyDecimalsForLength && this.maxLength < 4) { + throw new IllegalArgumentException("Max length must be at least 4 characters"); + } + } + + public ParamsBuilder copyToBuilder() { + DecimalFormat format = (DecimalFormat) this.format.clone(); + format.setMinimumFractionDigits(this.format.getMinimumFractionDigits()); + format.setMaximumFractionDigits(this.format.getMaximumFractionDigits()); + format.setMinimumIntegerDigits(this.format.getMinimumIntegerDigits()); + format.setMaximumIntegerDigits(this.format.getMaximumIntegerDigits()); + format.setRoundingMode(this.format.getRoundingMode()); + format.setGroupingSize(this.format.getGroupingSize()); + format.setGroupingUsed(this.format.isGroupingUsed()); + return new ParamsBuilder() + .format(format) + .maxLength(this.maxLength) + .considerOnlyDecimalsForLength(this.considerOnlyDecimalsForLength) + .considerDecimalSeparatorForLength(this.considerDecimalSeparatorForLength) + .considerMinusForLength(this.considerMinusForLength) + .considerSuffixForLength(this.considerSuffixForLength) + .spaceAfterNumber(this.spaceAfterNumber); + } + + public String format(double number) { + return NumberFormat.format(number, this); + } + + public String format(BigDecimal number) { + return NumberFormat.format(number, this); + } + } + + public static class ParamsBuilder { + + private DecimalFormat format; + private int maxLength; + private boolean considerOnlyDecimalsForLength; + private boolean considerDecimalSeparatorForLength; + private boolean considerMinusForLength; + private boolean considerSuffixForLength; + private boolean spaceAfterNumber; + + private DecimalFormat checkFormat() { + if (this.format == null) { + this.format = new DecimalFormat("0.###"); + } + return this.format; + } + + public ParamsBuilder format(DecimalFormat format) { + this.format = format; + return this; + } + + public ParamsBuilder roundingMode(RoundingMode roundingMode) { + checkFormat().setRoundingMode(roundingMode); + return this; + } + + public ParamsBuilder decimalFormatSymbols(DecimalFormatSymbols symbols) { + checkFormat().setDecimalFormatSymbols(symbols); + return this; + } + + public ParamsBuilder decimalSeparator(char c) { + DecimalFormatSymbols symbols = checkFormat().getDecimalFormatSymbols(); + symbols.setDecimalSeparator(c); + checkFormat().setDecimalFormatSymbols(symbols); + return this; + } + + public ParamsBuilder maxLength(int maxLength) { + this.maxLength = maxLength; + return this; + } + + public ParamsBuilder considerOnlyDecimalsForLength(boolean considerOnlyDecimalsForLength) { + this.considerOnlyDecimalsForLength = considerOnlyDecimalsForLength; + return this; + } + + public ParamsBuilder considerDecimalSeparatorForLength(boolean considerDecimalSeparatorForLength) { + this.considerDecimalSeparatorForLength = considerDecimalSeparatorForLength; + return this; + } + + public ParamsBuilder considerMinusForLength(boolean considerMinusForLength) { + this.considerMinusForLength = considerMinusForLength; + return this; + } + + public ParamsBuilder considerSuffixForLength(boolean considerSuffixForLength) { + this.considerSuffixForLength = considerSuffixForLength; + return this; + } + + public ParamsBuilder spaceAfterNumber(boolean spaceAfterNumber) { + this.spaceAfterNumber = spaceAfterNumber; + return this; + } + + public Params build() { + return new Params(checkFormat(), this.maxLength, this.considerOnlyDecimalsForLength, + this.considerDecimalSeparatorForLength, + this.considerMinusForLength, this.considerSuffixForLength, spaceAfterNumber); + } + } + + public static String format(double number, Params params) { + boolean negative = number < 0; + int maxLength = params.maxLength; + if (negative) { + number = -number; + if (params.considerMinusForLength) maxLength--; + } + String formattedNumber = formatInternal(number, maxLength, params); + if (negative) formattedNumber = "-" + formattedNumber; + return formattedNumber; + } + + public static String format(BigDecimal number, Params params) { + boolean negative = number.compareTo(BigDecimal.ZERO) < 0; + int maxLength = params.maxLength; + if (negative) { + number = number.negate(); + if (params.considerMinusForLength) maxLength--; + } + String formattedNumber = formatInternal(number, maxLength, params); + if (negative) formattedNumber = "-" + formattedNumber; + return formattedNumber; + } + + public static String formatFromUnit(double number, SIPrefix unit, Params params) { + return format(number * unit.factor, params); + } + + public static SIPrefix findBestPrefix(double number) { + if (Double.isNaN(number)) return SIPrefix.One; + if (Double.isInfinite(number)) return SIPrefix.Infinite; + number = Math.abs(number); + if (number == 0 || (number >= 1 && number < 10_000)) return SIPrefix.One; + SIPrefix[] high = SIPrefix.HIGH; + SIPrefix[] low = SIPrefix.LOW; + int n = high.length - 1; + SIPrefix prefix; + if (number >= 10_000) { + int index; + for (index = 0; index < n; index++) { + if (number < high[index + 1].factor) { + break; + } + } + prefix = high[index]; + } else { + int index; + for (index = 0; index < n; index++) { + if (number >= low[index].factor) { + break; + } + } + prefix = low[index]; + } + return prefix; + } + + public static SIPrefix findBestPrefix(BigDecimal number) { + number = number.abs(); + if ((number.compareTo(BigDecimal.ONE) >= 0 && number.compareTo(TEN_THOUSAND) < 0) || + number.equals(BigDecimal.ZERO)) { + return SIPrefix.One; + } + SIPrefix[] high = SIPrefix.HIGH; + SIPrefix[] low = SIPrefix.LOW; + int n = high.length - 1; + SIPrefix prefix; + if (number.compareTo(TEN_THOUSAND) >= 0) { + int index; + for (index = 0; index < n; index++) { + if (number.compareTo(high[index + 1].bigFactor) < 0) { + break; + } + } + prefix = high[index]; + } else { + int index; + for (index = 0; index < n; index++) { + if (number.compareTo(low[index].bigFactor) >= 0) { + break; + } + } + prefix = low[index]; + } + return prefix; + } + + private static String formatInternal(double number, int maxLength, Params params) { + if (Double.isNaN(number)) return "NaN"; + SIPrefix prefix = findBestPrefix(number); + if (prefix.infiniteLike) return prefix.stringSymbol; + return formatToString(number * prefix.oneOverFactor, prefix.symbol, maxLength, params); + } + + private static String formatToString(double value, char prefix, int maxLength, Params params) { + if (params.considerSuffixForLength && prefix != Character.MIN_VALUE) { + maxLength--; + if (params.spaceAfterNumber) maxLength--; + } + if (params.considerDecimalSeparatorForLength) maxLength--; + if (!params.considerOnlyDecimalsForLength) { + if (value % 1 > 0) { + maxLength -= GTMath.intPlaces(value); + } + } + int m1 = params.format.getMaximumFractionDigits(); + int m2 = params.format.getMinimumFractionDigits(); + params.format.setMaximumFractionDigits(maxLength); + String s = params.format.format(value); + params.format.setMaximumFractionDigits(m1); + params.format.setMinimumFractionDigits(m2); + + if (prefix != Character.MIN_VALUE) { + if (params.spaceAfterNumber) s += ' '; + s += prefix; + } + return s; + } + + private static String formatInternal(BigDecimal number, int maxLength, Params params) { + SIPrefix prefix = findBestPrefix(number); + if (prefix.infiniteLike) return prefix.stringSymbol; + return formatToString(number.multiply(prefix.bigOneOverFactor), prefix.symbol, maxLength, params); + } + + private static String formatToString(BigDecimal value, char prefix, int maxLength, Params params) { + if (params.considerSuffixForLength && prefix != Character.MIN_VALUE) { + maxLength--; + if (params.spaceAfterNumber) maxLength--; + } + if (params.considerDecimalSeparatorForLength) maxLength--; + if (!params.considerOnlyDecimalsForLength) { + if (value.remainder(BigDecimal.ONE).signum() > 0) { + maxLength -= GTMath.intPlaces(value); + } + } + int m1 = params.format.getMaximumFractionDigits(); + int m2 = params.format.getMinimumFractionDigits(); + params.format.setMaximumFractionDigits(maxLength); + String s = params.format.format(value); + params.format.setMaximumFractionDigits(m1); + params.format.setMinimumFractionDigits(m2); + + if (prefix != Character.MIN_VALUE) { + if (params.spaceAfterNumber) s += ' '; + s += prefix; + } + return s; + } + + public static String formatNanos(long nanos) { + return DECIMALS_3.format(nanos * SIPrefix.Nano.factor); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/math/ParseResult.java b/src/main/java/com/gregtechceu/gtceu/utils/math/ParseResult.java index 5ddc9c82749..0ea2581c4d0 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/math/ParseResult.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/math/ParseResult.java @@ -1,28 +1,30 @@ package com.gregtechceu.gtceu.utils.math; +import com.ezylang.evalex.BaseException; +import com.ezylang.evalex.data.EvaluationValue; import lombok.Getter; import org.jetbrains.annotations.NotNull; public class ParseResult { @Getter - private final double result; + private final EvaluationValue result; @Getter - private final String error; + private final BaseException error; - public static ParseResult success(double result) { + public static ParseResult success(EvaluationValue result) { return new ParseResult(result, null); } - public static ParseResult failure(@NotNull String error) { - return failure(Double.NaN, error); + public static ParseResult failure(@NotNull BaseException error) { + return failure(null, error); } - public static ParseResult failure(double value, @NotNull String error) { + public static ParseResult failure(EvaluationValue value, @NotNull BaseException error) { return new ParseResult(value, error); } - private ParseResult(double result, String error) { + private ParseResult(EvaluationValue result, BaseException error) { this.result = result; this.error = error; } @@ -36,6 +38,14 @@ public boolean isFailure() { } public boolean hasValue() { - return !Double.isNaN(this.result); + return this.result != null; + } + + public String getErrorMessage() { + return isFailure() ? + String.format("%s for Token %s at %d:%d", + this.error.getMessage(), this.error.getTokenString(), + this.error.getStartPosition(), this.error.getEndPosition()) : + null; } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/math/PostfixPercentOperator.java b/src/main/java/com/gregtechceu/gtceu/utils/math/PostfixPercentOperator.java new file mode 100644 index 00000000000..14da7a72b33 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/math/PostfixPercentOperator.java @@ -0,0 +1,30 @@ +package com.gregtechceu.gtceu.utils.math; + +import com.ezylang.evalex.EvaluationException; +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.data.EvaluationValue; +import com.ezylang.evalex.operators.AbstractOperator; +import com.ezylang.evalex.operators.OperatorIfc; +import com.ezylang.evalex.operators.PostfixOperator; +import com.ezylang.evalex.parser.Token; + +import java.math.BigDecimal; + +@PostfixOperator(precedence = OperatorIfc.OPERATOR_PRECEDENCE_MULTIPLICATIVE - 1) +public class PostfixPercentOperator extends AbstractOperator { + + public static final BigDecimal HUNDRED = new BigDecimal(100); + + @Override + public EvaluationValue evaluate(Expression expression, Token operatorToken, + EvaluationValue... operands) throws EvaluationException { + EvaluationValue operand = operands[0]; + + if (operand.isNumberValue()) { + return expression.convertValue( + operand.getNumberValue().divide(HUNDRED, expression.getConfiguration().getMathContext())); + } else { + throw EvaluationException.ofUnsupportedDataTypeInOperation(operatorToken); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/math/SIPrefix.java b/src/main/java/com/gregtechceu/gtceu/utils/math/SIPrefix.java index 809d3daf179..6e630a51e54 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/math/SIPrefix.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/math/SIPrefix.java @@ -1,18 +1,23 @@ package com.gregtechceu.gtceu.utils.math; +import com.ezylang.evalex.Expression; + +import java.math.BigDecimal; + public enum SIPrefix { + Infinite('∞', Double.MAX_VALUE, true), Quetta('Q', 30), Ronna('R', 27), Yotta('Y', 24), Zetta('Z', 21), - Exa('E', 18), + Exa('X', 18), // this should actually be E, but this clashes with euler's number e = 2.71... Peta('P', 15), Tera('T', 12), Giga('G', 9), Mega('M', 6), Kilo('k', 3), - One(Character.MIN_VALUE, 0), + One(), Milli('m', -3), Micro('µ', -6), Nano('n', -9), @@ -22,24 +27,50 @@ public enum SIPrefix { Zepto('z', -21), Yocto('y', -24), Ronto('r', -27), - Quecto('q', -30); + Quecto('q', -30), + Infinitesimal('∞', Double.MIN_NORMAL, true); public final char symbol; public final String stringSymbol; public final double factor; public final double oneOverFactor; + public final BigDecimal bigFactor; + public final BigDecimal bigOneOverFactor; + public final boolean infiniteLike; - SIPrefix(char symbol, int powerOfTen) { + SIPrefix() { + this.symbol = Character.MIN_VALUE; + this.stringSymbol = ""; + this.factor = 1.0; + this.oneOverFactor = 1.0; + this.bigFactor = BigDecimal.ONE; + this.bigOneOverFactor = BigDecimal.ONE; + this.infiniteLike = false; + } + + SIPrefix(char symbol, double f, boolean inf) { this.symbol = symbol; - this.stringSymbol = symbol != Character.MIN_VALUE ? Character.toString(symbol) : ""; - this.factor = Math.pow(10, powerOfTen); - this.oneOverFactor = 1 / this.factor; + this.stringSymbol = Character.toString(symbol); + this.factor = f; + this.oneOverFactor = 1 / f; + this.bigFactor = new BigDecimal(f); + this.bigOneOverFactor = new BigDecimal(this.oneOverFactor); + this.infiniteLike = inf; + } + + SIPrefix(char symbol, int powerOfTen) { + this(symbol, Math.pow(10, powerOfTen), false); } public boolean isOne() { return this == One; } + public void addToExpression(Expression e) { + e.with(String.valueOf(this.symbol), this.factor); + } + + public static final SIPrefix[] VALUES = values(); public static final SIPrefix[] HIGH = new SIPrefix[values().length / 2]; public static final SIPrefix[] LOW = new SIPrefix[values().length / 2]; @@ -50,4 +81,10 @@ public boolean isOne() { LOW[i] = values[HIGH.length + 1 + i]; } } + + public static void addAllToExpression(Expression e) { + for (SIPrefix siPrefix : VALUES) { + siPrefix.addToExpression(e); + } + } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/memoization/GTMemoizer.java b/src/main/java/com/gregtechceu/gtceu/utils/memoization/GTMemoizer.java index 36728327d77..5dc365689c3 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/memoization/GTMemoizer.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/memoization/GTMemoizer.java @@ -6,11 +6,13 @@ import net.minecraft.world.level.block.Block; +import com.google.common.base.Suppliers; import lombok.Getter; import org.apache.commons.lang3.function.TriFunction; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; +import java.time.Duration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; @@ -30,6 +32,40 @@ public static MemoizedSupplier memoize(Supplier delegate) { return new MemoizedSupplier<>(delegate); } + /** + * Store a supplier in a delegate function to be computed once, and only again after time to live has expired. + *

+ * If you need thread safety, you should use + * {@link Suppliers#memoize(com.google.common.base.Supplier) Suppliers#memoize} instead. + *

+ * + * @param The type of object supplied + * @param delegate The supplier to memoize + * @param timeToLive Time to retain calculation. If negative, retain indefinitely. + * @see #memoize(Supplier) + * @see Suppliers#memoize(com.google.common.base.Supplier) + */ + public static MemoizedSupplier memoize(Supplier delegate, Duration timeToLive) { + return memoize(delegate, timeToLive.toNanos()); + } + + /** + * Store a supplier in a delegate function to be computed once, and only again after time to live has expired. + *

+ * If you need thread safety, you should use + * {@link Suppliers#memoize(com.google.common.base.Supplier) Suppliers#memoize} instead. + *

+ * + * @param The type of object supplied + * @param delegate The supplier to memoize + * @param timeToLive Time in nanoseconds to retain calculation. If negative, retain indefinitely. + * @see #memoize(Supplier) + * @see Suppliers#memoize(com.google.common.base.Supplier) + */ + public static MemoizedSupplier memoize(Supplier delegate, long timeToLive) { + return new MemoizedSupplier<>(delegate, timeToLive); + } + public static MemoizedBlockSupplier memoizeBlockSupplier(Supplier delegate) { return new MemoizedBlockSupplier<>(delegate); } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/memoization/MemoizedSupplier.java b/src/main/java/com/gregtechceu/gtceu/utils/memoization/MemoizedSupplier.java index 065d68ed01b..d4d35e143fe 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/memoization/MemoizedSupplier.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/memoization/MemoizedSupplier.java @@ -8,12 +8,28 @@ public class MemoizedSupplier implements Supplier { protected boolean initialized = false; protected final Supplier delegate; + protected long timeToLiveNanos = -1; + private volatile long lastAccessNanos; + protected MemoizedSupplier(Supplier delegate) { this.delegate = delegate; } + protected MemoizedSupplier(Supplier delegate, long timeToLiveNanos) { + this.delegate = delegate; + this.timeToLiveNanos = timeToLiveNanos; + } + @Override public T get() { + if (timeToLiveNanos != -1) { + long now = System.nanoTime(); + if (lastAccessNanos == 0 || (timeToLiveNanos >= 0 && now - lastAccessNanos >= timeToLiveNanos)) { + value = delegate.get(); + } + lastAccessNanos = now; + return value; + } if (!initialized) { value = delegate.get(); initialized = true; @@ -22,12 +38,14 @@ public T get() { } public void invalidate() { + lastAccessNanos = 0; initialized = false; value = null; } @Override public String toString() { - return getClass().getSimpleName() + "(" + (initialized ? value : "Uninitialized") + ")"; + return getClass().getSimpleName() + "(" + ((initialized || lastAccessNanos != 0) ? value : "Uninitialized") + + ")"; } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java b/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java index 84f566e7a10..ff8e0deba16 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/serialization/network/ByteBufAdapters.java @@ -28,6 +28,15 @@ public class ByteBufAdapters { public static final IByteBufAdapter STRING = makeAdapter(NetworkUtils::readStringSafe, NetworkUtils::writeStringSafe, null); public static final IByteBufAdapter BYTE_BUF = makeAdapter(NetworkUtils::readByteBuf, NetworkUtils::writeByteBuf, null); public static final IByteBufAdapter FRIENDLY_BYTE_BUF = makeAdapter(NetworkUtils::readFriendlyByteBuf, NetworkUtils::writeByteBuf, null); + + public static final IByteBufAdapter INT = makeAdapter(FriendlyByteBuf::readInt, FriendlyByteBuf::writeInt, null); + public static final IByteBufAdapter LONG = makeAdapter(FriendlyByteBuf::readLong, FriendlyByteBuf::writeLong, null); + public static final IByteBufAdapter FLOAT = makeAdapter(FriendlyByteBuf::readFloat, FriendlyByteBuf::writeFloat, null); + public static final IByteBufAdapter DOUBLE = makeAdapter(FriendlyByteBuf::readDouble, FriendlyByteBuf::writeDouble, null); + public static final IByteBufAdapter BOOL = makeAdapter(FriendlyByteBuf::readBoolean, FriendlyByteBuf::writeBoolean, null); + public static final IByteBufAdapter BYTE = makeAdapter(FriendlyByteBuf::readByte, (buffer, b) -> buffer.writeByte(b), null); + public static final IByteBufAdapter SHORT = makeAdapter(FriendlyByteBuf::readShort, (buffer, b) -> buffer.writeShort(b), null); + public static final IByteBufAdapter CHAR = makeAdapter(FriendlyByteBuf::readChar, (buffer, b) -> buffer.writeChar(b), null); // spotless:on public static final IByteBufAdapter BYTE_ARR = new IByteBufAdapter<>() { From cd9762c85b371e80078d7d246b136422bd05a341 Mon Sep 17 00:00:00 2001 From: YoungOnion <39562198+YoungOnionMC@users.noreply.github.com> Date: Wed, 18 Feb 2026 01:09:39 -0700 Subject: [PATCH 2/3] remove progress double supplier --- .../api/machine/steam/SteamBoilerMachine.java | 6 +++++- .../gtceu/api/mui/widgets/ProgressWidget.java | 6 ------ .../api/recipe/gui/GTRecipeTypeUILayout.java | 6 +++++- .../api/recipe/gui/GTRecipeViewerUILayout.java | 2 +- .../gtceu/common/data/mui/GTMuiWidgets.java | 11 +++++++++-- .../machine/electric/BatteryBufferMachine.java | 7 ++++++- .../common/machine/electric/ChargerMachine.java | 7 ++++++- .../common/machine/electric/FisherMachine.java | 6 +++++- .../common/machine/muimachine/TestMuiMachine.java | 7 +++++-- .../multiblock/primitive/CokeOvenMachine.java | 15 +++++++++++++-- .../primitive/PrimitiveBlastFurnaceMachine.java | 12 +++++++++++- .../machine/steam/SteamLiquidBoilerMachine.java | 12 ++++++++++-- .../common/machine/steam/SteamSolarBoiler.java | 9 ++++++++- .../machine/steam/SteamSolidBoilerMachine.java | 9 ++++++++- 14 files changed, 92 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamBoilerMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamBoilerMachine.java index 8a61aa5971c..59b82c87134 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamBoilerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamBoilerMachine.java @@ -11,6 +11,7 @@ import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.FluidSlotSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; @@ -327,6 +328,9 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet UITexture progressTexture = isHighPressure() ? GTGuiTextures.PROGRESS_BAR_BOILER_EMPTY_STEEL : GTGuiTextures.PROGRESS_BAR_BOILER_EMPTY_BRONZE; + DoubleSyncValue tempPercentage = syncManager.getOrCreateSyncHandler("tempPercentage", DoubleSyncValue.class, + () -> new DoubleSyncValue(this::getTemperaturePercent)); + panel.child(new Row() .top(12) .left(50) @@ -347,7 +351,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .texture(progressTexture, GTGuiTextures.PROGRESS_BAR_BOILER_HEAT, 54) .size(14, 54) - .progress(this::getTemperaturePercent) + .value(tempPercentage) .direction(ProgressWidget.Direction.UP) .tooltipAutoUpdate(true) .tooltipBuilder((r) -> r.addLine(IKey diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java index 6691725b19c..263ff61241a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/ProgressWidget.java @@ -18,8 +18,6 @@ import lombok.experimental.Accessors; import org.jetbrains.annotations.NotNull; -import java.util.function.DoubleSupplier; - @Accessors(fluent = true, chain = true) public class ProgressWidget extends Widget { @@ -176,10 +174,6 @@ public ProgressWidget value(IDoubleValue value) { return this; } - public ProgressWidget progress(DoubleSupplier progress) { - return value(new DoubleValue.Dynamic(progress, null)); - } - public ProgressWidget progress(double progress) { return value(new DoubleValue(progress)); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeTypeUILayout.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeTypeUILayout.java index 6bba0334d08..0d5350cf699 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeTypeUILayout.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeTypeUILayout.java @@ -7,6 +7,7 @@ import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.theme.ThemeAPI; import com.gregtechceu.gtceu.api.mui.utils.Alignment; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandlers; import com.gregtechceu.gtceu.api.mui.widget.ParentWidget; @@ -187,9 +188,12 @@ public ParentWidget getBackedSlotsRow(@NotNull PanelSyncManager syncManager, backedSlotsPanel.child(backedSlotsRow.left(slotLeftShiftPx)); + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", + DoubleSyncValue.class, () -> new DoubleSyncValue(progressSupplier)); + backedSlotsPanel.child(new ProgressWidget() .center() - .progress(progressSupplier) + .value(progressPercent) .name("progressBar") .texture(progressBar, progressSize) .size(progressSize) diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeViewerUILayout.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeViewerUILayout.java index a2abd798384..1b38f11ed9b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeViewerUILayout.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/gui/GTRecipeViewerUILayout.java @@ -110,7 +110,7 @@ public ParentWidget getRecipeWidget() { parentWidget.child(new ProgressWidget() .center() - .progress(() -> 0.5f) + // .progress(() -> 0.5f) .name("progressBar") .texture(layout.getProgressBar(), layout.getProgressSize()) .size(layout.getProgressSize()) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java b/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java index 0f23490f46d..81227db0bc0 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/mui/GTMuiWidgets.java @@ -128,10 +128,17 @@ public static ToggleButton createPowerButton(IRecipeLogicMachine recipeLogicMach syncManager); } - public static ProgressWidget createProgressBar(IRecipeLogicMachine workableMachine, UITexture texture, int size) { + public static ProgressWidget createProgressBar(IRecipeLogicMachine workableMachine, PanelSyncManager syncManager, + UITexture texture, int size) { + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", DoubleSyncValue.class, + () -> new DoubleSyncValue(() -> { + if (workableMachine.getMaxProgress() == 0.0f) return 0.0f; + return workableMachine.getProgress() / (double) workableMachine.getMaxProgress(); + })); + return new ProgressWidget() .texture(texture, size) - .progress(() -> workableMachine.getProgress() / (double) workableMachine.getMaxProgress()); + .value(progressPercent); } public static FluidSlot createTankWidget() { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java index 68fb4a8d4b6..146d63eb81c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BatteryBufferMachine.java @@ -13,6 +13,7 @@ import com.gregtechceu.gtceu.api.machine.trait.NotifiableEnergyContainer; import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; import com.gregtechceu.gtceu.api.mui.widgets.layout.Column; @@ -105,6 +106,10 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet String[] matrix; if (inventorySize == 8) matrix = new String[] { "BBBB", "BBBB" }; else matrix = GTMuiMachineUtil.createSquareMatrix(inventorySize, 'B'); + + DoubleSyncValue energyPercentage = syncManager.getOrCreateSyncHandler("energyPercentage", DoubleSyncValue.class, + () -> new DoubleSyncValue(this::getEnergyPercentage)); + return new ModularPanel("battery_buffer") .child(GTMuiWidgets.createTitleBar(getDefinition(), 172)) .child(Flow.row() @@ -117,7 +122,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .texture(GTGuiTextures.PROGRESS_BAR_BOILER_EMPTY_STEEL, GTGuiTextures.PROGRESS_BAR_BOILER_HEAT, 60) .direction(ProgressWidget.Direction.UP) - .progress(this::getEnergyPercentage) + .value(energyPercentage) .marginRight(50) .size(18, 60) .verticalCenter() diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java index 48a2c2c5f0b..22adb67719f 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ChargerMachine.java @@ -10,6 +10,7 @@ import com.gregtechceu.gtceu.api.machine.trait.NotifiableEnergyContainer; import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; import com.gregtechceu.gtceu.api.mui.widgets.layout.Column; @@ -128,6 +129,10 @@ public void onMachineDestroyed() { @Override public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) { String[] matrix = GTMuiMachineUtil.createSquareMatrix(inventorySize, 'B'); + + DoubleSyncValue energyPercentage = syncManager.getOrCreateSyncHandler("energyPercentage", DoubleSyncValue.class, + () -> new DoubleSyncValue(this::getEnergyPercentage)); + return new ModularPanel(getDefinition().getName()) .child(GTMuiWidgets.createTitleBar(getDefinition(), 172)) .child(Flow.row() @@ -140,7 +145,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .texture(GTGuiTextures.PROGRESS_BAR_BOILER_EMPTY_STEEL, GTGuiTextures.PROGRESS_BAR_BOILER_HEAT, 60) .direction(ProgressWidget.Direction.UP) - .progress(this::getEnergyPercentage) + .value(energyPercentage) .marginRight(50) .size(18, 60) .verticalCenter() diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java index 87618d7c9bf..94414d99ea3 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java @@ -16,6 +16,7 @@ import com.gregtechceu.gtceu.api.mui.utils.Alignment; import com.gregtechceu.gtceu.api.mui.value.BoolValue; import com.gregtechceu.gtceu.api.mui.value.sync.BooleanSyncValue; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.ItemSlotSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; @@ -352,6 +353,9 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet panel.size(176, 124 + Math.max(36, 18 * slotHeight)); + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", DoubleSyncValue.class, + () -> new DoubleSyncValue(() -> progress / (double) maxProgress)); + panel.child(GTMuiWidgets.createTitleBar(getDefinition(), 176, GTGuiTextures.BACKGROUND)) .child(new Row() .coverChildrenHeight() @@ -367,7 +371,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .child(new ProgressWidget() .alignY(Alignment.Center) .texture(GTGuiTextures.PROGRESS_BAR_ARROW, 16) - .progress(() -> progress / (double) maxProgress)) + .value(progressPercent)) .child(new Column() .coverChildrenWidth() .mainAxisAlignment(Alignment.MainAxis.CENTER) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java index 3b577256bc3..11bebc88145 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/muimachine/TestMuiMachine.java @@ -182,6 +182,9 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .size(176, 220) // set a static size for the main panel .align(Alignment.Center); // center the panel in the screen + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", DoubleSyncValue.class, () -> + new DoubleSyncValue(() -> (this.progress / (double) this.duration))); + var babyFop = new Fox(EntityType.FOX, data.getLevel()); babyFop.setAge(-1); panel.child(new Row() @@ -323,10 +326,10 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet // .widthRel(0.5f) .crossAxisAlignment(Alignment.CrossAxis.CENTER) .child(new ProgressWidget() - .progress(() -> (this.progress / (double) this.duration)) + .value(progressPercent) .texture(GTGuiTextures.PROGRESS_BAR_ARROW, 20)) .child(new ProgressWidget() - .progress(() -> (this.progress / (double) this.duration)) + .value(progressPercent) .texture(GTGuiTextures.PROGRESS_BAR_MIXER, 20) .direction( ProgressWidget.Direction.CIRCULAR_CW)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java index 6f440ae01e2..80827654aea 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CokeOvenMachine.java @@ -7,6 +7,7 @@ import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; import com.gregtechceu.gtceu.api.mui.theme.ThemeAPI; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.FluidSlotSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.ItemSlotSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; @@ -48,6 +49,13 @@ public CokeOvenMachine(BlockEntityCreationInfo info) { public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) { ITheme uiTheme = ThemeAPI.INSTANCE.getTheme(getDefinition().getThemeId()); + + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", DoubleSyncValue.class, + () -> new DoubleSyncValue(() -> { + if (recipeLogic == null) return -1f; + return recipeLogic.getProgressPercent(); + })); + return new ModularPanel(this.getDefinition().getName()) .size(176, 166) // Top half of the screen @@ -65,8 +73,11 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .background(uiTheme.getItemSlotTheme().getTheme().getBackground(), GTGuiTextures.PRIMITIVE_FURNACE_OVERLAY) .margin(103, 0, 30, 0)) - .child(new ProgressWidget().progress(recipeLogic::getProgressPercent).size(20, 15) - .texture(GTGuiTextures.PRIMITIVE_BLAST_FURNACE_PROGRESS_BAR, 18).margin(76, 32)) + .child(new ProgressWidget() + .value(progressPercent) + .size(20, 15) + .texture(GTGuiTextures.PRIMITIVE_BLAST_FURNACE_PROGRESS_BAR, 18) + .margin(76, 32)) .child(createTankWidget() .overlay(GTGuiTextures.PRIMITIVE_LARGE_FLUID_TANK_OVERLAY) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveBlastFurnaceMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveBlastFurnaceMachine.java index 3fc6e49fb1a..99df2796fb5 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveBlastFurnaceMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveBlastFurnaceMachine.java @@ -13,6 +13,7 @@ import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; import com.gregtechceu.gtceu.api.mui.theme.ThemeAPI; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.ItemSlotSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; @@ -155,11 +156,20 @@ public void clientTick() { @Override public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) { ITheme theme = ThemeAPI.INSTANCE.getTheme(getDefinition().getThemeId()); + + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", DoubleSyncValue.class, + () -> new DoubleSyncValue(() -> { + if (recipeLogic == null) return -1f; + return recipeLogic.getProgressPercent(); + })); + return new ModularPanel(this.getDefinition().getName()) .size(176, 166) // Top half of the screen .child(createImportItemSlot(syncManager, theme).margin(52, 16)) - .child(new ProgressWidget().progress(recipeLogic::getProgressPercent).size(20, 15) + .child(new ProgressWidget() + .value(progressPercent) + .size(20, 15) .texture(GTGuiTextures.PRIMITIVE_BLAST_FURNACE_PROGRESS_BAR, 0).margin(77, 35)) .child(createExportItemSlot(syncManager, theme).margin(104, 0, 34, 0)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamLiquidBoilerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamLiquidBoilerMachine.java index c5bc9062763..e954c354858 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamLiquidBoilerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamLiquidBoilerMachine.java @@ -8,6 +8,7 @@ import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; import com.gregtechceu.gtceu.api.mui.utils.Alignment; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.FluidSlotSyncHandler; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; @@ -85,6 +86,12 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet UITexture progressTexture = isHighPressure() ? GTGuiTextures.PROGRESS_BAR_BOILER_FUEL_STEEL : GTGuiTextures.PROGRESS_BAR_BOILER_FUEL_BRONZE; + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", DoubleSyncValue.class, + () -> new DoubleSyncValue(() -> { + if (recipeLogic == null) return -1f; + return recipeLogic.getProgressPercent(); + })); + return super.buildUI(data, syncManager, settings) .child(new Row() .coverChildren() @@ -94,8 +101,9 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .child(new ProgressWidget() .size(18) .texture(progressTexture, 18) - .progress(recipeLogic::getProgressPercent) - .direction(ProgressWidget.Direction.UP)) + .value(progressPercent) + .direction(ProgressWidget.Direction.UP) + .setEnabledIf((w) -> progressPercent.getFloatValue() > -1f)) .child(new FluidSlot() .syncHandler(new FluidSlotSyncHandler(fuelTank.getStorages()[0]) .canFillSlot(true).canDrainSlot(true)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolarBoiler.java b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolarBoiler.java index ab449a69408..b864e352861 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolarBoiler.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolarBoiler.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic; import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; @@ -74,12 +75,18 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet UITexture progressTexture = isHighPressure() ? GTGuiTextures.PROGRESS_BAR_SOLAR_STEEL : GTGuiTextures.PROGRESS_BAR_SOLAR_BRONZE; + DoubleSyncValue canSeeSun = syncManager.getOrCreateSyncHandler("canSeeSun", DoubleSyncValue.class, + () -> new DoubleSyncValue(() -> { + if (GTUtil.canSeeSunClearly(getLevel(), getBlockPos())) return 1.0f; + return 0.0f; + })); + return super.buildUI(data, syncManager, settings) .child(new ProgressWidget() .top(30).right(18) .size(18) .texture(progressTexture, 20) - .progress(() -> GTUtil.canSeeSunClearly(getLevel(), getBlockPos()) ? 1.0 : 0.0)); + .value(canSeeSun)); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java index 5ced7cdc051..3cf0ea7a254 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java @@ -10,6 +10,7 @@ import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; import com.gregtechceu.gtceu.api.mui.drawable.UITexture; import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; +import com.gregtechceu.gtceu.api.mui.value.sync.DoubleSyncValue; import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.mui.widgets.ProgressWidget; import com.gregtechceu.gtceu.api.mui.widgets.layout.Column; @@ -127,6 +128,12 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet UITexture progressTexture = isHighPressure() ? GTGuiTextures.PROGRESS_BAR_BOILER_FUEL_STEEL : GTGuiTextures.PROGRESS_BAR_BOILER_FUEL_BRONZE; + DoubleSyncValue progressPercent = syncManager.getOrCreateSyncHandler("progressPercent", DoubleSyncValue.class, + () -> new DoubleSyncValue(() -> { + if (recipeLogic == null) return -1f; + return recipeLogic.getProgressPercent(); + })); + return super.buildUI(data, syncManager, settings) .child(new Column() .coverChildren() @@ -138,7 +145,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .child(new ProgressWidget() .size(18) .texture(progressTexture, 18) - .progress(recipeLogic::getProgressPercent) + .value(progressPercent) .direction(ProgressWidget.Direction.UP)) .child(new ItemSlot() .slot(new ModularSlot(this.ashHandler, 0)))); From 8acfa17f0d278b9285bf53ce4ecada65041e8634 Mon Sep 17 00:00:00 2001 From: YoungOnion <39562198+YoungOnionMC@users.noreply.github.com> Date: Wed, 18 Feb 2026 01:29:27 -0700 Subject: [PATCH 3/3] fix rename --- .../machine/multiblock/electric/ActiveTransformerMachine.java | 2 +- .../common/machine/multiblock/electric/CleanroomMachine.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index 1e7afbf4e2c..7df6a1a443c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -202,7 +202,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) .child(GTMuiWidgets.createPowerButton(this, syncManager)) .child(GTMuiWidgets.createVoidingButton(this, syncManager)) - .excludeAreaInXei()) + .excludeAreaInRecipeViewer()) .child(SlotGroupWidget.playerInventory(false).left(7).bottom(7)); return panel; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index e86cb289428..335160bc45b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -498,7 +498,7 @@ public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISet .background(GTGuiTextures.BACKGROUND.getSubArea(0.25f, 0f, 1.0f, 1.0f)) .child(GTMuiWidgets.createPowerButton(this, syncManager)) .child(GTMuiWidgets.createVoidingButton(this, syncManager)) - .excludeAreaInXei()) + .excludeAreaInRecipeViewer()) .child(SlotGroupWidget.playerInventory(false).left(7).bottom(7)); return panel; }